- 특징: 임의 키를 가진 원소를 삽입, 삭제, 검색하는데 효율적인 자료구조
- 정의: 모든 원소는 상이한 키를 가짐 + 왼쪽 키 < 루트 키 < 오른쪽 키
- 원소 탐색 방법:
- 키 값= x, 루트에서 탐색 시작 -> 공백일 시 실패로 종료 -> 루트키가 x이면 성공으로 종료
- 키 값 x < 루트 키 일때, 왼쪽 서브트리만 탐색, 또는 반대로
- 알고리즘
public BinaryTree find(String x) {
BinaryTree T = btree;
int result;
while (T != null) {
// 비교를 해서 data보다 작음으로 왼쪽 링크를 쫒아감.
if ((result = x.compareTo((String) T.data)) < 0) {
// 왼쪽 링크 쫓아감
T=T.llink;
}
// 비교를 해서 data와 같으므로 검색된 data를 반환함.
else if (result == 0) {
return T;
}
// 비교를 해서 data보다 큼으로 오른쪽 링크를 쫒아감.
else {
// 오른쪽 링크 쫓아감
T=T.rlink;
}
}
return T;
}
}
- 원소 삽입 방법:
- 알고리즘
private BinaryTree insertKey(BinaryTree T, String x) {
// 공백노드일시 최상위 노드에 삽입
if (isEmpty(T)) {
// 왼쪽, 오른쪽 링크는 null로 데이터는 x인 이진트리 생성
BinaryTree newNode = new BinaryTree(null, x, null);
return newNode;
}
// 입력된 문자열이 data보다 작으면 왼쪽 링크에 삽입
else if (x.compareTo((String) T.data) < 0) {
// 왼쪽 링크에 다시 insertKey를 사용하여 반환값 저장
T.llink=insertKey(T.llink,x);
return T;
}
// 입력된 문자열이 data보다 크면면 오른쪽 링크에 삽입
else if (x.compareTo((String) T.data) > 0) {
//오른쪽 링크에 다시 insertKey를 사용하여 반환값 저장
T.rlink=insertKey(T.rlink, x);
return T;
}
else {
return T;
}
}
- 원소 삭제 방법:
- 삭제하고자 하는 키 값의 원소 탐색 -> 노드 발견 시 삭제 연산
a. 자식이 없는 리프 노드 삭제
->부모 노드의 해당 링크 필드를 null로 변경 후 삭제
b. 자식이 하나인 노드 삭제
-> 삭제되는 노드 자리에 자식 노드를 위치시킴
c. 자식이 둘인 노드 삭제
-> 삭제되는 노드 자리에: 왼쪽 서브트리에서 제일 큰 원소 or 오른쪽 서브 트리에 제일 작은 원소로 대체
- 이원 탐색 트리의 결합과 분할
1. 3원 결합: threeJoin(aBST,x,bBST,cBST)
- 새로운 트리노드 cBST생성 -> key값이 x -> Left링크 필드에 aBST, Right 링크 필드에 bBST설정
- 결합을 위한 조건: aBST의 모든 원소 < x, bBST의 모든 원소 > x
- 새로운 이원 탐색 트리의 높이 = max{height(aBST), height(bBST)} + 1
2. 2원 결합: twoJoin(aBST,bBST,cBST)
- aBST와 bBST를 결합하여 하나의 이원 탐색 cBST를 생성함
- 결합을 위한 조건: aBST 모든 키 < bBST 모든 키
- cBST의 높이: max{height(aBST), height(bBST)} + 1
a. aBST에서 키 값 가장 큰 원소 삭제 후 threeJoin(aBST', max, bBST, cBST) 실행
b. bBST에서 가장 작은 원소 삭제
3. 분할: split(aBST, x, bBST, cBST)
- 이원 탐색 트리 aBST를 주어진 키 값 x를 기준으로 b,c로 분할
- 조건: bBST에서 x보다 작은 키 가진 aBST의 모든 원소 포함, cBST는 x보다 큰 키값을 가진 aBST모두 포함,
키 x가 aBST에 있다면 true, 아니면 false를 반환
- 분할 연산: split(aBST, x, bBST, cBST)
i) aBST 루트 노드의 키 = x: x의 왼쪽 서브트리는 bBST + 오른쪽 서브트리는 cBST
ii) 루트노드 키 값 > x: 루트, 오른쪽 서브트리 ⊂ cBST
iii) 루트노드 키 값 < x: 루트, 왼쪽 서브트리 ⊂ bBST
* 분할 연산 알고리즘
split(aBST, x, bBST, cBST)
small <- getTreeNode(); //키 값 x보다 큰 원소로된 BST
large <- getTreeNode(); //키 값 x보다 작은 원소로된 BST
S <- small; //smallBST 순회 포인터
L <- large; //largeBST 순회 포인터
P <- aBST; //aBST 순회 포인터
4. 이원 탐색 트리의 수행 시간
- 트리의 높이 커짐 -> 원소 검색-삽입-삭제 연산 수행 시간 늘어남
- n 개의 노드 이원 탐색트리의 높이 = n - 1
- 평균적인 높이 = O(log n)
+ 이진 트리의 기타 주요 연산
a. 리프 노드인지 확인하는 함수: isLeaf()
public boolean isLeaf() {
if(llink==null&&rlink==null)
return true;
else
return false;// 왼쪽 링크와 오른쪽 링크가 null인지 확인
}
b. 이진트리의 노드의 개수를 구하는 함수: size()
public int size() {
// 왼쪽 링크와 오른쪽 링크가 null이면 반환값 1
if(llink==null&rlink==null)
return 1;
// 왼쪽 링크만 null이면 오른쪽 링크의 크기와 루트의 크기(1)을 더해서 반환
else if(llink==null&&rlink!=null)
return rlink.size()+1;
// 오른쪽 링크만 null이면 왼쪽 링크의 크기와 루트의 크기(1)을 더해서 반환
else if(llink!=null&&rlink==null)
return llink.size()+1;
// 왼쪽, 오른쪽 링크 둘 다 null이 아니라면 왼쪽+오른쪽+루트 크기 반환
else
return 1+llink.size()+rlink.size();
}
c. 이진트리의 리프노드 개수를 구하는 함수: numLeave()
public int numLeaves() {
if (llink==null && rlink==null) return 1;
if (llink==null) return rlink.numLeaves();
// 오른쪽 링크가 null이면 왼쪽 링크의 numLeaves 호출
if(rlink==null) return llink.numLeaves();
// 왼쪽, 오른쪽 링크가 null이 아니면 왼쪽과 오른쪽 링크의 numLeaves를 더함
return 1+ rlink.numLeaves()+llink.numLeaves();
}
'알고리즘' 카테고리의 다른 글
[Algorithm]그래프(Graph)의 정의 - 그래프 추상 데이터 타입 (0) | 2022.10.11 |
---|---|
[Algorithm]선택트리(Selection Tree) (1) | 2022.10.11 |
[Algorithm]힙(Heap)+ 우선순위Q (0) | 2022.10.11 |
[Algorithm]이진 트리 순회(Traversal) (0) | 2022.09.28 |
[Algorithm]트리와 이진트리의 기본 개념 (0) | 2022.09.28 |