數據結構之二叉樹的精講

𝙉𝙞𝙘𝙚!!👏🏻???????👏🏻??????? 👏🏻?????:Solitary_walk

? ? ? ?? ? ━━━┓
? ? ?- 個性標簽 - :來于“云”的“羽球人”。 Talk is cheap. Show me the code
┗━━━━━━━ ?? ?

本人座右銘 : ? 欲達高峰,必忍其痛;欲戴王冠,必承其重。

👑💎💎👑💎💎👑?
💎💎💎自💎💎💎
💎💎💎信💎💎💎
👑💎💎 💎💎👑 ? ?希望在看完我的此篇博客后可以對你有幫助喲

👑👑💎💎💎👑👑 ? 此外,希望各位大佬們在看完后,可以互相支持,蟹蟹!
👑👑👑💎👑👑👑


對二叉樹的基本概念性的理解,若有不明白的友友們,可以看一下前期寫的關于堆與二叉樹的精講

鏈接在此:

有了大家對二叉樹的基本理解接下來,對以下知識的理解應該是易如反掌!

1.二叉樹的鏈式結構的實現

?對于任何一個二叉樹的節點來說:都是由值域,左孩子,右孩子構成,只不過對于某些節點而言左右孩子為空

1.1定義一個二叉樹的結構體
typedef int BT_DataType;
typedef struct BinaryTreeNode
{struct BinaryTreeNode* left; //左孩子struct BinaryTreeNode* right;//右孩子BT_DataType val;  //值域}BT;
1.2二叉樹的鏈式結構

?為了方便對二叉樹的理解,我暫時手動創建節點,進行連接

BT* BT_Create()
{BT* n1 = BuyNode( 1);BT* n2 = BuyNode( 2);BT* n3 = BuyNode( 3);BT* n4 = BuyNode( 4);BT* n5 = BuyNode(5);BT* n6 = BuyNode( 6);BT* n7 = BuyNode( 7);BT* n8= BuyNode( 8);BT* n9 = BuyNode( 9);BT* n10 = BuyNode( 10);n1->left = n2;n1->right = n3;n2->right = n4;n3->left = n5;n3->right = n6;n2->left = n7;n4->left = n8;return n1;
}
2.二叉樹的遍歷
2.1前序遍歷(先序遍歷)

先訪問根節點,其次訪問左子樹,左后訪問右子樹,注意這是一個遞歸的定義。

見圖如下:

?代碼:
void Pre_order(BT* root)
{if (root == NULL){printf("%c ", 'n');//返回n表示為空return;}printf("%d ", root->val);Pre_order(root->left);Pre_order(root->right);
}
遞歸展開圖的解釋:

2.2中序遍歷

先訪問左子樹,在訪問根節點最后訪問右子樹,依然是一個遞歸的定義

分析如下:
?代碼:
void In_Order(BT* root)
{if (root == NULL){printf("%c ", 'n');//返回n表示為空return;}In_Order(root->left);printf("%d ", root->val);In_Order(root->right);
}
2.3后續遍歷

先訪問左子樹,再訪問右子樹,最后訪問根節點,依然是遞歸定義

分析見下:

代碼:
void Post_Order(BT* root)
{if (root == NULL){printf("%c ", 'n');//返回n表示為空return;}Post_Order(root->left);Post_Order(root->right);printf("%d ", root->val);}
3.與二叉樹相關節點的求解
3.1求二叉樹所有節點個數

可能有些老鐵們會說:直接進行計數就可以了:只有是當前節點不為空就讓計數器(size)加一,采用前序遍歷的方法。沒錯也可以這樣但是這樣有些坑需要注意一下否則一不小心就掉進坑里了。

?

?這時候可能有老鐵會說,直接定義一個全局變量不就OK了,注意當我們連續調用BT_Size()這個函數進行求個數的話會有問題滴!

?因為szie作為一個全局變量,第一調用確實為8沒有錯,但是當我們后續在進行調用的時候就需要把size 手動進行置零,(關于這個問題詳解,感興趣的友友們,可以看前期我寫的博客:鏈接在此,自取,蟹蟹支持!)要不然只會在當前size = 8 的基礎上進行相加,這也就是為什么最后會出現16,24的這樣結果了,也就不以為奇了。

代碼:
int size = 0;
int BT_Size(BT* root)
{//int size = 0;if (root == NULL)return size;size++;BT_Size(root->left);//對左子樹進行個數的遍歷BT_Size(root->right);//對右子樹進行個數的遍歷return size;
}

?運行結果:

3.2求二叉樹葉節點個數

既然是讓咱求葉節點個數,咱就需要知道什么是葉節點:度為0的節點(沒有左孩子,也沒有右孩子的節點)

通過前面對二叉樹的遍歷咱們應該漸漸對遞歸要有些體悟了,當一個問題很大的時候,可以化大為小,化繁為簡。這樣豈不是很爽!

?分析見下:
?代碼:
int BT_Leaf_Size(BT* root)
{if (root == NULL)return 0;if (root->left == NULL && root->right == NULL) // 判斷是否為葉節點return 1;return  BT_Leaf_Size(root->left) + BT_Leaf_Size(root->right);
}
3.3求二叉樹第H層節點個數

假設根節點所在層次就是第一層,依次下推,第H層的每個節點必然是第(H-1)層節點的左右孩子,這不就解決問題了嘛:求二叉樹第H層節點個數轉化為求二叉樹第H-1層每個節點的左右孩子之和不就OK了。

?分析見下:

?代碼:
int BT_LevelH_Size(BT* root, int h)
{if (root == NULL)return 0;if (h == 1)return 1;
return BT_LevelH_Size(root->left, h - 1)+ BT_LevelH_Size(root->right, h - 1) ;
}
4.二叉樹高度的求解

對于一個二叉樹而言,樹的高度是左子樹與右子樹相比高度最大的一個再加1

還是如此,借助遞歸思想

子問題:左子樹與右子樹相比高度最大的一個再加1

結束條件:判斷當前節點是否為空,其次當前節點是否為葉節點

?分析見下:

代碼:
int BT_Height(BT* root)// 求樹高度
{if (root == NULL)return 0;if (root->left == NULL && root->right == NULL)return 1;int left_h = BT_Height(root->left);int right_h = BT_Height(root->right);return left_h > right_h ? left_h + 1 : right_h + 1;
}
5.二叉樹的銷毀

注意這是鏈式二叉樹,不能直接進行刪除,更為直接的是采用后續遍歷來進行銷毀

代碼:

void BT_Destroy(BT* root)
{if (root == NULL)return;BT_Destroy(root->left);BT_Destroy(root->right);free(root);
}
6.二叉樹的層次遍歷

?對于二叉樹的層次遍歷很顯然就是一層一層進行遍歷,在這里借助隊的性質先進先出,來實現對二叉樹的層次遍歷

當隊頭元素出隊的時候同時讓隊頭元素的左右孩子節點也進隊

?這里需要借助咱們之前寫的隊列的相關代碼才可以玩喲!

?代碼:
void Level_order(BT* root)
{Queque q;QuqueInit(&q);QuquePush(&q, root);while (!QuequeEmpty(&q)){BT* front = QuequeFront(&q);//取隊頭元素if (front)printf("%d ", front->val);QuquePop(&q);//刪除隊頭元素//隊頭元素的左右孩子進隊if (front)  {QuquePush(&q, front->left);QuquePush(&q, front->right);}}QuqueDestroy(&q);
}
7.借助二叉樹前序遍歷的結果實現對二叉樹的構建

?分析:?還是分治的思想,層層遞歸,直到遇到空返回,把每一個節點看作一個新的根節點,只要當前節點不為空,就繼續先序遍歷

首先這是一個IO型的,所以完全需要自己手撕代碼,

先把當前字符串的內容進行接收

其次利用遞歸:先序建立二叉樹

子問題:先序建立? ? 結束條件:遇到空,直接返回

最后利用遞歸寫一個中序遍歷

?輔助:需要我們每一個數據開辟節點

?定義一個二叉樹的結構體:

?遞歸建立二叉樹:

注意這里必須是 (*pi)++,不能是 *pi++。因為是遞歸調用每一次都需要進行棧幀建立,這樣就不能做保證下標正確性,問題本質同二叉樹求節點個數中的size

?完整代碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef char BT_DataType; // 存儲char類型數據
typedef struct BinaryTreeNode
{struct BinaryTreeNode* left;struct BinaryTreeNode* right;BT_DataType val;}BT;
BT* BuyNode( BT_DataType x)
{BT*  n1 = (BT*)malloc(sizeof(BT));if (n1 == NULL)return NULL;n1->val = x;n1->left = n1->right = NULL;return n1;
}
BT* CreateTree(char*pa,int* pi){if(pa[*pi] == '#'){(*pi)++; // err *(pi)++return NULL;}BT*root = BuyNode(pa[*pi]);(*pi)++; // err *(pi)++root->left = CreateTree(pa,pi );root->right =CreateTree(pa,pi );return root;}void  In_Order(BT*root){if(root == NULL)return ;In_Order(root->left);printf("%c ",root->val);In_Order(root->right);}int main() 
{char a[100];scanf("%s",a);int i = 0;// 下標訪問數組BT* root =  CreateTree(a,&i);In_Order(root);
}
8.判斷一棵樹是否為完全二叉樹

?對于這個,可以借助層次遍歷的思想來玩。只要是在出隊的時候連續全部為空即為完全二叉樹;否則就不是完全二叉樹

?

代碼:

bool BT_Complete(BT* root)
{Queque q;QuqueInit(&q);QuquePush(&q, root);while (!QuequeEmpty(&q)){BT* front = QuequeFront(&q);//取隊頭元素QuquePop(&q);//刪除隊頭元素if (front == NULL)break;QuquePush(&q, front->left);QuquePush(&q, front->right);}//來到這只能有2種情況:隊列為空  front == NULLwhile (!QuequeEmpty(&q)){//只能是front為空BT* front1 = QuequeFront(&q);//取隊頭元素if(front1)return false;  //非空 說明不是二叉樹QuquePop(&q);}QuqueDestroy(&q);return true;
}
9:二叉樹的查找

查找某個節點的值是否存在,若存在則返回該節點的地址,否則返回NULL

可以用先序來遍歷

?錯誤示例:當我想查找3這個節點時候

?相信有不少老鐵們一開始就會這樣寫吧,但是明明3這個節點存在為什么會沒有找到呢?

其實通過我們調試發現這樣寫的邏輯是有Bug的,及時當要查找的節點存在時,也會造成把已找到的節點覆蓋掉,其實這個查找邏輯的代碼重在對return 返回的考察

正確代碼:
BT* BT_Find(BT* root, BT_DataType x) // 3
{if (root == NULL)return  NULL;if (root->val == x)return root; //先去左子樹查找BT* left = BT_Find(root->left, x);if (left)return left;//說明左子樹不存在,去右子樹查找BT* right = BT_Find(root->right, x);if (right)return right;//來到這說明左右子樹都不存在return NULL;
}

?運行結果:

10.二叉樹相關OJ的練習
10.1 單值二叉樹

?解題分析:

其實一個遍歷就直接搞定了。拿雙親節點的值與孩子節點對應的值進行比較,若是不相等直接 return false

是不是看著比較簡單,但是寫起來是有坑滴

?

?運行結果:

其實走讀一遍代碼大概就找到問題所在了:return 語句返回是返回到調用當前函數的上一個函數里,并不是直接返回到最外層?

這個問題的本質同二叉樹查找指定數據是一樣的

OJ代碼:
bool isUnivalTree(struct TreeNode* root) 
{if(root == NULL)return true;if(root->left){if(root->val != root->left->val)return false;}if(root->right){if(root->val != root->right->val)return false;}//遞歸左子樹bool ret1 = isUnivalTree(root->left);//遞歸右子樹bool ret2=  isUnivalTree(root->right);return ret1 && ret2;
}
10.2 判斷2個二叉樹是否相同

?解題分析:

采用遍歷的方式,根節點與根節點進行對比,左孩子與左孩子對比,右孩子與右孩子對比,注意是對比val而不是對比節點所對應的地址

OJ代碼:
bool isSameTree(struct TreeNode* p, struct TreeNode* q){if(p == NULL &&q == NULL)return true;if(p == NULL || q == NULL)return false;//來到這說明都不為空if(p->val  != q->val)return false;return  isSameTree(p->left,q->left) && isSameTree(p->right,q->right);//注意這里必須是 邏輯且的關系,不能是邏輯或
}

?OK,以上就是我今日要為大家分享的,希望各位都有得!對于二叉樹這部分是數據結構初階比較難的一部分了,初學的時候是不好理解,事事都有個過渡期,當然自己有空的時候也不要忘了敲敲代碼!

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

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

相關文章

蘋果汽車項目的敗局:起步失誤與方向迷茫

蘋果汽車的發展方向內部分歧導致項目多年掙扎&#xff0c;最終在本周宣布終止。 Brian X. Chen 和 Tripp Mickle 從項目初期就開始關注蘋果的汽車項目。 在過去十年中&#xff0c;許多參與蘋果秘密汽車項目“泰坦”&#xff08;內部代號&#xff09;的員工戲稱其為“泰坦尼克…

Python實現鏈表:從基礎到應用

一、引言 鏈表是一種常見的數據結構&#xff0c;它由一系列節點組成&#xff0c;每個節點包含數據和指向下一個節點的指針。鏈表在內存中的存儲不是連續的&#xff0c;這使得它在插入和刪除操作上具有較高的效率。本文將使用Python語言來實現一個簡單的鏈表&#xff0c;并展示其…

【前端面試題1】偽類與偽元素有什么區別

偽類與偽元素的區別&#xff1a; 1.偽類使用單冒號&#xff0c;而偽元素使用雙冒號。如 :hover 是偽類&#xff0c;::before 是偽元素 2.偽元素會在文檔流生成一個新的元素&#xff0c;但偽元素本身并不是DOM元素&#xff0c;并且可以使用 content 屬性設置內容 CSS偽類與偽元…

卷積神經網絡基本概念補充

卷積&#xff08;convolution&#xff09;、通道&#xff08;channel&#xff09; 卷積核大小一般為奇數&#xff0c;有中心像素點&#xff0c;便于定位卷積核。 步長&#xff08;stride&#xff09;、填充&#xff08;padding&#xff09; 卷積核移動的步長&#xff08;stride…

小白提示您:FaceTime詐騙持續高發,小伙伴們謹防詐騙!

前幾天小白的iPhone突然接到了個FaceTime通話請求&#xff0c;說是某抖音賬號需要續費啥的才能解鎖某些功能。&#xff08;具體小白也記不太清了&#xff09; 這幾天也有朋友說有個支付寶客服打FaceTime通話給他說快遞出現了點問題&#xff0c;需要操作認證一下才能退款啥的。…

多線程萬字詳解

進程和線程是計算機程序執行的兩個重要概念。 1.進程&#xff1a; 進程是操作系統分配資源的基本單位&#xff0c;每個進程都有自己獨立的地址空間&#xff0c;每啟動一個進程&#xff0c;系統就會為它分配內存。進程間通信比較復雜&#xff0c;需要用到IPC&#xff08;InterP…

js監聽F11觸發全屏事件

當用戶使用 F11 鍵進行瀏覽器全屏時&#xff0c;由于此時并非通過瀏覽器提供的 Fullscreen API 進入全屏模式&#xff0c;因此無法通過 fullscreenchange 事件來監聽全屏狀態的變化。在這種情況下&#xff0c;可以通過監聽 resize 事件來檢測瀏覽器窗口大小的變化&#xff0c;從…

【學習日記】快速排序

思想 快速排序之所以快&#xff0c;一個重要原因就是其每一次遍歷&#xff0c;都把本輪要排序的數字&#xff08;稱為軸&#xff09;放到了最終的位置上快排使用分治思想&#xff0c;所以一般采用遞歸實現&#xff0c;非遞歸版本可以用棧根據第一點&#xff0c;我們需要一個函…

[滲透教程]-006-滲透測試-Metasploit

文章目錄 1.Metasploit簡介2.配置2.1方法1 推薦2.2方法23.使用4. Metasploitable2-linuxMetasploit攻擊流程攻擊實例步驟會話管理1.Metasploit簡介 Metasploit是一個滲透測試平臺,使您能夠查找,利用和驗證漏洞.是一個免費的可下載的,通過它可以很容易對計算機軟件漏洞實施攻擊.…

AttributeError_ ‘list‘ object has no attribute ‘view‘

問題描述 訓練yolov9的時候遇到了下面的問題。 In loss_tal.py: pred_distri, pred_scores torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( (self.reg_max * 4, self.nc), 1) The error is as follows&#xff1a; AttributeError: list …

JavaWeb之 Web概述

目錄 前言1.1 Web和 JavaWeb的概念1.2 JavaWeb技術棧1.2.1 B/S架構1.2.2 靜態資源1.2.3 動態資源1.2.4 數據庫1.2.5 HTTP協議1.2.6 Web服務器 1.3 JavaWeb 學習內容 前言 博主將用 CSDN 記錄 Java 后端開發學習之路上的經驗&#xff0c;并將自己整理的編程經驗和知識分享出來&a…

【Web自動化測試——代碼篇十二】自動化測試模型——數據驅動測試和關鍵字驅動測試

&#x1f525; 交流討論&#xff1a;歡迎加入我們一起學習&#xff01; &#x1f525; 資源分享&#xff1a;耗時200小時精選的「軟件測試」資料包 &#x1f525; 教程推薦&#xff1a;火遍全網的《軟件測試》教程 &#x1f4e2;歡迎點贊 &#x1f44d; 收藏 ?留言 &#x1…

「優選算法刷題」:刪除字符串中的所有相鄰重復項

一、題目 給出由小寫字母組成的字符串 S&#xff0c;重復項刪除操作會選擇兩個相鄰且相同的字母&#xff0c;并刪除它們。 在 S 上反復執行重復項刪除操作&#xff0c;直到無法繼續刪除。 在完成所有重復項刪除操作后返回最終的字符串。答案保證唯一。 示例&#xff1a; 輸…

理解C#里面的集合有哪些?怎么用,什么是安全集合?

介紹 在C#中&#xff0c;集合是一種用于存儲和操作多個元素的數據結構。它們提供了各種操作&#xff0c;如添加、刪除、查找等&#xff0c;以及遍歷集合中的元素。集合通常根據其實現方式和行為特征進行分類。 集合繼承IEnumerable 在C#中&#xff0c;幾乎所有的集合類型都實現…

簡歷中自我評價,是否應該刪掉?

你好&#xff0c;我是田哥 年后&#xff0c;不少朋友已經開始著手準備面試了&#xff0c;準備面試的第一個問題就是&#xff1a;簡歷。 寫簡歷是需要一些技巧的&#xff0c;你的簡歷是要給面試官看&#xff0c;得多留點心。 很多簡歷上都會寫自我評價/個人優勢/個人總結等&…

2024有哪些免費的mac蘋果電腦深度清理工具?CleanMyMac X

蘋果電腦用戶們&#xff0c;你們是否經常感到你們的Mac變得不再像剛拆封時那樣迅速、流暢&#xff1f;可能是時候對你的蘋果電腦進行一次深度清理了。在這個時刻&#xff0c;擁有一些高效的深度清理工具就顯得尤為重要。今天&#xff0c;我將介紹幾款優秀的蘋果電腦深度清理工具…

一個Web3項目的收官之作,必然是友好的用戶界面(Web3項目三實戰之四)

正如標題所述,一個對用戶體驗友好的應用,總是會贏得用戶大加贊賞,這是毋庸置疑的。 甭管是web2,亦或是已悄然而至的Web3,能有一個外觀優美、用戶體驗效果佳的的界面,那么,這個應用無疑是個成功的案例。 誠然,Web3項目雖然核心是智能合約攥寫,但用戶界面也是一個DApp不…

【Leetcode每日一刷】哈希表|綱領、242.有效的字母異位詞、349. 兩個數組的交集

綱領 &#x1f517;代碼隨想錄理論部分 關于哈希表這個數據結構就不再重復講了&#xff0c;下面對幾個關鍵點記錄一下&#xff1a; 哈希碰撞 解決方法1&#xff1a;拉鏈法 解決方法2&#xff1a;線性探測法 下面針對做題要用到的三種結構講一下&#xff08;也是重復造輪子了…

vue.config.js publicPath 和 vue-router base 結合配置項目根目錄為二級目錄案例

背景: 同個域名下需要有 PC 管理后臺, H5 端, 企業微信 ......等多個端, 需要在一個域名下通過不同的路徑來區分不同的項目; 例如: abc.com/pc, abc.com/h5, abc.com/wx-work.... 此處做個記錄 步驟: 1. 修改 vue.config.js 中的 publicPath module.exports {outputDir:…

MATLAB|【免費】概率神經網絡的分類預測--基于PNN的變壓器故障診斷

目錄 主要內容 部分代碼 結果一覽 下載鏈接 主要內容 ?《MATLAB神經網絡43個案例分析》共有43章&#xff0c;內容涵蓋常見的神經網絡&#xff08;BP、RBF、SOM、Hopfield、Elman、LVQ、Kohonen、GRNN、NARX等&#xff09;以及相關智能算法&#xff08;SVM、決策…