Skip to content

Commit b3d8abf

Browse files
authored
Merge pull request #40 from Data-Structure-Study/yoonexample
이진 탐색트리 구현 완료
2 parents 57a4ac6 + 8397436 commit b3d8abf

File tree

6 files changed

+257
-16
lines changed

6 files changed

+257
-16
lines changed

yoonexample/src/main/java/search/binarysearchtree/BinarySearchTreeNode.java

+8
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,12 @@ public interface BinarySearchTreeNode<E> {
2424
* @param data BST에 저장할 데이터
2525
*/
2626
void insert(E data);
27+
28+
/**
29+
* 해당 데이터를 BST에서 제거하고 해당 데이터를 저장한 노드를 반환합니다.
30+
*
31+
* @param target 제거할 데이터
32+
* @return 제거된 데이터를 저장한 노드
33+
*/
34+
BinaryTreeNode<E> remove(E target);
2735
}

yoonexample/src/main/java/search/binarysearchtree/LinkedBinarySearchTreeNode.java

+84-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

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

9-
private final BinaryTreeNode<E> node;
109
private final Comparator<E> comparator;
10+
private BinaryTreeNode<E> node;
1111

1212
public LinkedBinarySearchTreeNode(E data, Comparator<E> comparator) {
1313
this.node = new LinkedBinaryTreeNode<>(data);
@@ -62,4 +62,87 @@ public void insert(E data) {
6262
parentNode.setRightSubTree(newNode);
6363
}
6464
}
65+
66+
@Override
67+
public BinaryTreeNode<E> remove(E target) {
68+
BinaryTreeNode<E> rootDummyNode = new LinkedBinaryTreeNode<>(null);
69+
BinaryTreeNode<E> parentNode = rootDummyNode;
70+
BinaryTreeNode<E> currentNode = this.node;
71+
BinaryTreeNode<E> deleteNode;
72+
73+
rootDummyNode.changeRightSubTree(this.node);
74+
75+
while (currentNode != null && currentNode.getData() != target) {
76+
parentNode = currentNode;
77+
if (comparator.compare(target, currentNode.getData()) < 0) {
78+
currentNode = currentNode.getLeftSubTree();
79+
} else {
80+
currentNode = currentNode.getRightSubTree();
81+
}
82+
}
83+
84+
if (currentNode == null) { // 삭제 대상이 조회되지 않은 경우
85+
return null;
86+
}
87+
88+
deleteNode = currentNode;
89+
90+
if (deleteNode.getLeftSubTree() == null && deleteNode.getRightSubTree() == null) {
91+
// 삭제 대상이 단말 노드인 경우
92+
if (parentNode.getLeftSubTree() == deleteNode) {
93+
parentNode.removeLeftSubTree();
94+
} else {
95+
parentNode.removeRightSubTree();
96+
}
97+
} else if (deleteNode.getLeftSubTree() == null || deleteNode.getRightSubTree() == null) {
98+
// 삭제 대상이 하나의 자식 노드를 갖는 경우
99+
BinaryTreeNode<E> childNode;
100+
101+
if (deleteNode.getLeftSubTree() != null) {
102+
childNode = deleteNode.getLeftSubTree();
103+
} else {
104+
childNode = deleteNode.getRightSubTree();
105+
}
106+
107+
if (parentNode.getLeftSubTree() == deleteNode) {
108+
parentNode.changeLeftSubTree(childNode);
109+
} else {
110+
parentNode.changeRightSubTree(childNode);
111+
}
112+
} else {
113+
// 둘 다 있는 경우
114+
BinaryTreeNode<E> moveNode = deleteNode.getRightSubTree();
115+
BinaryTreeNode<E> moveParentNode = deleteNode;
116+
117+
// 삭제 대상의 대체 노드 찾기
118+
while (moveNode.getLeftSubTree() != null) {
119+
moveParentNode = moveNode;
120+
moveNode = moveNode.getLeftSubTree();
121+
}
122+
123+
// 대체 노드의 부모 노드와 자식 노드 연결
124+
if (moveParentNode.getLeftSubTree() == moveNode) {
125+
moveParentNode.changeLeftSubTree(moveNode.getRightSubTree());
126+
} else {
127+
moveParentNode.changeRightSubTree(moveNode.getRightSubTree());
128+
}
129+
130+
// 삭제 노드의 하위 노드를 대체 노드에 연결
131+
moveNode.changeLeftSubTree(deleteNode.getLeftSubTree());
132+
moveNode.changeRightSubTree(deleteNode.getRightSubTree());
133+
134+
// 부모 노드의 하위 노드 변경
135+
if (parentNode.getLeftSubTree() != deleteNode) {
136+
parentNode.changeRightSubTree(moveNode);
137+
} else {
138+
parentNode.changeLeftSubTree(moveNode);
139+
}
140+
}
141+
142+
if (rootDummyNode.getRightSubTree() != this.node) {
143+
this.node = rootDummyNode.getRightSubTree();
144+
}
145+
146+
return deleteNode;
147+
}
65148
}

yoonexample/src/main/java/tree/binarytree/BinaryTreeNode.java

+28
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,32 @@ public interface BinaryTreeNode<E> {
4242
* @param subTree 대상이 될 노드
4343
*/
4444
void setRightSubTree(BinaryTreeNode<E> subTree);
45+
46+
/**
47+
* 왼쪽 서브트리를 제거하고 반환합니다.
48+
*
49+
* @return 왼쪽 서브트리
50+
*/
51+
BinaryTreeNode<E> removeLeftSubTree();
52+
53+
/**
54+
* 오른쪽 서브트리를 제거하고 반환합니다.
55+
*
56+
* @return 오른쪽 서브트리
57+
*/
58+
BinaryTreeNode<E> removeRightSubTree();
59+
60+
/**
61+
* 왼쪽 서브트리를 입력된 서브트리로 대체합니다.
62+
*
63+
* @param subTree 왼쪽 서브트리를 대체할 서브트리
64+
*/
65+
void changeLeftSubTree(BinaryTreeNode<E> subTree);
66+
67+
/**
68+
* 오른쪽 서브트리를 입력된 서브트리로 대체합니다.
69+
*
70+
* @param subTree 오른쪽 서브트리를 대체할 서브트리
71+
*/
72+
void changeRightSubTree(BinaryTreeNode<E> subTree);
4573
}

yoonexample/src/main/java/tree/binarytree/LinkedBinaryTreeNode.java

+24
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,28 @@ public BinaryTreeNode<E> getRightSubTree() {
3434
public void setRightSubTree(BinaryTreeNode<E> subTree) {
3535
this.right = subTree;
3636
}
37+
38+
@Override
39+
public BinaryTreeNode<E> removeLeftSubTree() {
40+
BinaryTreeNode<E> deleteNode = this.getLeftSubTree();
41+
this.left = null;
42+
return deleteNode;
43+
}
44+
45+
@Override
46+
public BinaryTreeNode<E> removeRightSubTree() {
47+
BinaryTreeNode<E> deleteNode = this.getRightSubTree();
48+
this.right = null;
49+
return deleteNode;
50+
}
51+
52+
@Override
53+
public void changeLeftSubTree(BinaryTreeNode<E> subTree) {
54+
this.left = subTree;
55+
}
56+
57+
@Override
58+
public void changeRightSubTree(BinaryTreeNode<E> subTree) {
59+
this.right = subTree;
60+
}
3761
}

yoonexample/src/test/java/search/binarysearchtree/BinarySearchTreeNodeTest.java

+67
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,71 @@ class BinarySearchTreeNodeTest {
3737
searchNode = bstRoot.search(7);
3838
assertThat(searchNode).isNull();
3939
}
40+
41+
@Test
42+
@DisplayName("이진_탐색_트리_제거_테스트")
43+
void 이진_탐색_트리_제거_테스트() {
44+
int RootNodeData = 5;
45+
int terminalNodeData = 2;
46+
int singleSubTreeNodeData = 6;
47+
int doubleSubTreeNodeData = 8;
48+
49+
BinarySearchTreeNode<Integer> bstRoot = new LinkedBinarySearchTreeNode<>(RootNodeData,
50+
(Comparator.comparingInt(o -> o)));
51+
52+
bstRoot.insert(doubleSubTreeNodeData);
53+
bstRoot.insert(1);
54+
bstRoot.insert(singleSubTreeNodeData);
55+
bstRoot.insert(4);
56+
bstRoot.insert(9);
57+
bstRoot.insert(3);
58+
bstRoot.insert(terminalNodeData);
59+
bstRoot.insert(7);
60+
61+
assertThat(bstRoot.search(terminalNodeData).getData())
62+
.isEqualTo(bstRoot.remove(terminalNodeData).getData());
63+
assertThat(bstRoot.search(singleSubTreeNodeData).getData())
64+
.isEqualTo(bstRoot.remove(singleSubTreeNodeData).getData());
65+
assertThat(bstRoot.search(doubleSubTreeNodeData).getData())
66+
.isEqualTo(bstRoot.remove(doubleSubTreeNodeData).getData());
67+
assertThat(bstRoot.search(RootNodeData).getData())
68+
.isEqualTo(bstRoot.remove(RootNodeData).getData());
69+
}
70+
71+
@Test
72+
@DisplayName("이진_탐색_트리_제거_테스트2")
73+
void 이진_탐색_트리_제거_테스트2() {
74+
BinarySearchTreeNode<Integer> bstRoot = new LinkedBinarySearchTreeNode<>(5,
75+
(Comparator.comparingInt(o -> o)));
76+
77+
bstRoot.insert(8);
78+
bstRoot.insert(1);
79+
bstRoot.insert(6);
80+
bstRoot.insert(3);
81+
bstRoot.insert(2);
82+
bstRoot.insert(4);
83+
bstRoot.insert(9);
84+
bstRoot.insert(7);
85+
86+
assertThat(bstRoot.search(1).getData())
87+
.isEqualTo(bstRoot.remove(1).getData());
88+
89+
assertThat(bstRoot.search(3).getData())
90+
.isEqualTo(bstRoot.remove(3).getData());
91+
92+
assertThat(bstRoot.search(5).getData())
93+
.isEqualTo(bstRoot.remove(5).getData());
94+
95+
assertThat(bstRoot.search(4).getData())
96+
.isEqualTo(bstRoot.remove(4).getData());
97+
98+
assertThat(bstRoot.search(7).getData())
99+
.isEqualTo(bstRoot.remove(7).getData());
100+
101+
assertThat(bstRoot.search(9).getData())
102+
.isEqualTo(bstRoot.remove(9).getData());
103+
104+
assertThat(bstRoot.search(8).getData())
105+
.isEqualTo(bstRoot.remove(8).getData());
106+
}
40107
}

yoonexample/src/test/java/tree/binarytree/BinaryTreeNodeTest.java

+46-15
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,43 @@
22

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

5+
import org.junit.jupiter.api.BeforeEach;
56
import org.junit.jupiter.api.DisplayName;
67
import org.junit.jupiter.api.Test;
78

89
class BinaryTreeNodeTest {
910

11+
private BinaryTreeNode<Integer> bt1;
12+
private BinaryTreeNode<Integer> bt2;
13+
private BinaryTreeNode<Integer> bt3;
14+
private BinaryTreeNode<Integer> bt4;
15+
private BinaryTreeNode<Integer> bt5;
16+
17+
@BeforeEach
18+
void setUp() {
19+
bt1 = new LinkedBinaryTreeNode<>(1);
20+
bt2 = new LinkedBinaryTreeNode<>(2);
21+
bt3 = new LinkedBinaryTreeNode<>(3);
22+
bt4 = new LinkedBinaryTreeNode<>(4);
23+
bt5 = new LinkedBinaryTreeNode<>(5);
24+
25+
bt1.setLeftSubTree(bt2);
26+
bt1.setRightSubTree(bt3);
27+
bt2.setLeftSubTree(bt4);
28+
}
29+
1030
@Test
1131
@DisplayName("이진_트리_생성_및_초기화_테스트")
1232
void 이진_트리_생성_및_초기화_테스트() {
13-
BinaryTreeNode<Integer> bt = new LinkedBinaryTreeNode<>(1);
14-
15-
assertThat(bt).isNotNull();
16-
assertThat(bt.getData()).isEqualTo(1);
17-
assertThat(bt.getLeftSubTree()).isNull();
18-
assertThat(bt.getRightSubTree()).isNull();
33+
assertThat(bt5).isNotNull();
34+
assertThat(bt5.getData()).isEqualTo(5);
35+
assertThat(bt5.getLeftSubTree()).isNull();
36+
assertThat(bt5.getRightSubTree()).isNull();
1937
}
2038

2139
@Test
2240
@DisplayName("이진_트리_저장_및_출력_테스트")
2341
void 이진_트리_저장_및_출력_테스트() {
24-
BinaryTreeNode<Integer> bt1 = new LinkedBinaryTreeNode<>(1);
25-
BinaryTreeNode<Integer> bt2 = new LinkedBinaryTreeNode<>(2);
26-
BinaryTreeNode<Integer> bt3 = new LinkedBinaryTreeNode<>(3);
27-
BinaryTreeNode<Integer> bt4 = new LinkedBinaryTreeNode<>(4);
28-
29-
bt1.setLeftSubTree(bt2);
30-
bt1.setRightSubTree(bt3);
31-
bt2.setLeftSubTree(bt4);
32-
3342
assertThat(bt1).isNotNull();
3443
assertThat(bt2).isNotNull();
3544
assertThat(bt3).isNotNull();
@@ -43,4 +52,26 @@ class BinaryTreeNodeTest {
4352
assertThat(bt1.getLeftSubTree().getLeftSubTree().getData()).isEqualTo(4);
4453
assertThat(bt1.getLeftSubTree().getRightSubTree()).isNull();
4554
}
55+
56+
@Test
57+
@DisplayName("이진_트리_제거_테스트")
58+
void 이진_트리_제거_테스트() {
59+
assertThat(bt1.removeLeftSubTree()).isSameAs(bt2);
60+
assertThat(bt1.removeRightSubTree()).isSameAs(bt3);
61+
assertThat(bt1.getLeftSubTree()).isNull();
62+
assertThat(bt1.getRightSubTree()).isNull();
63+
}
64+
65+
@Test
66+
@DisplayName("이진_트리_대체_테스트")
67+
void 이진_트리_대체_테스트() {
68+
assertThat(bt1.getLeftSubTree()).isSameAs(bt2);
69+
assertThat(bt1.getRightSubTree()).isSameAs(bt3);
70+
71+
bt1.changeLeftSubTree(bt3);
72+
assertThat(bt1.getLeftSubTree()).isSameAs(bt3);
73+
74+
bt1.changeRightSubTree(bt2);
75+
assertThat(bt1.getRightSubTree()).isSameAs(bt2);
76+
}
4677
}

0 commit comments

Comments
 (0)