通宵爆肝:C語言下的平衡二叉樹(Avl)原來如此簡單!

文章目錄

  • 平衡二叉樹的構造過程
    • 1 算法描述
  • 平衡二叉樹的編程
    • 1 樹上結點的高度計算
    • 2 LL調整函數
    • 3 RR調整函數
    • 4 LR調整函數
    • 5 RL調整函數
    • 6 根據結點的值、動態構造平衡二叉樹


平衡二叉樹的構造過程

對一個查找問題而言,查找表的存儲結構、應該組織成二叉樹結構。而把一個離散的數據、組織成最接近滿二叉排序樹的方法,最常見的就是平衡二叉樹。

對平衡二叉樹而言,有四種調整方式,就是LL、LR、RR、RL四種方式。

1 算法描述

(1) LL調整

對圖1而言,如插入10,就是下面的過程:
在這里插入圖片描述
插入的結果就是:如40為根,則左子樹高、減去右子樹、高度差是2。在這種情況下,需要調整,調整的結果就是:注意K1、K2結點的變化。

在這里插入圖片描述
(2) RR調整

對下面的樹而言,插入80則發生RR調整:
在這里插入圖片描述
對上述二叉樹、進行調整就是下圖的過程:注意K1、K2結點的變化。

在這里插入圖片描述
(3) LR調整

對以下的圖,如果插入35,則要進行LR調整:

在這里插入圖片描述
注意下面K3的變化:

在這里插入圖片描述在這里插入圖片描述.
(4) RL調整

在以下的樹上,如果要插入53,則要進行的調整就是RL調整,注意過程:

在這里插入圖片描述
此時要調整的過程、類似LR調整,過程如下:注意K1的變化。

在這里插入圖片描述在這里插入圖片描述

平衡二叉樹的四種調整介紹完畢,你能就任意一組數據、完成構造平衡二叉樹的過程么?

平衡二叉樹的編程

1 樹上結點的高度計算

從前面的平衡二叉樹的構造過程可知:對平衡二叉樹,最關鍵的問題是結點的高度計算問題,如果每個結點的高度有了,則左右子樹的高度差也就可以計算了。

我們從二叉排序樹的結構中補充一個字段:Height,同時修改結構名稱為AvlNode,目的就是構造平衡二叉樹。

struct AvlNode{int Element;struct AvlNode  *Left;struct AvlNode  *Right;int    Height;};

我們定義:當前結點的高度、是取左右孩子高度最大值再加1,所以對一下的結點,有:

在這里插入圖片描述
注意這個高度編法,它是從樹的葉結點開始的,這樣的高度計算方法和從樹根編下來有差異,但計算左右樹高度差都是一樣的。之所以這么編高度,是因為編程中確定葉結點高度為0非常簡單。

struct AvlNode *Insert(int X, struct AvlNode *T)
{if(T==NULL){T =(struct AvlNode *)malloc(sizeof(struct AvlNode));if(T==NULL) {printf("內存不足\n");exit(0);}T->Element=X; T->Left=T->Right= NULL;T->Height=0;}if(X<T->Element) T->Left=Insert(X,T->Left);if(X>T->Element) T->Right=Insert(X,T->Right);T->Height=Max(Height(T->Left), Height(T->Right))+1;
return T;
}

在表1的第7行,我們新構造的每個結點高度都是0;

在表1的第11行,當前結點T的高度是T的左、右孩子結點高度最大者加1,這樣構造的樹、其每個結點的高度就如同表9。

能插入結點值為X并構造二叉排序樹的程序見AvlTree0.c,它能給每個結點計算高度,當然,這個程序還不能構造平衡二叉樹,它依然構造的是二叉排序樹。但我們知道:平衡二叉樹是二叉排序樹的一種特殊情況。我們就要根據這個程序,不斷修改出一個能構造平衡二叉樹的程序。

2 LL調整函數

LL調整函數的過程見圖1、圖2,首先我們給這個樹從葉結點開始編高度,其高度數據就是:

在這里插入圖片描述
為測試方便,我們先編寫main()函數、構造圖1這樣的二叉排序樹,然后再編LL調整函數,所以main()就是:

main( )
{struct AvlNode *T;struct AvlNode BT[6];/*	構造圖1的二叉排序樹 */BT[0].Element=40;BT[0].Left=&BT[1];BT[0].Right=&BT[2];BT[0].Height=3;BT[1].Element=30;BT[1].Left=&BT[3];BT[1].Right=&BT[4];BT[1].Height=2;BT[2].Element=50;BT[2].Left=NULL;  BT[2].Right=NULL;BT[2].Height=0;  BT[3].Element=20;BT[3].Left=&BT[5];BT[3].Right=NULL;BT[3].Height=1;  BT[4].Element=35;BT[4].Left=NULL;  BT[4].Right=NULL;BT[4].Height=0;   BT[5].Element=10;BT[5].Left=NULL;  BT[5].Right=NULL;BT[5].Height=0;   T=LL(BT);jConvert(T);printf("\n");
}

有這個二叉樹后再次回顧圖2,所謂LL調整就是:

如樹的根為K2,則:

K1為K2的左孩子;

K2的左孩子賦值為K1的右孩子;(35給40當左孩子)

K1的右孩子賦值為K2;(40是35的右孩子)

調整K2的高度;

調整K1的高度;

返回K1為根的樹;

用C語言寫出來就是:

struct AvlNode *LL(struct AvlNode *K2)
{
struct AvlNode *K1;
K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2;
//注意各個結點高度計算
K2->Height = Max(Height(K2->Left), Height(K2->Right))+1;
K1->Height = Max( Height(K1->Left), K2->Height)+1;
return K1;
}

全部代碼見LL.C,以下結果看看是否合理。

ID PID Value Height
0 -1 30 2
1 0 20 1
2 1 10 0
3 0 40 1
4 3 35 0
5 3 50 0

一定嘗試著用遍歷的結果來反推這個樹的形態。

3 RR調整函數

RR調整和LL調整是對稱操作,看著圖4,所以是:

如K1是根結點;

K2是K1的右孩子;

把K2的左孩子賦值給K1當右孩子(53成為50的右孩子);

K1成為K2的左孩子(50成為60的左孩子);

重新計算K1的高度;

重新計算K2的高度;

返回K2為根的二叉樹;

所以程序見下表:

struct AvlNode * RR(struct AvlNode *K1)
{
struct AvlNode *K2;
K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1;K1->Height = Max(Height(K1->Left), Height(K1->Right))+1;
K2->Height = Max(Height(K2->Right), K1->Height)+1;
return K2;
}

對照表4,可知和LL調整是完全向對應、但方向相反。

下面是測試圖4中RR調整的二叉樹數據和main()程序

main( )
{struct AvlNode *T;struct AvlNode BT[6];/*  下面這組數據是測試RR平衡的 */BT[0].Element=50;BT[0].Left=&BT[1];BT[0].Right=&BT[2];BT[0].Height=3;   BT[1].Element=40;BT[1].Left=NULL;  BT[1].Right=NULL;  BT[1].Height=0;   BT[2].Element=60;BT[2].Left=&BT[3];BT[2].Right=&BT[4];BT[2].Height=2;   BT[3].Element=53;BT[3].Left=NULL;  BT[3].Right=NULL;  BT[3].Height=0;   BT[4].Element=70;BT[4].Left=NULL;  BT[4].Right=&BT[5];BT[4].Height=1;   BT[5].Element=80;BT[5].Left=NULL;  BT[5].Right=NULL;BT[5].Height=0;   T=RR(BT);jConvert(T);printf("\n");
}

這個程序的結果見下表:

在這里插入圖片描述
仔細分析以下這些結點的關系,嘗試著用遍歷的方法反推這個樹的形態。

4 LR調整函數

從圖6的過程可以看到:

所謂LR調整、如K3為根的話,則K3的左孩子先進行RR調整,然后,整個樹再以K3為根做LL調整。
完成這樣的調整、寫成程序會非常簡單,就是:

struct AvlNode *LR(struct AvlNode *K3)
{K3->Left = RR(K3->Left);return  LL(K3);
}

每個調整過程都會自己調整結點高度,所以整個LR調整中不需要再次調整結點高度。

5 RL調整函數

從圖8的過程可知:

如樹的根結點是K1,則首先K1的右孩子進行LL調整,調整后的結果,再按K1為根進行RR調整。
所以整個RL的調整編程就是:

struct AvlNode *RL(struct AvlNode *K1)
{
K1->Right=LL(K1->Right);
return RR(K1);
}

LR.C、LR.C兩個函數的具體執行情況見相關程序。各個程序的結果請同學們自己分析。這樣,我們就完成了平衡二叉樹的結點高度定義、以及四種調整方法的函數,有了這些基礎,我們再次修改Insert()函數就有基礎了。

6 根據結點的值、動態構造平衡二叉樹

回顧表1,這個函數僅僅能構造二叉排序樹,經過修改,目前能對插入的結點計算出高度來,我們要不斷修改這個函數,讓它能構造平衡二叉樹。

首先,當插入X后,要構造出二叉排序樹,其次要立刻判斷這個結點的高度差,在表1中,在當前結點T上插入結點(以插入左子樹左孩子為例)后,就是:

if(X<T->Element) T->Left=Insert(X,T->Left);

但現在,首先要計算T的左右孩子高度差,如果高度差是2,則再次判斷X是否小于T的左孩子,如是,則必然為LL調整,否則為LR調整,就是:

if(X<T->Element)
{T->Left = Insert(X,T->Left);if(Height(T->Left)-Height(T->Right)==2)if(X<T->Left->Element)T=LL(T);elseT=LR(T);
}

注意上面的過程,是在X插入到當前結點T的左孩子的情況,此時,還有兩種可能,在第5行的判斷就是:插入到T的左孩子左子樹,則做LL調整,如是在左孩子右子樹,則做LR調整。同理可以編寫出插入到右子樹的情況,整個平衡二叉樹的構造函數就是:

struct AvlNode *Insert(int X, struct AvlNode *T)
{
if(T==NULL){T =(struct AvlNode *)malloc(sizeof(struct AvlNode));if(T==NULL) {printf("內存不夠,程序退出" );exit (0);}T->Element=X; T->Height=0;T->Left=T->Right= NULL;}if(X<T->Element){T->Left = Insert(X,T->Left);if(Height(T->Left)-Height(T->Right)==2)if(X<T->Left->Element)T=LL(T);elseT=LR(T);}if(X>T->Element){T->Right = Insert(X,T->Right);if(Height(T->Right)-Height(T->Left)== 2)if(X>T->Right->Element )T=RR(T);elseT=RL(T);}
T->Height=Max(Height(T->Left), Height(T->Right))+1;
return (T);
}

有這個函數后,我們可以編寫個main()函數,測試這個函數是否正確,整個程序見AvlTree.c,這個程序用遍歷的方法給出樹的形態,注意自己再反推回去。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285010.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285010.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285010.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[轉]定了!2020年,6種將死的編程語言!

隨著年度復工大戲的開播&#xff0c;編程界語言排行榜又要面臨一次全新的洗牌&#xff0c;六大編程語言將要黃了&#xff01;此消息一出&#xff0c;令眾多程序員心碎&#xff01;那么這將“亡”的六大語言中有你所擅長的嗎&#xff1f; Perl 曾幾何時&#xff0c;幾乎每個人都…

Java研發方向如何準備BAT技術面試答案(上)

http://blog.csdn.net/q979392157/article/details/52164319 阿里面試題總結 http://blog.csdn.net/q979392157/article/details/52173812 JAVA多線程和并發基礎 http://blog.csdn.net/q979392157/article/details/52104466 轉載于:https://www.cnblogs.com/Berryxiong/p/6…

正式發布丨AKS上的Dapr、ML、Gitops擴展

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;5分鐘)我們很高興地宣布在 Azure Kubernetes? Service&#xff08;以下簡稱AKS&#xff09;上啟用的 Dapr、Azure 機器學習和 GitOps 三項新功能正式發布&#xff0c;可以通過稱為“集群擴展”的功能在 AKS 集群上啟…

【BZOJ3036】綠豆蛙的歸宿 概率DP

鏈接&#xff1a; #include <stdio.h> int main() {puts("轉載請注明出處[輾轉山河弋流歌 by 空灰冰魂]謝謝");puts("網址&#xff1a;blog.csdn.net/vmurder/article/details/46467217"); } 題解&#xff1a; 呃。拓撲圖上從后往前掃就好了Qwq 代碼…

C語言試題182之統計一串字符包含the的個數

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款刷算法、筆試、面經、拿大公司offer神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目: 統計一…

Mac上怎么把mov文件轉成gif文件

前言 在github上&#xff0c;我們發現很多開源庫的readme里都有gif文件&#xff0c;平時聊天我們也發現經常有些小伙伴發一些自制的gif文件。怎么把mov&#xff0c;MP4等其他格式的文件轉為gif文件呢&#xff1f;網上有很多介紹各種軟件的&#xff0c;大家可以隨便Google一下&a…

[轉]nginx反向代理網站(網易、百度之類的)

使用nginx反向代理百度之類的網站和反向代理自己發布的服務設置上有點差別&#xff0c;因為此差別費時良久&#xff0c;故記錄在此。 使用include 配置文件方式&#xff0c; 首先在 nginx.conf文件的 http 中 加入&#xff0c; include /etc/nginx/proxy34.conf;p…

【ArcGIS Pro微課1000例】0013:NOAA全球1km分辨率DEM下載及拼接教程(附已拼接成果下載地址)

文章目錄 一、全球1km分辨率DEM拼接成果介紹二、全球1km分辨率DEM原始數據下載三、全球1km分辨率DEM處理拼接流程四、全球1km分辨率DEM下載地址一、全球1km分辨率DEM拼接成果介紹 在ArcGIS Pro中加載拼接好的全球1km分辨率DEM數據集,如下圖所示: 三維顯示: 柵格源信息如下:…

國際主流產品信息管理規范SMBIOS支持LoongArch架構

SMBIOS支持龍架構&#xff08;LoongArch?&#xff09;龍芯生態標準統一近日&#xff0c;DMTF&#xff08;分布式管理任務組&#xff09;宣布SMBIOS規范支持龍架構&#xff08;LoongArch?&#xff09;&#xff0c;自此基于龍架構平臺開發的基礎硬件信息都將規范統一顯示&#…

Git 常用命令(二)

用 git init 在目錄中創建新的 Git 倉庫。 $ mkdir test $ cd test/ $ git init Initialized empty Git repository in /Users/chenm/www/test/.git/ # 在 /www/test/.git/ 目錄初始化空 Git 倉庫完畢。 可以看到在你的項目中生成了 .git 這個子目錄(隱藏文件)。 這就是你的 Gi…

【ArcGIS Pro微課1000例】0014:兩種坐標系全國1km分辨率DEM下載地址(WGS84+Albers投影)

本文提供兩種坐標系全國1km分辨率DEM下載地址(WGS84+Albers投影)。 文章目錄 全國1km分辨率DEM數據預覽WGS84地理坐標系Albers投影坐標系全國1km分辨率DEM數據下載全國1km分辨率DEM數據預覽 WGS84地理坐標系 三維顯示: 柵格信息:

AsyncTask的使用半解--!

AsyncTask,即異步任務,是Android給我們提供的一個處理異步任務的類.通過此類,可以實現UI線程和后臺線程進行通訊,后臺線程執行異步任務,并把結果返回給UI線程. .為什么需要使用異步任務? 我們知道,Android中只有UI線程,也就是主線程才能進行對UI的更新操作,而其他線程是不能直…

Andorid與webView交互,獲取webView選中文字,兼容了iframe

js調試效果&#xff1a; 下面主要是拼裝js代碼 &#xff1a; /** * Description 獲取webView選中文字內容 * param webView* param callBack*/public static void webViewGetSelectedData(WebView webView,webViewGetSelectedDataCallBack callBack) {String js "function…

C語言試題183之編寫一個程序,從標準的輸入讀取一些字符,并統計下各類字符所占的百分比

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款刷算法、筆試、面經、拿大公司offer神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目: 編寫一…

C# 11 的新特性和改進前瞻

前言.NET 7 的開發還剩下一個多月就要進入 RC&#xff0c;C# 11 的新特性和改進也即將敲定。在這個時間點上&#xff0c;不少新特性都已經實現完畢并合并入主分支C# 11 包含的新特性和改進非常多&#xff0c;類型系統相比之前也有了很大的增強&#xff0c;在確保靜態類型安全的…

ajax加php實現三級聯動

js代碼 <script type"text/javascript"> function get_next(t,pid){ //當前元素的id&#xff0c;當前option的value&#xff0c;一般都是id吧&#xff1f;反正我的是 $.ajax({ type: "POST", url: "/index.p…

iOS 玩轉CocoaPods

####導語&#xff1a; 有時候看到其他人 source開源時候用pod xxx 配置在你的Podfile文件中&#xff0c;執行下pod install 或者 pod update &#xff0c;代碼瞬間就到你的pod庫, 頓時覺得高大上。那是怎么做到的呢&#xff1f; Agenda: CocoaPods 的由來Github 使用PodSpec介紹…

【ArcGIS Pro微課1000例】0015:ArcGIS Pro中屬性字段分式標注案例教程

文章目錄 1. 符號化2. 屬性字段分式標注在ArcGIS及Pro中很容易實現格式化標簽的,本文講解在ArcGIS Pro中實現屬性字段分式標注,結果如下圖所示: 1. 符號化 右鍵數據圖層→符號系統,打開符號系統對話框,住符號系統選擇【唯一值】,字段1選擇NAME。 2. 屬性字段分式標注 加…

mysql主從

1》mysql主從的工作原理&#xff1a;主服務器將更新寫入二進制日志文件&#xff08;bin_log&#xff09;&#xff0c;并維護文件的一個索引以跟蹤日志循環。這些日志可以記錄發送到從服務器的更新。當一個從服務器連接主服務器時&#xff0c;它通知 主服務器從服務器在日志中讀…

C語言試題184之編寫一個函數,從標準輸入讀取一個字符串,把字符串復制到動態內存分配的內存中,并返回該字符串的拷貝,這個函數不應該對讀入字符串的長度作任何限制

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款刷算法、筆試、面經、拿大公司offer神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目: 編寫一…