linked list에서 탐색의 경우, 최악은 O(n). 탐색을 head에서부터 해야 하므로 임의의 장소로 바로 갈 수 없다.
기본적인 tree의 용어 및 구조에 대해 확인하고 binary tree와 binary search tree에 대해 학습한다.
선형구조인 list에 비해 탐색시간이 절감된다는 큰 장점이 있다.
node, edge, root, subtree, child
sibling: 같은 level의 children
leaf: child가 없는 노드
ancester: 특정 노드로부터 root까지 올라가며 존재하는 모든 노드
decendent: subtree의 모든 것
Depth of x
: length of path from root to x (root에서부터 x까지의 path 수)
: number of edges in path from root to x (root에서부터 x까지의 path에 있는 간선의 수)
height of x
: number of edges in logest path from x to leaf (x에서부터 leaf노드까지의 가장 긴 path에 있는 간선의 수)
: children을 최대 2개까지만 가질 수 있는 tree
: 마지막 level을 제외하고 모든 level이 완전히 채워지고, 만약 채워지지 않았다면 모든 노드들이 왼쪽부터 채워진 트리
: 마지막 level까지 모든 노드가 2개의 자식을 가지는 트리
: 모든 노드의 왼쪽 서브트리와 오른쪽 서브트리의 높이 차이가 k보다 크지 않은 트리 (보통 k=1)
이진트리 | 이진탐색트리 | |
---|---|---|
search, insert, remove | 배열(정렬x) O(n), O(1), O(n) 연결리스트 O(n), O(1),O(n) 배열(정렬o) O(log n), O(n), O(n) | O(log n) |
정렬여부 | X | O |
Strucnt BSTNode{
int data;
BSTNode* left;
BSTNode* right;
}
BSTNode* Insert(BSTNode* root, int data){
if(root==NULL){
root = GetNewNode(data);
}else if(data <= root->data){
root->left = Insert(root->left, data);
}else{
root->right = Insert(root->right, data);
}
return root;
}
int Search(BSTNode* root, int data){
if(root == NULL) return 0;
else if(root-> data == data) return 1;
else if(root->data >= data) return Search(root->left, data);
else return Search(root->right, data);
}
int main(){
BSTNode* rootPtr;
root = Insert(0,15);
root = Insert(root,10);
root = Insert(root,20);
.
.
.
num입력받기
if(Search(root, num) == 1) Printf('found');
}
자세히 살펴보자.
//main
root = Insert(0,15);
main의 다음 코드에 따라 Insert 함수를 호출한다.
BSTNode* Insert(BSTNode* root, int data){
if(root==NULL){
root = GetNewNode(data);
}else if(data <= root->data){
root->left = Insert(root->left, data);
}else{
root->right = Insert(root->right, data);
}
return root;
}
Insert의 첫 if문으로 들어가며 다음과 같은 상태가 된다.
//main
root = Insert(root,10);
root가 200을 가리키고 data(10)이 root의 data(15)보다 작으므로 else if 로 진입한다.
else if 내의 순환으로, Insert(0, 10)을 호출하고 root->left가 그를 가리킨다.
//current선언
int FindMin(BSTNode * root){
if(root == NULL){
printf("error, Empty");
return -1;
}
BSTNode* current = root;
while(current->left != NULL){
current = current->left;
}
return current->data;
}
또는
//current선언없이, root를 바로 사용해도 된다. 파라미터 root는 함수 내에 있는 지역변수이므로
int FindMin(BSTNode * root){
if(root == NULL){
printf("error, Empty");
return -1;
}
while(root->left != NULL){
root = root->left;
}
return root->data;
}
//순환호출 사용하기
int FindMin(BSTNode * root){
if(root == NULL){
printf("error, Empty");
return -1;
}else if(root->left == NULL){
return root->data;
}
return FindMin(root->left);
}
//current선언
int FindMax(BSTNode * root){
if(root == NULL){
printf("error, Empty");
return -1;
}
while(root->right != NULL){
root = root->right;
}
return root->data;
}
cf.
depth: root에서 x까지의 높이
(height는 root에서 x를 거쳐 leaf까지의 높이)
int FindHeight(BSTNode* root){
if(root == NULL) return -1;
int leftHeight = FindHHeight(root->left);
int rightHeight = FindHeight(root->right);
return max(leftHeight, rightHeight) + 1;
}
최악은 O(n
보통......
아래의 트리에 대해 1, 2번 순회를 확인한다.
F -> D -> J -> B -> E -> G -> K -> A -> C -> I -> H 순으로 순회한다.
root, left, right순으로 순회한다.
위의 트리에 대해, F -> D -> B -> A -> C -> E -> J -> G -> I -> H -> K 순으로 순회한다.
left, root, right순으로 순회한다.
A -> B -> C -> D-> E -> F -> G -> H -> I -> J -> K
left, right, root순으로 순회한다.
A -> C -> B -> E -> D -> H -> I -> G -> K -> J -> F
ADT를 생각하고 구현한다.