ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 이진 힙, 이진 탐색 트리
    컴퓨터 공부/자료구조 2020. 4. 4. 12:40

    완전이진트리

    부모의 우선 순위 > 자식의 우선 순위

    종류

    최소힙(Minimum Heap) : 키 값이 작을수록 높은 우선순위

    최대힙(Maximum Heap) : 키 값이 클수록 높은 우선순위

     

    이진 탐색 트리

    왼쪽 서브 트리 <= 루트 노드 <= 오른쪽 서브트리 (중위 순회하면 오름차순으로 정렬)

    탐색(찾기)

    (1) 비교한 키가 같으면 탐색이 성공

    (2) 주어진 키 값이 루트 노드의 키보다 작으면 탐색은 왼쪽 자식으로 다시 시작한다.

    (3) 주어진 키 값이 루트 노드의 키보다 크면 탐색은오른쪽 자식으로 다시 시작한다.

    //순환적인 탐색 함수
    TreeNode  *search(TreeNode  *node,  int  key)
    {
          if ( node == NULL )  return NULL;
          if ( key == node->key ) return node;     (1)
          else if ( key < node->key )
                return  search(node->left, key);     (2)
          else
                return  sear ch(node->right, key);  (3)
    }
    

    삽입

    먼저 탐색하다가

    탐색에 실패한 위치에 새로운 노드를 삽입

    void insert_node(TreeNode **root, int key) 
    {
    	TreeNode *p, *t; // p는 부모노드, t는 현재노드 
    	TreeNode *n;	 // n은 새로운 노드
    	t = *root;
    	p = NULL;
    	// 탐색을 먼저 수행 
    	while (t != NULL){
    	    if( key == t->key ) return;
    	    p = t;
    	    if( key < t->key ) t = t->left;
    	    else t = t->right;
    	}
    	// key가 트리 안에 없으므로 삽입 가능
    	n = (TreeNode *) malloc(sizeof(TreeNode));
    	if( n == NULL ) return;
    	// 데이터 복사
    	n->key = key;
    	n->left = n->right = NULL;
    	// 부모 노드와 링크 연결
    	if( p != NULL ) 
    		if( key < p->key ) 
    			p->left = n;
    		else p->right = n;
    	else *root = n;
    }
    

     

     

     

     

    삭제

    1. 삭제하려는 노드가 단말 노드 -> 부모노드를 찾아서 연결 끊기

    더보기

    // 1. 단말노드인 경우
    if( (t->left==NULL) && (t->right==NULL) ){ 
       if( p != NULL ){
          // 부모노드의 자식필드를 NULL로 만든다.
          if( p->left == t )  
             p->left = NULL;
          else p->right = NULL;
       }
       else  // 만약 부모노드가 NULL이면 삭제되는 노드가 루트
          *root = NULL;
    }

    2. 삭제하려는 노드가 자식 하나만 가짐 -> 자식만 부모에 붙여줌 

    더보기

    // 2. 하나의 자식만 가지는 경우
    else if((t->left==NULL)||(t->right==NULL)){
      child = (t->left != NULL) ? t->left : t->right;
       if( p != NULL ){
          if( p->left == t ) // 부모를 자식과 연결 
             p->left = child;
          else p->right = child;
       }
       else // 만약 부모노드가 NULL이면 삭제되는 노드가 루트
          *root = child;
    }

    3. 삭제하려는 노드가 자식 둘 다 가짐 -> 두 자식 중 가장 비슷한 자식을 삭제할 위치로 가져옴

    더보기

    // 3. 두개의 자식을 가지는 경우
    else{
       // 오른쪽 서브트리에서 후계자를 찾는다.
       succ_p = t;
       succ = t->right;
       // 후계자를 찾아서 계속 왼쪽으로 이동한다.
       while(succ->left != NULL){
          succ_p = succ;
          succ = succ->left;
       }
       // 후속자의 부모와 자식을 연결 
       if( succ_p->left == succ )
          succ_p->left = succ->right;
       else 
          succ_p->right = succ->right;
       // 후속자가 가진 키값을 현재 노드에 복사
       t->key = succ->key;
       // 원래의 후속자 삭제
       t = succ;
    }

    // 삭제 함수
    void delete_node(TreeNode **root, int key)
    {
    TreeNode *p, *child, *succ, *succ_p, *t;
    // key를 갖는 노드 t를 탐색, p는 t의 부모노드
    p = NULL;
    t = *root;
    
    // key를 갖는 노드 t를 탐색한다.
    while( t != NULL && t->key != key ){
       p = t;
       t = ( key < t->key ) ? t->left : t->right;
    }
    
    // 탐색이 종료된 시점에 t가 NULL이면 트리안에 key가 없음
    if( t == NULL ) { 	// 탐색트리에 없는 키
       printf("key is not in the tree");
       return;
    }
    
    // 1. 단말노드인 경우
    if( (t->left==NULL) && (t->right==NULL) ){ 
       if( p != NULL ){
          // 부모노드의 자식필드를 NULL로 만든다.
          if( p->left == t )	 
             p->left = NULL;
          else p->right = NULL;
       }
       else  // 만약 부모노드가 NULL이면 삭제되는 노드가 루트
          *root = NULL;
    }
    
    // 2. 하나의 자식만 가지는 경우
    else if((t->left==NULL)||(t->right==NULL)){
      child = (t->left != NULL) ? t->left : t->right;
       if( p != NULL ){
          if( p->left == t )	// 부모를 자식과 연결 
             p->left = child;
          else p->right = child;
       }
       else // 만약 부모노드가 NULL이면 삭제되는 노드가 루트
          *root = child;
    }
    // 3. 두개의 자식을 가지는 경우
    else{		
       // 오른쪽 서브트리에서 후계자를 찾는다.
       succ_p = t;
       succ = t->right;
       // 후계자를 찾아서 계속 왼쪽으로 이동한다.
       while(succ->left != NULL){
          succ_p = succ;
          succ = succ->left;
       }
       // 후속자의 부모와 자식을 연결 
       if( succ_p->left == succ )
          succ_p->left = succ->right;
       else 
          succ_p->right = succ->right;
       // 후속자가 가진 키값을 현재 노드에 복사
       t->key = succ->key;
       // 원래의 후속자 삭제
       t = succ;
    }
    free(t);
    }
    
    

     

    최선의 경우 (높이에 비례)

    균형 트리,  h = log N

    최악의 경우

    경사이진트리, h = N

    '컴퓨터 공부 > 자료구조' 카테고리의 다른 글

    트리 순회  (0) 2020.04.04
    트리  (0) 2020.04.03
    연결리스트  (0) 2020.03.28
    정렬 - 퀵, 힙, 기수  (0) 2020.03.25
    정렬 - 삽입, 선택, 버블, 쉘, 합병  (0) 2020.03.25
Designed by Tistory.