数据结构——平衡二叉树(AVL树)之插入
文章目錄
- 前言
- 一.定義
- 二.基本操作
- 1.查找,
- 2.插入(如何調整)
- 如何調整
- 代碼實現插入
前言
首先我們來思考一下一個普通二叉樹保存數據,如果想查找一個數據,由于普通二叉樹保存數據是隨機的,要找到數據的時間復雜度為O(n)。后面為了方便
,我們又學習二叉搜索樹,它的定義是將比根節點小的數放左邊,比根節點大的數放右邊,并且每一課子樹都是二叉搜索樹這樣使得數據在樹上存儲有一定
的規律,在一定情況下查找起來很方便。但是,二叉搜索數當給出數據的順序不同時,二叉搜索樹也會不同。比如如果給出的序列為{1,2,3,4,5}或
{3,2,1,4,5}兩顆二叉搜索樹會截然不同,查找效率也會不同。
我們知道一顆樹的查找效率與樹的高度有關,最好的樹結構當然是滿二叉樹或者是完全二叉樹,我們稱這種樹是平衡的。由我們知道二叉搜索樹在一定情況下可以達到很好的查找效率。但是,通常情況二叉搜索樹的結點插入順序并不能事先確定,動態查找(查找時同時進行刪除與插入操作)的時候總還是會改變數的結構,不能做到平衡。所以,我們就需要考慮如何保證既能完成動態查找,又能保持一個較完美樹結構的二叉搜索樹。這樣我們就有兩個問題需要考慮:一個是標準,什么樣的樹才是一顆樹結構好的樹,第二是平衡化處理,怎樣使其達到平衡。
一.定義
平衡二叉樹又稱AVL樹(由發明它的兩位數學家名字命名),它仍然是一顆二叉搜索樹,所以具備二叉搜索樹的所有性質,只是加上了"平衡"的限制。 平衡二叉樹要不是一顆空樹,要不是具備以下條件的非空二叉搜索樹: 1. 左右子樹高度差的絕對值不能超過1(平衡因子,相當于一種標準)。 2. 左右子樹仍然是一顆平衡二叉樹。 有了平衡因子的定義,我們就可以找出不平衡的樹,然后再對其進行平衡化處理,處理的具體內容分如下。處理完后使樹的高度能保持在O(logn)級別,使得 查找操作的時間復雜度為O(logn).
圖1圖2圓上為平衡因子的值,明顯圖1不是平衡二叉樹,有提個點的平衡因子超過了1。圖2是平衡二叉樹。
二.基本操作
1.查找,
由于平衡二叉樹仍是一顆二叉搜索樹,其查找操作并不會改變平衡因子,所以與二叉搜索樹的操作相同。可見博客:二叉搜索樹的查找。
2.插入(如何調整)
如何調整
假設這里有一顆平衡二叉樹:(上方代表平衡因子)
LL型
當要往D的左子樹或者右子樹插入結點時,此時破壞了原來平衡二叉樹的平衡結構,如圖:此時A結點的平衡因子超過了1,我們稱A結點為發現問題結點,六角星為產生問題結點。
此時,我們需要看發現問題結點與產生問題結點路徑上,從發現問題結點開始的連續三個結點。入上圖的A->B->D。我們發現這三個結點都在發現問題結點A左子樹的左子樹上,我們稱這種不平衡狀態為LL型(向左傾斜)不平衡。
如何調整,LL型不平衡的調整策略主要將這三個結點(A,B,D)順時針旋轉,并且仍然要是一顆二叉搜索樹。
由于二叉搜索樹的性質:
顯然只有只有從根節點到插入結點路徑上的結點才會發生平衡因子的變化,因此只需要對這條路徑上的失衡的結點進行調整,并且只需要把最靠近插入節點的失衡節點調整到正常,路徑上的所有結點都會平衡。所以發現問題的結點不一定是根節點
注意:看的是發現問題結點到產生問題結點路徑上,從發現問題結點開始的連續三個結點的方向,確定是什么型。并且主要也是調整這三個結點。
代碼如下:
RR型
RR型的處理方法與LL型類似,如圖:
產生問題結點為六角星結點(插入E的左子樹或者右子樹),發現問題結點為A結點。路徑上從發現問題結點開始的連續三個結點為(A,C,E)結點,分別在發現問題結點右子樹的右子樹上,所以為RR型(向右傾斜)不平衡。
調整方式:主要將這三個結點(A,C,E)逆時針旋轉,并且仍然要是一顆二叉搜索樹。
LR型
產生問題結點為六角星(插入E的左子樹或者右子樹),發現問題結點為A結點。路徑上從發現問題結點開始的連續三個結點為(A,B,E)結點,分別在發現問題結點左子樹的右子樹上,所以為LR型不平衡。
調整方式:“左-右雙旋”,主要先將B結點作為根節點逆時針旋轉(左旋),再以A結點作為根節點順時針旋轉(右旋)。(畫圖以白色六角星作為插入)
代碼實現調整LR型就很簡單了,先右旋,再左旋
RL型
產生問題結點為六角星(插入D的左子樹或者右子樹),發現問題結點為A結點。路徑上從發現問題結點開始的連續三個結點為(A,C,D)結點,分別在發現問題結點右子樹的左子樹上,所以為RL型不平衡。
調整方式:"右-左雙旋"主要先將C結點作為根節點順時針旋轉(右旋),再以A結點作為根節點逆時針旋轉(左旋)。(畫圖以白色六角星作為插入)
代碼實現調整RL型就很簡單了,先左旋,再右旋
代碼實現插入
#include<stdio.h> #include<stdlib.h> #include<Windows.h> #pragma warning(disable:4996)typedef int Elementtype; typedef struct Balacetree{//二叉樹信息Elementtype val;int hight;struct Balacetree *left;struct Balacetree *right;}Bactree;Bactree *TreeNodeCreate(Elementtype x){//創建樹節點Bactree *tree = (Bactree *)malloc(sizeof(Bactree));tree->val = x;tree->hight = 1;tree->left = NULL;tree->right = NULL;return tree; }int GetHight(Bactree *tree){//求樹高度if (!tree){return 0;}int H;int LH;int RH;LH = GetHight(tree->left);RH = GetHight(tree->right);H = LH > RH ? LH : RH;return H + 1; } void SigelleftCir(Bactree **tree){//LL旋轉Bactree *temp = NULL;temp = (*tree)->left;(*tree)->left = temp->right;temp->right = (*tree);(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;//調整后要保持每個結點高度正確。temp->hight = (GetHight(temp->left) > GetHight(temp->right) ? GetHight(temp->left) : GetHight(temp->right)) + 1;(*tree) = temp; //要賦值給(*tree),不然temp才是正確的數} void SigelrightCir(Bactree **tree){//RR旋轉,與LL一樣Bactree *temp = NULL;temp = (*tree)->right;(*tree)->right = temp->left;temp->left = (*tree);(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;temp->hight = (GetHight(temp->left) > GetHight(temp->right) ? GetHight(temp->left) : GetHight(temp->right)) + 1;(*tree) = temp;}void LeftrightCir(Bactree **tree){//LR旋轉SigelrightCir(&((*tree)->left));SigelleftCir(tree); } void RightleftCir(Bactree **tree){//RL旋轉SigelleftCir(&((*tree)->right));SigelrightCir(tree); }Bactree *BalaceTreePush(Bactree **tree, Elementtype x){if (!(*tree)){ //插入結點*tree=TreeNodeCreate(x);return *tree;}if ((*tree)->val > x){ //x小的插入左邊(*tree)->left = BalaceTreePush(&((*tree)->left), x);//往右邊找,將結點返回給左指針//為什么放循環里,放循環里確認了一個方向,是左邊if (GetHight((*tree)->left) - GetHight((*tree)->right) >= 2){//平衡因子if ((*tree)->left->val > x){//確認了第二個方向 左邊SigelleftCir(tree);//LL}else{//右邊LeftrightCir(tree);//LR}}}else{(*tree)->right = BalaceTreePush(&((*tree)->right), x);if (GetHight((*tree)->left) - GetHight((*tree)->right) <= -2){//注意是-2if ((*tree)->right->val < x){SigelrightCir(tree);}else{RightleftCir(tree);}}}(*tree)->hight = (GetHight((*tree)->left) > GetHight((*tree)->right) ? GetHight((*tree)->left) : GetHight((*tree)->right)) + 1;//更新高度return *tree;}void Print(Bactree *tree){if (tree){Print(tree->left);printf("%d ", tree->val);Print(tree->right);} }int main(){Bactree *T = NULL;BalaceTreePush(&T, -10);BalaceTreePush(&T, -3);BalaceTreePush(&T, 0);BalaceTreePush(&T, 5);BalaceTreePush(&T, 9);BalaceTreePush(&T, 10);Print(T);system("pause");return 0; }總結
以上是生活随笔為你收集整理的数据结构——平衡二叉树(AVL树)之插入的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab混响时间仿真,用PC机测量声
- 下一篇: vs setup project ,