1. 程式人生 > >平衡二叉樹(Balanced Binary Tree 或 Height-Balanced Tree)又稱AVL樹

平衡二叉樹(Balanced Binary Tree 或 Height-Balanced Tree)又稱AVL樹

binary strong 但是 inf ++i 平衡二叉樹 data 效率 assert

平衡二叉樹(Balanced Binary Tree 或 Height-Balanced Tree)又稱AVL樹

技術分享圖片

(a)和(b)都是排序二叉樹,但是查找(b)的93節點就需要查找6次,查找(a)的93節點就需要查找3次,所以(b)的效率不高。

平衡二叉樹(Balanced Binary Tree 或 Height-Balanced Tree)又稱AVL樹。它或者是一顆空樹,或者是具有下列性質的二叉樹:它的左子樹和右子樹的深度只差的絕對值不超過1。若將二叉樹上節點的平衡因子BF(Balance Factor)定義為該節點的左子樹的深度減去它右子樹的深度,則平衡二叉樹上所有節點的平衡因子只可能是-1,0,1。只要二叉樹上有一個節點的平衡因子的絕對值大於1,則該二叉樹就是不平衡的。

技術分享圖片

上圖(a)是平衡二叉樹,(b)不是平衡二叉樹,因為有的節點的平衡因子大於1了。

插入節點的大致思路:

  • 首先找到插入節點的位置,插入節點
  • 插入節點後,調整相關節點的平衡因子
  • 調整平衡因子後,如果發現樹不平衡了,就要進行節點的調整(單左旋轉,或單右旋轉,或雙旋轉(先左後又,或者先右後左)。

avl_tree.h

#ifndef __AVLTREE__
#define __AVLTREE__

#include<stdio.h>
#include<malloc.h>
#include<assert.h>
#include "nodestack.h"

#define Type int
#define FALSE 0
#define TRUE 1
#define BOOL int

typedef struct AVLNode{
  Type data;
  struct AVLNode* left;
  struct AVLNode* right;
  int bf;//平衡因子
}AVLNode;

typedef struct AVLTree{
  struct AVLNode* root;
}AVLTree;

void init_avl_tree(AVLTree* avl);
//插入節點
BOOL insert_avl(AVLTree* avl, Type t);

#endif

avl_tree.c

#include "avl_tree.h"

void init_avl_tree(AVLTree* avl){
  avl->root = NULL;
}
AVLNode* malNode(Type x){
    AVLNode* t = (AVLNode*)malloc(sizeof(AVLNode));
    assert(NULL != t);
    t->data  = x;
    t->left  = NULL;
    t->right = NULL;
    t->bf    = 0;
    return t;
}
//右旋轉
void rotateR(AVLNode** t){
  AVLNode* subR = *t;
  *t = (*t)->left;
  subR->left = (*t)->right;
  (*t)->right = subR;
  (*t)->bf = 0;
  subR->bf = 0;

}
//左旋轉
void rotateL(AVLNode** t){
  AVLNode* subL = *t;
  *t = (*t)->right;
  subL->right = (*t)->left;
  (*t)->left = subL;
  (*t)->bf = 0;
  subL->bf = 0;

}
//左右旋轉
void rotateLR(AVLNode** t){
  AVLNode* subR = *t;
  AVLNode* subL = subR->left;
  *t = subL->right;

  subL->right = (*t)->left;
  (*t)->left = subL;
  if((*t)->bf <= 0){///??
    subL->bf = 0;
  }
  else{
    subL->bf = -1;
  }

  subR->left = (*t)->right;
  (*t)->right = subR;
  if((*t)->bf == -1){
    subR->bf = 1;//???
  }
  else{
    subR->bf = 0;//???
  }

  (*t)->bf = 0;  
}
//右左旋轉
void rotateRL(AVLNode** t){
  AVLNode* subL = *t;
  AVLNode* subR = subL->right;
  *t = subR->left;
  
  subR->left = (*t)->right;
  (*t)->right = subR;
  if((*t)->bf >= 0){
    subR->bf = 0;
  }
  else{
    subR->bf = 1;
  }

  subL->right = (*t)->left;
  (*t)->left = subL;
  if((*t)->bf == 1){
    subL->bf = -1;
  }
  else{
    subL->bf = 0;
  }

  (*t)->bf = 0;
}
//插入樹的節點
BOOL insert_avl_node(AVLNode** t, Type x){
  AVLNode* p = *t;
  AVLNode* parent = NULL;

  nodestack st;
  init(&st);
  
  while(p != NULL){
    if(x == p->data)
      return FALSE;
    parent = p;
    push(&st, parent);
    if(x < p->data)
      p = p->left;
    else
      p = p->right;
  }
  p = malNode(x);
  //插入節點為root節點
  if(parent == NULL){
    *t = p;
    return TRUE;
  }
  //插入節點不是root節點
  if(x < parent->data)
    parent->left = p;
  else
    parent->right = p;

  //調整BF
  while(length(&st) != 0){
    parent = getTop(&st);
    pop(&st);
    if(parent->left == p){
      parent->bf--;
    }
    else{
      parent->bf++;
    }
    
    if(parent->bf == 0){
      break;
    }
    if(parent->bf == 1 || parent->bf == -1){
      p = parent;
    }
    else{
      //旋轉樹,讓樹變成平衡樹
      int flag = (parent->bf < 0) ? -1 : 1;
      //符號相同,說明是一條直線,不是折線,所以單旋轉
      if(p->bf == flag){
    //因為是撇/,所以右旋轉
    if(flag == -1){
      rotateR(&parent);
    }
    //因為是捺\,所以左旋轉
    else{
      rotateL(&parent);
    }
      }
      //符號不同,說明是折線,所以雙旋轉
      else{
    //折線的角指向右>
    if(flag == 1){
      rotateRL(&parent);
    }
    //折線的角指向左<
    else{
      rotateLR(&parent);
    }
      }
      break;
    }
  }
  
  
  if(length(&st) == 0){
    *t = parent;
  }
  else{
    AVLNode* q = getTop(&st);
    if(q->data > parent->data){
      q->left = parent;
    }
    else{
      q->right = parent;
    }
  }
  

  clear(&st);
  return TRUE;
}
//插入節點
BOOL insert_avl(AVLTree* avl, Type t){
  return insert_avl_node(&avl->root, t);
}

avl_treemain.c

#include "avl_tree.h"

int main(){
  AVLTree avl;
  init_avl_tree(&avl);

  //Type ar[] = {13,24,37,90,53};
  //Type ar[] = {30,20,10};  
  //Type ar[] = {30,20,40,10,25,5,22,28,21};  
  //Type ar[] = {30,20,10};
  //Type ar[] = {50,40,60,10,45,70,5,30,20,12};
  Type ar[] = {30,20,50,10,40,70,60,80,55};

  int n = sizeof(ar) / sizeof(Type);
  for(int i = 0; i < n; ++i){
    insert_avl(&avl, ar[i]);
  }
  return 0;
}

完整代碼

編譯方法:g++ -g nodestack.c avl_tree.c avl_treemain.c

平衡二叉樹(Balanced Binary Tree 或 Height-Balanced Tree)又稱AVL樹