二叉樹講解升級版

目錄

二叉樹的存儲結構

二叉樹結點的查找和修改

二叉樹結點的插入

二叉樹的創建

二叉樹的遍歷

先序遍歷

中序遍歷

后序遍歷

層序遍歷

重建二叉樹

二叉樹的靜態實現

二叉樹的存儲結構

一般來說,二叉樹使用鏈表來定義。和普通鏈表的區別是,由于二叉樹每個結點有兩條出邊,因此指針域變成了兩個---分別指向左子樹的根結點地址和右子樹根節點地址。如果某個子樹不存在,則指向NULL,其他地方和普通鏈表完全相同,因此又把這種鏈表叫做二叉鏈表,其定義如下:

struct node{typename data;node* lchild;node* rchild;
};

由于在二叉樹建樹前根節點不存在,因此其地址一般設為NULL。

node* root=NULL;

而如果需要新建結點(例如往二叉樹中插入結點的時候),就可以使用下面的函數:

//生成一個新結點,v為結點權值
node* newNode(int v){node* Node=new node;Node->data=v;Node->lchild=Node->right=NULL;return Node;
} 

二叉樹的常用操作有以下幾個:二叉樹的建立,二叉樹結點的查找、修改、插入與刪除,其中刪除操作對不同性質的二叉樹區別比較大,這里不做介紹。

二叉樹結點的查找和修改

查找操作是指在給定數據域的條件下,在二叉樹中找到所以數據域為給定數據域的結點,并將它們的數據域修改為給定的數據域。

需要使用遞歸來完成查找修改操作。在這里,遞歸式是指對當前結點的左子樹和右子樹分別進行遞歸,遞歸邊界是當前結點為空時到達死胡同。

void search(node* root,int x,int newdata){if(root==NULL){return;}if(root->data==x){root->data=newdata;}search(root->lchild,x,newdata);search(root->rchild,x,newdata);
}

二叉樹結點的插入

二叉樹結點的插入位置就是數據域在二叉樹中查找失敗的位置。而由于這個位置是確定的,因此在遞歸查找的過程中一定是只根據二叉樹的性質來選擇左子樹或右子樹中的一棵子樹進行遞歸,且最后到達空樹的地方就是查找失敗的地方。

void insert(node* &root,int x){if(root==NULL){root=newNode(x);return;}if(由二叉樹的性質,x應該插在左子樹){insert(root->lchild,x);}else{insert(root->rchild);}
}

二叉樹的創建

二叉樹的創建其實就是二叉樹結點的插入過程,而插入所需要結點的數據域一般都會由題目給出,因此比較常用的寫法是把需要插入的數據存儲在數組中,然后再將它們使用insert函數一個個插入二叉樹中,并最終返回根節點的指針root。

node* Create(int data[],int n){node* root=NULL;for(int i=0;i<n;i++){insert(root,data[i]);}return root;
}

二叉樹的遍歷

先序遍歷

void preorder(node* root){if(root==NULL){return;}printf("%d\n",root->data);preorder(root->lchild);preorder(root->rchild);
}

中序遍歷

void inorder(node* root){if(root==NULL){return;}inorder(root->lchild);printf("%d\n",root->data);inorder(root->rchild);
}

后序遍歷

void postorder(node* root){if(root==NULL){return;}postorder(root->lchild);postorder(root->rchild);printf("%d\n",root->data);
}

層序遍歷

void layerorder(node* root){queue<node*> q;//注意隊列里存地址 q.push(root);while(!q.empty()){node* now=q.front;q.pop();printf("%d",now->data);if(now->lchild!=NULL){q.push(now->lchild);}if(now->rchild!=NULL){q.push(now->rchild);}}
}

在這里使用node*型變量,這樣就可以通過訪問地址去修改原元素,如果使用node型,隊列中保存的只是元素的一個副本,因此如果隊列中直接存放node型,當需要修改隊首元素時,就無法修改

另外還需要指出,如果題目中要求計算出每個結點所處的層次,這時就需要在二叉樹結點的定義中添加一個記錄層次layer的變量:

struct node{int data;int layer;node* lchild;node* rchild;
};

需要在根節點入隊前就先令根節點的layer為1來表示根節點在第一層,之后在now->lchild和now->rchild入隊前,把它們的層號都記為當前結點now的層號加1

void Layerorder(node* root){queue<node*> q;root->layer=1;q.push(root);while(!q.empty()){node* now=q.front();q.pop();printf("%d ",now->data);if(now->lchild!=NULL){now->lchild->layer=now->layer+1;q.push(now->lchild);}if(now->rchild!=NULL){now->rchild->layer=now->layer+1;q.push(now->rchild);}}
}

重建二叉樹

給定一棵二叉樹的先序遍歷序列和中序遍歷序列,重建這棵二叉樹。

根據二叉樹遍歷的性質,先序遍歷的第一個結點為二叉樹的根節點,中序遍歷的序列可以根據二叉樹的根節點將中序遍歷序列劃分為左子樹和右子樹。因此只需要在中序遍歷序列中找到根節點的位置,然后劃分為兩個子樹,然后再兩個子樹中分別遞歸執行上面的操作。

node* create(int prel,int prer,int inl,int inr){if(prel>prer){return NULL;}node* root=new node;root->data=pre[prel];int k;for(k=inl;k<=inr;k++){if(in[k]==pre[prel]){break;}}int numleft=k-inl;root->lchild=create(prel+1,prel+numleft,inl,k-1);root->rchild=create(prel+numleft+1,prer,k+1,inr);return root;
}

另外如果給定了后序序列和中序序列也可以構建一棵二叉樹,做法是一樣的。

例題:給出一棵樹的后序遍歷序列和中序遍歷序列,求這棵二叉樹的層次遍歷序列。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 50;
struct node{int data;node* lchild;node* rchild;
};
int pre[maxn],in[maxn],post[maxn];
int n;
node* create(int postl,int postr,int inl,int inr){if(postl>postr){return NULL;}node* root=new node;root->data=post[postr];int k;for(k=inl;k<=inr;k++){if(in[k]==post[postr]){break;}}int numleft=k-inl;root->lchild=create(postl,postl+numleft-1,inl,k-1);root->rchild=create(postl+numleft,postr-1,k+1,inr);return root;
}
int num=0;
void bfs(node* root){queue<node*> q;q.push(root);while(!q.empty()){node* now=q.front();q.pop();printf("%d",now->data);num++;if(num<n){printf(" ");}if(now->lchild!=NULL){q.push(now->lchild);}if(now->rchild!=NULL){q.push(now->rchild);}}
}
int main(){scanf("%d",&n);for(int i=0;i<n;i++){scanf("%d",&post[i]);}for(int i=0;i<n;i++){scanf("%d",&in[i]);}node* root=create(0,n-1,0,n-1);bfs(root);return 0;
}

二叉樹的靜態實現

可以使用數組來實現上面的操作,采用靜態二叉鏈表,結點的左右指針域使用int型代替,用來表示左右子樹的根節點在數組中的下標。為此需要建立一個大小為結點上限個數的node型數組,所有動態生成的結點都直接使用數組中的結點,所有對指針的操作都改為對數組下標的訪問。于是,結點node的定義變為如下:

struct node{typename data;int lchild;int rchild;
}Node[maxn];

在這樣的定義下,結點的動態生成就可以轉變為如下的靜態指定

int index=0;
int newNode(int v){Node[index].data=v;Node[index].lchild=-1;Node[index].rchild=-1;return index++;
}

下面給出二叉樹的查找、插入、建立的代碼。

void search(int root,int x,int newdata){if(root==-1){return;}if(Node[root].data==x){Node[root].data=newdata;}search(Node[root].lchild,x,newdata);search(Node[root].rchild,x,newdata);
}
void insert(int &root,int x){if(root==-1){root=newNode(x);return;}if(由二叉樹的性質x應該插在左子樹){insert(Node[root].lchild,x);}else{insert(Node[root].rchild,x);}
}
int Create(int data[],int n){int root=-1;for(int i=0;i<n;i++){insert(root,data[i]);}return root;
}

關于二叉樹的先序遍歷、中序遍歷、后序遍歷、層次遍歷也做相應的轉換:

void Layerorder(int root){queue<int> q;q.push(root);while(!q.empty()){int now=q.front();q.pop();printf("%d ",Node[now].data);if(Node[now].lchild!=-1){q.push(Node[now].lchild);}if(Node[now].rchild!=-1){q.push(Node[now].rchild);}}
}

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

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

相關文章

【Java】解決Java報錯:StackOverflowError

文章目錄 引言1. 錯誤詳解2. 常見的出錯場景2.1 無限遞歸2.2 遞歸深度過大2.3 方法調用層次過深 3. 解決方案3.1 優化遞歸算法3.2 尾遞歸優化3.3 增加調用棧大小3.4 檢查遞歸終止條件 4. 預防措施4.1 使用迭代替代遞歸4.2 尾遞歸優化4.3 合理設計遞歸算法4.4 調整JVM參數4.5 定…

b端系統類管理平臺設計前端開發案例

b端系統類管理平臺設計前端開發案例

二叉樹-堆的詳解

一&#xff0c;樹的概念 1&#xff0c;樹的概念 樹是一種非線性的數據結構&#xff0c;它是由n&#xff08;n>0&#xff09;個有限結點組成一個具有層次關系的集合。 把它叫做樹是因為它看起來像一棵倒掛的樹&#xff0c;也就是說它是根朝上&#xff0c;而葉朝下的。 有…

vue3 + echarts 二次開發百分比餅圖

效果圖&#xff1a; 安裝 pnpm i echarts 公共模塊組件 <divclass"pie"ref"percent"style"width: 100%; height: calc(100% - 48px)"></div> import { ref, onMounted } from vue import * as echarts from echarts const prop…

【JavaScript腳本宇宙】解密前端工具:選擇最佳JavaScript模塊管理工具

精選前端工具匯總&#xff1a;打包器和捆綁器的完整指南 前言 在現代Web開發中&#xff0c;使用適當的工具和庫可以極大地提高開發效率和項目質量。本文將介紹一些常用的Web應用程序捆綁器&#xff0c;這些工具能夠幫助開發人員有效地管理JavaScript模塊和資源。 歡迎訂閱專欄…

SpringBoot項目啟動提示端口號占用

Windows環境下&#xff0c;SpringBoot項目啟動時報端口號占用&#xff1a; *************************** APPLICATION FAILED TO START ***************************Description:Web server failed to start. Port 8080 was already in use.Action:Identify and stop the proc…

【樂吾樂3D可視化組態編輯器】狀態告警示例

狀態告警的設置方法為兩種&#xff1a; 1.通過數據點號設置&#xff08;推薦&#xff09;&#xff1a; 適用于綁定單一數據點號&#xff0c;設置邏輯簡潔&#xff0c;實現簡單邏輯交互 2.通過交互事件監聽數據點號設置&#xff1a; 適用于綁定多個數據點號&#xff0c;實現復…

LLM大模型AI應用的三階技術

第一階 指令工程&#xff08;Prompt Enginner&#xff09; 設計提示&#xff08;Prompt Design&#xff09; 結果優化&#xff08;Response Optimization&#xff09; 交互設計&#xff08;Interaction Design&#xff09; 模型理解&#xff08;Model Understanding&#…

哈希經典題目(C++)

文章目錄 前言一、兩數之和1.題目解析2.算法原理3.代碼編寫 二、判定是否互為字符重排1.題目解析2.算法原理3.代碼編寫 三、 字?異位詞分組1.題目解析2.算法原理3.代碼編寫 總結 前言 哈希表是一個存儲數據的容器&#xff0c;我們如果想要快速查找某個元素&#xff0c;就可以…

Python驅動下的AI革命:技術賦能與案例解析

在當今這個信息化、數據化的時代&#xff0c;人工智能&#xff08;AI&#xff09;已經成為推動社會發展的重要力量。而Python&#xff0c;作為一種簡單易學、功能強大的編程語言&#xff0c;在AI領域的應用中發揮著至關重要的作用。本文將探討Python在AI領域的應用、其背后的技…

MMUNet:形態學特征增強網絡在結腸癌病理圖像分割中的應用

MMUNet: Morphological feature enhancement network for colon cancer segmentation in pathological images. 發表在&#xff1a;Biomedical Signal Processing and Control2024--影響因子&#xff1a;3.137 南華大學的論文 論文地址&#xff1a;main.pdf (sciencedirecta…

Wakeup Source框架設計與實現

Wakeup Source 為系統組件提供了投票機制&#xff0c;以便低功耗子系統判斷當前是否可以進入休眠。 Wakeup Source(后簡稱&#xff1a;WS) 模塊可與內核中的其他模塊或者上層服務交互&#xff0c;并最終體現在對睡眠鎖的控制上。 1. 模塊功能說明 WS的處理邏輯基本上是圍繞 com…

后端進階-分庫分表

文章目錄 為什么需要分庫為什么需要分表 什么時候需要分庫分表只需要分庫只需要分表 分庫分表解決方案垂直分庫水平分庫垂直分表水平分表 分庫分表常用算法范圍算法hash分片查表分片 分庫分表模式客戶端模式代理模式 今天跟著訓練營學習了分庫分表&#xff0c;整理了學習筆記。…

機器學習模型進行預測和回測

這段代碼是為了并行地處理多個 CSV 文件&#xff0c;并使用機器學習模型進行預測和回測。主要涉及以下步驟&#xff1a; 初始化環境與設置&#xff1a; 引入必要的庫&#xff0c;如 ray 用于并行計算&#xff0c;pandas 用于數據處理&#xff0c;tqdm 用于進度條顯示等。設置一…

golang 不用sleep如何實現實現每隔指定時間執行一次for循環?

今天介紹的是在go語言里面不用time.Sleep&#xff0c; 使用for range 定時器管道 來實現按照我們指定的時間間隔來執行for循環, 即&#xff1a; for range ticker.C { } 這樣就實現了for每隔指定時間執行一次&#xff0c;除非管道被關閉&#xff0c;否則for而且會一直柱塞當前線…

淺說線性DP(下)

聲明 最近博主身體不適&#xff0c;更新較慢&#xff0c;請大家體諒體諒 最大上升子序列 【題目描述】 一個數的序列 你的任務&#xff0c;就是對于給定的序列&#xff0c;求出最大上升子序列和。注意&#xff0c;最長的上升子序列的和不一定是最大的&#xff0c;比如序列(1…

03-3.3.1 棧在括號匹配中的應用

&#x1f44b; Hi, I’m Beast Cheng&#x1f440; I’m interested in photography, hiking, landscape…&#x1f331; I’m currently learning python, javascript, kotlin…&#x1f4eb; How to reach me --> 458290771qq.com 喜歡《數據結構》部分筆記的小伙伴可以訂…

echarts的使用

一 echarts的使用 引入 echarts.js 文件 <script src"https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script> 準備一個呈現圖表的盒子 <div class"container"><div class"t_header"><span>端午…

東方博宜1760 - 整理抽屜

題目描述 期末考試即將來臨&#xff0c;小T由于同時肩負了學習、競賽、班團活動等多方面的任務&#xff0c;一直沒有時間好好整理他的課桌抽屜&#xff0c;為了更好地復習&#xff0c;小T首先要把課桌抽屜里的書分類整理好。 小T的抽屜里堆著 N 本書&#xff0c;每本書的封面上…

智能視頻監控平臺LntonCVS視頻融合共享平臺保障露營安全解決方案

在當今社會&#xff0c;都市生活的快節奏和壓力使得越來越多的人渴望逃離城市的喧囂&#xff0c;尋求一種短暫的慢生活體驗。他們向往在壯麗的山河之間或寧靜的鄉村中露營&#xff0c;享受大自然的寧靜與美好。隨著露營活動的普及&#xff0c;露營地的場景也變得更加豐富多樣&a…