Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

이진 탐색트리 구현 완료 #40

Merged
merged 7 commits into from
Aug 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ public interface BinarySearchTreeNode<E> {
* @param data BST에 저장할 데이터
*/
void insert(E data);

/**
* 해당 데이터를 BST에서 제거하고 해당 데이터를 저장한 노드를 반환합니다.
*
* @param target 제거할 데이터
* @return 제거된 데이터를 저장한 노드
*/
BinaryTreeNode<E> remove(E target);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

public class LinkedBinarySearchTreeNode<E> implements BinarySearchTreeNode<E> {

private final BinaryTreeNode<E> node;
private final Comparator<E> comparator;
private BinaryTreeNode<E> node;

public LinkedBinarySearchTreeNode(E data, Comparator<E> comparator) {
this.node = new LinkedBinaryTreeNode<>(data);
Expand Down Expand Up @@ -62,4 +62,87 @@ public void insert(E data) {
parentNode.setRightSubTree(newNode);
}
}

@Override
public BinaryTreeNode<E> remove(E target) {
BinaryTreeNode<E> rootDummyNode = new LinkedBinaryTreeNode<>(null);
BinaryTreeNode<E> parentNode = rootDummyNode;
BinaryTreeNode<E> currentNode = this.node;
BinaryTreeNode<E> deleteNode;

rootDummyNode.changeRightSubTree(this.node);

while (currentNode != null && currentNode.getData() != target) {
parentNode = currentNode;
if (comparator.compare(target, currentNode.getData()) < 0) {
currentNode = currentNode.getLeftSubTree();
} else {
currentNode = currentNode.getRightSubTree();
}
}

if (currentNode == null) { // 삭제 대상이 조회되지 않은 경우
return null;
}

deleteNode = currentNode;

if (deleteNode.getLeftSubTree() == null && deleteNode.getRightSubTree() == null) {
// 삭제 대상이 단말 노드인 경우
if (parentNode.getLeftSubTree() == deleteNode) {
parentNode.removeLeftSubTree();
} else {
parentNode.removeRightSubTree();
}
} else if (deleteNode.getLeftSubTree() == null || deleteNode.getRightSubTree() == null) {
// 삭제 대상이 하나의 자식 노드를 갖는 경우
BinaryTreeNode<E> childNode;

if (deleteNode.getLeftSubTree() != null) {
childNode = deleteNode.getLeftSubTree();
} else {
childNode = deleteNode.getRightSubTree();
}

if (parentNode.getLeftSubTree() == deleteNode) {
parentNode.changeLeftSubTree(childNode);
} else {
parentNode.changeRightSubTree(childNode);
}
} else {
// 둘 다 있는 경우
BinaryTreeNode<E> moveNode = deleteNode.getRightSubTree();
BinaryTreeNode<E> moveParentNode = deleteNode;

// 삭제 대상의 대체 노드 찾기
while (moveNode.getLeftSubTree() != null) {
moveParentNode = moveNode;
moveNode = moveNode.getLeftSubTree();
}

// 대체 노드의 부모 노드와 자식 노드 연결
if (moveParentNode.getLeftSubTree() == moveNode) {
moveParentNode.changeLeftSubTree(moveNode.getRightSubTree());
} else {
moveParentNode.changeRightSubTree(moveNode.getRightSubTree());
}

// 삭제 노드의 하위 노드를 대체 노드에 연결
moveNode.changeLeftSubTree(deleteNode.getLeftSubTree());
moveNode.changeRightSubTree(deleteNode.getRightSubTree());

// 부모 노드의 하위 노드 변경
if (parentNode.getLeftSubTree() != deleteNode) {
parentNode.changeRightSubTree(moveNode);
} else {
parentNode.changeLeftSubTree(moveNode);
}
}

if (rootDummyNode.getRightSubTree() != this.node) {
this.node = rootDummyNode.getRightSubTree();
}

return deleteNode;
}
}
28 changes: 28 additions & 0 deletions yoonexample/src/main/java/tree/binarytree/BinaryTreeNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,32 @@ public interface BinaryTreeNode<E> {
* @param subTree 대상이 될 노드
*/
void setRightSubTree(BinaryTreeNode<E> subTree);

/**
* 왼쪽 서브트리를 제거하고 반환합니다.
*
* @return 왼쪽 서브트리
*/
BinaryTreeNode<E> removeLeftSubTree();

/**
* 오른쪽 서브트리를 제거하고 반환합니다.
*
* @return 오른쪽 서브트리
*/
BinaryTreeNode<E> removeRightSubTree();

/**
* 왼쪽 서브트리를 입력된 서브트리로 대체합니다.
*
* @param subTree 왼쪽 서브트리를 대체할 서브트리
*/
void changeLeftSubTree(BinaryTreeNode<E> subTree);

/**
* 오른쪽 서브트리를 입력된 서브트리로 대체합니다.
*
* @param subTree 오른쪽 서브트리를 대체할 서브트리
*/
void changeRightSubTree(BinaryTreeNode<E> subTree);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,28 @@ public BinaryTreeNode<E> getRightSubTree() {
public void setRightSubTree(BinaryTreeNode<E> subTree) {
this.right = subTree;
}

@Override
public BinaryTreeNode<E> removeLeftSubTree() {
BinaryTreeNode<E> deleteNode = this.getLeftSubTree();
this.left = null;
return deleteNode;
}

@Override
public BinaryTreeNode<E> removeRightSubTree() {
BinaryTreeNode<E> deleteNode = this.getRightSubTree();
this.right = null;
return deleteNode;
}

@Override
public void changeLeftSubTree(BinaryTreeNode<E> subTree) {
this.left = subTree;
}

@Override
public void changeRightSubTree(BinaryTreeNode<E> subTree) {
this.right = subTree;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,71 @@ class BinarySearchTreeNodeTest {
searchNode = bstRoot.search(7);
assertThat(searchNode).isNull();
}

@Test
@DisplayName("이진_탐색_트리_제거_테스트")
void 이진_탐색_트리_제거_테스트() {
int RootNodeData = 5;
int terminalNodeData = 2;
int singleSubTreeNodeData = 6;
int doubleSubTreeNodeData = 8;

BinarySearchTreeNode<Integer> bstRoot = new LinkedBinarySearchTreeNode<>(RootNodeData,
(Comparator.comparingInt(o -> o)));

bstRoot.insert(doubleSubTreeNodeData);
bstRoot.insert(1);
bstRoot.insert(singleSubTreeNodeData);
bstRoot.insert(4);
bstRoot.insert(9);
bstRoot.insert(3);
bstRoot.insert(terminalNodeData);
bstRoot.insert(7);

assertThat(bstRoot.search(terminalNodeData).getData())
.isEqualTo(bstRoot.remove(terminalNodeData).getData());
assertThat(bstRoot.search(singleSubTreeNodeData).getData())
.isEqualTo(bstRoot.remove(singleSubTreeNodeData).getData());
assertThat(bstRoot.search(doubleSubTreeNodeData).getData())
.isEqualTo(bstRoot.remove(doubleSubTreeNodeData).getData());
assertThat(bstRoot.search(RootNodeData).getData())
.isEqualTo(bstRoot.remove(RootNodeData).getData());
}

@Test
@DisplayName("이진_탐색_트리_제거_테스트2")
void 이진_탐색_트리_제거_테스트2() {
BinarySearchTreeNode<Integer> bstRoot = new LinkedBinarySearchTreeNode<>(5,
(Comparator.comparingInt(o -> o)));

bstRoot.insert(8);
bstRoot.insert(1);
bstRoot.insert(6);
bstRoot.insert(3);
bstRoot.insert(2);
bstRoot.insert(4);
bstRoot.insert(9);
bstRoot.insert(7);

assertThat(bstRoot.search(1).getData())
.isEqualTo(bstRoot.remove(1).getData());

assertThat(bstRoot.search(3).getData())
.isEqualTo(bstRoot.remove(3).getData());

assertThat(bstRoot.search(5).getData())
.isEqualTo(bstRoot.remove(5).getData());

assertThat(bstRoot.search(4).getData())
.isEqualTo(bstRoot.remove(4).getData());

assertThat(bstRoot.search(7).getData())
.isEqualTo(bstRoot.remove(7).getData());

assertThat(bstRoot.search(9).getData())
.isEqualTo(bstRoot.remove(9).getData());

assertThat(bstRoot.search(8).getData())
.isEqualTo(bstRoot.remove(8).getData());
}
}
61 changes: 46 additions & 15 deletions yoonexample/src/test/java/tree/binarytree/BinaryTreeNodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,43 @@

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class BinaryTreeNodeTest {

private BinaryTreeNode<Integer> bt1;
private BinaryTreeNode<Integer> bt2;
private BinaryTreeNode<Integer> bt3;
private BinaryTreeNode<Integer> bt4;
private BinaryTreeNode<Integer> bt5;

@BeforeEach
void setUp() {
bt1 = new LinkedBinaryTreeNode<>(1);
bt2 = new LinkedBinaryTreeNode<>(2);
bt3 = new LinkedBinaryTreeNode<>(3);
bt4 = new LinkedBinaryTreeNode<>(4);
bt5 = new LinkedBinaryTreeNode<>(5);

bt1.setLeftSubTree(bt2);
bt1.setRightSubTree(bt3);
bt2.setLeftSubTree(bt4);
}

@Test
@DisplayName("이진_트리_생성_및_초기화_테스트")
void 이진_트리_생성_및_초기화_테스트() {
BinaryTreeNode<Integer> bt = new LinkedBinaryTreeNode<>(1);

assertThat(bt).isNotNull();
assertThat(bt.getData()).isEqualTo(1);
assertThat(bt.getLeftSubTree()).isNull();
assertThat(bt.getRightSubTree()).isNull();
assertThat(bt5).isNotNull();
assertThat(bt5.getData()).isEqualTo(5);
assertThat(bt5.getLeftSubTree()).isNull();
assertThat(bt5.getRightSubTree()).isNull();
}

@Test
@DisplayName("이진_트리_저장_및_출력_테스트")
void 이진_트리_저장_및_출력_테스트() {
BinaryTreeNode<Integer> bt1 = new LinkedBinaryTreeNode<>(1);
BinaryTreeNode<Integer> bt2 = new LinkedBinaryTreeNode<>(2);
BinaryTreeNode<Integer> bt3 = new LinkedBinaryTreeNode<>(3);
BinaryTreeNode<Integer> bt4 = new LinkedBinaryTreeNode<>(4);

bt1.setLeftSubTree(bt2);
bt1.setRightSubTree(bt3);
bt2.setLeftSubTree(bt4);

assertThat(bt1).isNotNull();
assertThat(bt2).isNotNull();
assertThat(bt3).isNotNull();
Expand All @@ -43,4 +52,26 @@ class BinaryTreeNodeTest {
assertThat(bt1.getLeftSubTree().getLeftSubTree().getData()).isEqualTo(4);
assertThat(bt1.getLeftSubTree().getRightSubTree()).isNull();
}

@Test
@DisplayName("이진_트리_제거_테스트")
void 이진_트리_제거_테스트() {
assertThat(bt1.removeLeftSubTree()).isSameAs(bt2);
assertThat(bt1.removeRightSubTree()).isSameAs(bt3);
assertThat(bt1.getLeftSubTree()).isNull();
assertThat(bt1.getRightSubTree()).isNull();
}

@Test
@DisplayName("이진_트리_대체_테스트")
void 이진_트리_대체_테스트() {
assertThat(bt1.getLeftSubTree()).isSameAs(bt2);
assertThat(bt1.getRightSubTree()).isSameAs(bt3);

bt1.changeLeftSubTree(bt3);
assertThat(bt1.getLeftSubTree()).isSameAs(bt3);

bt1.changeRightSubTree(bt2);
assertThat(bt1.getRightSubTree()).isSameAs(bt2);
}
}