日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

全面剖析【二叉树】的各类遍历方法

發(fā)布時(shí)間:2025/3/20 编程问答 11 豆豆
生活随笔 收集整理的這篇文章主要介紹了 全面剖析【二叉树】的各类遍历方法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

二叉樹(shù)遍歷

二叉樹(shù)的遍歷主要有四種:

前序、中序、后序和層序

遍歷的實(shí)現(xiàn)方式主要是:

遞歸和非遞歸

遞歸遍歷的實(shí)現(xiàn)非常容易,非遞歸的實(shí)現(xiàn)需要用到棧,難度系數(shù)要高一點(diǎn)。

1.二叉樹(shù)節(jié)點(diǎn)的定義

二叉樹(shù)的每個(gè)節(jié)點(diǎn)由節(jié)點(diǎn)值、左子樹(shù)和右子樹(shù)組成。

class TreeNode{ public:int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(NULL), right(NULL) {} }

2.二叉樹(shù)的遍歷方式

前序遍歷:先訪問(wèn)根節(jié)點(diǎn),再訪問(wèn)左子樹(shù),最后訪問(wèn)右子樹(shù)

中序遍歷:先訪問(wèn)左子樹(shù),再訪問(wèn)根節(jié)點(diǎn),最后訪問(wèn)右子樹(shù)

后序遍歷:先訪問(wèn)左子樹(shù),再訪問(wèn)右子樹(shù),最后訪問(wèn)根節(jié)點(diǎn)

層序遍歷:每一層從左到右訪問(wèn)每一個(gè)節(jié)點(diǎn)。

舉例說(shuō)明:(以下面的二叉樹(shù)來(lái)說(shuō)明這四種遍歷)

前序遍歷:ABDFGHIEC
中序遍歷:FDHGIBEAC
后序遍歷:FHIGDEBCA
層序遍歷:ABCDEFGHI

3.前序遍歷

遞歸版本

按照遍歷的
順序很容易就能寫(xiě)出下列代碼:

以下代碼均在leetcode測(cè)試通過(guò),二叉樹(shù)前序遍歷的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

vector<int> preorderTraversal(TreeNode* root){vector<int> ret;dfsPreOrder(root,ret);return ret; } void dfsPreOrder(TreeNode* root,vector<int> &ret){if(root==NULL) return;ret.push_back(root->val);//存儲(chǔ)根節(jié)點(diǎn)if(root->left!=NULL) dfsPreOrder(root->left,ret);//訪問(wèn)左子樹(shù)if(root->right!=NULL) dfsPreOrder(root->right,ret);//訪問(wèn)右子樹(shù) }

非遞歸版本

非遞歸版本需要利用輔助棧來(lái)實(shí)現(xiàn)

1.首先把根節(jié)點(diǎn)壓入棧中
2.此時(shí)棧頂元素即為當(dāng)前根節(jié)點(diǎn),彈出并訪問(wèn)即可
3.把當(dāng)前根節(jié)點(diǎn)的右子樹(shù)和左子樹(shù)分別入棧,考慮到棧是先進(jìn)后出,所以必須右子樹(shù)先入棧,左子樹(shù)后入棧
4.重復(fù)2,3步驟,直到棧為空為止

vector<int> preorderTraversal(TreeNode* root) {vector<int> ret;if (root==NULL) return ret;stack<TreeNode*> st;st.push(root);while(!st.empty()){TreeNode* tp = st.top();//取出棧頂元素st.pop();ret.push_back(tp->val);//先訪問(wèn)根節(jié)點(diǎn)if(tp->right!=NULL) st.push(tp->right);//由于棧時(shí)先進(jìn)后出,考慮到訪問(wèn)順序,先將右子樹(shù)壓棧if(tp->left!=NULL) st.push(tp->left);//將左子樹(shù)壓棧}return ret; }

4.中序遍歷

遞歸版本

中序遍歷的訪問(wèn)順序依次是左子樹(shù)->根節(jié)點(diǎn)->右子樹(shù),按照遞歸的思想依次訪問(wèn)即可

以下代碼均在leetcode測(cè)試通過(guò),二叉樹(shù)中序遍歷的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

vector<int> inorderTraversal(TreeNode* root) {vector<int> ret;inorder(root,ret);return ret; } void inorder(TreeNode* p,vector<int>& ret) {if(p==NULL) return;inorder(p->left,ret);//訪問(wèn)左子樹(shù)ret.push_back(p->val);//訪問(wèn)根節(jié)點(diǎn)inorder(p->right,ret);//訪問(wèn)右子樹(shù) }

非遞歸版本

中序遍歷的非遞歸版本比前序稍微復(fù)雜一點(diǎn),除了用到輔助棧之外,還需要一個(gè)指針p指向下一個(gè)待訪問(wèn)的節(jié)點(diǎn)

如果p非空,則將p入棧,p指向p的左子樹(shù)
如果p為空,說(shuō)明此時(shí)左子樹(shù)已經(jīng)訪問(wèn)到盡頭了,彈出當(dāng)前棧頂元素,進(jìn)行訪問(wèn),并把p設(shè)置成p的右子樹(shù)的左子樹(shù),即下一個(gè)待訪問(wèn)的節(jié)點(diǎn)

vector<int> inorderTraversal(TreeNode* root) {vector<int> ret;TreeNode* p = root;stack<TreeNode*> st;while(!st.empty()||p!=NULL){if(p){//p非空,代表還有左子樹(shù),繼續(xù)st.push(p);p=p->left;}else{//如果為空,代表左子樹(shù)已經(jīng)走到盡頭了p = st.top();st.pop();ret.push_back(p->val);//訪問(wèn)棧頂元素if(p->right) {st.push(p->right);//如果存在右子樹(shù),將右子樹(shù)入棧p = p->right->left;//p始終為下一個(gè)待訪問(wèn)的節(jié)點(diǎn)}else p=NULL;}}return ret; }

5.后序遍歷

遞歸版本

遞歸版本還是一樣,按照訪問(wèn)順序來(lái)寫(xiě)代碼即可。

以下代碼均在leetcode測(cè)試通過(guò),二叉樹(shù)后序遍歷的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

vector<int> inorderTraversal(TreeNode* root) {vector<int> ret;inorder(root,ret);return ret;} void inorder(TreeNode* p,vector<int>& ret) {if(p==NULL) return;inorder(p->left,ret);//訪問(wèn)左子樹(shù)inorder(p->right,ret);//訪問(wèn)右子樹(shù)ret.push_back(p->val);//訪問(wèn)根節(jié)點(diǎn) }

非遞歸版本

采用一個(gè)輔助棧和兩個(gè)指針p和r,p代表下一個(gè)需要訪問(wèn)的節(jié)點(diǎn),r代表上一次需要訪問(wèn)的節(jié)點(diǎn)

1、如果p非空,則將p入棧,p指向p的左子樹(shù)

2、如果p為空,代表左子樹(shù)到了盡頭,此時(shí)判斷棧頂元素

如果棧頂元素存在右子樹(shù)且沒(méi)有被訪問(wèn)過(guò)(等于r代表被訪問(wèn)過(guò)),則右子樹(shù)入棧,p指向右子樹(shù)的左子樹(shù)
如果棧頂元素不存在或者已經(jīng)被訪問(wèn)過(guò),則彈出棧頂元素,訪問(wèn),然后p置為null,r記錄上一次訪問(wèn)的節(jié)點(diǎn)p

vector<int> postorderTraversal(TreeNode* root) {vector<int> ret;TreeNode* p = root;stack<TreeNode*> st;TreeNode* r = NULL;while(p||!st.empty()){if(p){st.push(p);p = p -> left;}else{p = st.top();if(p->right&&p->right!=r){p = p->right;st.push(p);p = p->left;}else {p = st.top();st.pop();ret.push_back(p->val);r= p;p = NULL;}}}return ret; }

還有另一種解法,大家可以看看前序遍歷的非遞歸版本,訪問(wèn)順序依次是根節(jié)點(diǎn)->左子樹(shù)->右子樹(shù),如果將壓棧順序改動(dòng)一下,可以很容易得到根節(jié)點(diǎn)->右子樹(shù)->左子樹(shù),觀察這個(gè)順序和后序遍歷左子樹(shù)->右子樹(shù)->根節(jié)點(diǎn)正好反序。

vector<int> postorderTraversal(TreeNode* root) {vector<int> ret;if(root==NULL) return ret;stack<TreeNode*> st;st.push(root);while(!st.empty()){TreeNode* tmp = st.top();ret.push_back(tmp->val);//先訪問(wèn)根節(jié)點(diǎn)st.pop();if(tmp->left!=NULL) st.push(tmp->left);//再訪問(wèn)左子樹(shù)if(tmp->right!=NULL) st.push(tmp->right);//最后訪問(wèn)右子樹(shù)}reverse(ret.begin(),ret.end());//將結(jié)果反序輸出return ret; }

6.層序遍歷

層序遍歷,即按層序從左到右輸出二叉樹(shù)的每個(gè)節(jié)點(diǎn)。如例子中的A(第一層)BC(第二層)DE(第三層)FG(第四層)HI(第五層)

層序遍歷需要借助隊(duì)列queue來(lái)完成,因?yàn)橐獫M足先進(jìn)先去的訪問(wèn)順序。具體思路看代碼:

以下代碼均在leetcode測(cè)試通過(guò),二叉樹(shù)層序遍歷的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> ret;if(root==NULL) return ret;queue<TreeNode*> que;que.push(root);while(!que.empty()){vector<int> temp;queue<TreeNode*> tmpQue;//存儲(chǔ)下一層需要訪問(wèn)的節(jié)點(diǎn)while(!que.empty())//從左到右依次訪問(wèn)本層{TreeNode* tempNode = que.front();que.pop();temp.push_back(tempNode->val);if(tempNode->left!=NULL) tmpQue.push(tempNode->left);//左子樹(shù)壓入隊(duì)列if(tempNode->right!=NULL) tmpQue.push(tempNode->right);//右子樹(shù)壓入隊(duì)列}ret.push_back(temp);que=tmpQue;//訪問(wèn)下一層}return ret; }

7.其他經(jīng)典考題

根據(jù)前序和中序遍歷來(lái)構(gòu)造二叉樹(shù)

前序遍歷的順序是:根節(jié)點(diǎn)->左子樹(shù)->右子樹(shù),中序遍歷的順序時(shí):左子樹(shù)->根節(jié)點(diǎn)->右子樹(shù)。

在前序遍歷中第一個(gè)節(jié)點(diǎn)為根節(jié)點(diǎn),然后去中序遍歷中找到根節(jié)點(diǎn),則其左邊為左子樹(shù),右邊為右子樹(shù)

例如前序遍歷ABC,中序遍歷BAC,在前序遍歷中找到根節(jié)點(diǎn)A,在中序遍歷中A的左邊B為左子樹(shù),右邊C為右子樹(shù)。

然后一次遞歸下去,就可以把整棵數(shù)構(gòu)造出來(lái)了。

以下代碼均在leetcode測(cè)試通過(guò),構(gòu)造二叉樹(shù)的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

typedef vector<int>::iterator vi; TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {if(preorder.empty()||inorder.empty()) return (TreeNode*)NULL;vi preStart = preorder.begin();vi preEnd = preorder.end()-1;vi inStart = inorder.begin();vi inEnd = inorder.end()-1;return constructTree(preStart,preEnd,inStart,inEnd); } TreeNode* constructTree(vi preStart,vi preEnd,vi inStart,vi inEnd) {if(preStart>preEnd||inStart>inEnd) return NULL;//前序遍歷的第一個(gè)節(jié)點(diǎn)為根節(jié)點(diǎn)TreeNode* root = new TreeNode(*preStart);if(preStart==preEnd||inStart==inEnd) return root;vi rootIn = inStart;while(rootIn!=inEnd){//在中序遍歷中找到根節(jié)點(diǎn)if(*rootIn==*preStart) break;else ++rootIn;}root->left = constructTree(preStart+1,preStart+(rootIn-inStart),inStart,rootIn-1);//遞歸構(gòu)造左子樹(shù)root->right = constructTree(preStart+(rootIn-inStart)+1,preEnd,rootIn+1,inEnd);//遞歸構(gòu)造右子樹(shù)return root; }

根據(jù)中序和后序遍歷構(gòu)造二叉樹(shù)

與上面的題目比較相似,后序遍歷中最后一個(gè)節(jié)點(diǎn)為根節(jié)點(diǎn),然后在中序遍歷中找到根節(jié)點(diǎn),左邊為左子樹(shù),右邊為右子樹(shù)。

以下代碼均在leetcode測(cè)試通過(guò),構(gòu)造二叉樹(shù)的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {if(inorder.empty()||postorder.empty()) return NULL;return constructTree(inorder,postorder,0,inorder.size()-1,0,postorder.size()-1); } TreeNode* constructTree(vector<int>& inorder, vector<int>& postorder, int inStart,int inEnd,int postStart,int postEnd) {if(postStart>postEnd||inStart>inEnd) return NULL;TreeNode* root = new TreeNode(postorder[postEnd]);if(postStart==postEnd||inStart==inEnd) return root;int i ;for(i = inStart ;i<inEnd;i++)//在中序遍歷中找到根節(jié)點(diǎn){if(inorder[i]==postorder[postEnd]) break;}root->left = constructTree(inorder,postorder,inStart,i-1,postStart,postStart+i-inStart-1);//遞歸構(gòu)造左子樹(shù)root->right = constructTree(inorder,postorder,i+1,inEnd,postStart+i-inStart,postEnd-1);//遞歸構(gòu)造右子樹(shù)return root; }

求二叉樹(shù)的深度

采用深度優(yōu)先搜索,可以很容易計(jì)算出深度

以下代碼均在leetcode測(cè)試通過(guò),二叉樹(shù)的深度的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

int maxDepth(TreeNode* root) {return DfsTree(root); } int DfsTree(TreeNode* root){if(root==NULL) return 0;int left = DfsTree(root->left);//左子樹(shù)的深度int right = DfsTree(root->right);//右子樹(shù)的深度return left>right?left+1:right+1;//比較左右子樹(shù)的深度,取最大值 }

判斷是否為平衡二叉樹(shù)

利用上面求深度的思想,求出左右子樹(shù)的深度,判斷它們相差是否大于1,如果大于則返回false。

以下代碼均在leetcode測(cè)試通過(guò),判斷平衡二叉樹(shù)的原題鏈接:戳我!leetcode直通車(chē)!上車(chē)?yán)?#xff01;

bool isBalanced(TreeNode* root) {return dfsTree(root)!=-1; } int dfsTree(TreeNode* root) {if(root==NULL) return 0;int left = dfsTree(root->left);//求左子樹(shù)的深度if(left == -1) return -1;//返回-1代表左子樹(shù)不平衡int right = dfsTree(root->right);//求右子樹(shù)的深度if(right== -1) return -1;//返回-1代表右子樹(shù)不平衡if(abs(left-right)>1) return -1;//如果左右子樹(shù)均平衡,則判斷它們是否相差小于等于1return max(left,right)+1;//返回該根節(jié)點(diǎn)樹(shù)的深度 }

原博客地址:http://blog.csdn.net/terence1212/article/details/52182836

總結(jié)

以上是生活随笔為你收集整理的全面剖析【二叉树】的各类遍历方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美熟妇毛茸茸 | 久久密桃 | 成人免费毛片男人用品 | 夜夜躁狠狠躁 | 一级成人免费视频 | 四虎影视永久免费观看 | 搡老岳熟女国产熟妇 | 欧美男人又粗又长又大 | 在线不卡日韩 | 国产成人精品一区二 | 69网站在线观看 | 华人色| 午夜在线一区二区三区 | 91直接看| 亚洲理论视频 | 91精品国产精品 | 日韩欧美三级在线 | 国产精品夜夜爽张柏芝 | 美女涩涩视频 | 国产视频在线一区二区 | 日韩五码在线 | 国产激情在线 | 中文字幕中文在线 | 婷婷伊人网 | 黄色性视频 | 黑人巨大精品欧美黑白配亚洲 | 一区二区三区国产av | 久草青青草| 欧美熟妇精品一区二区蜜桃视频 | 在线黄色大片 | a在线视频| 亚洲美女一级片 | 91嫩草欧美久久久九九九 | 男男全肉变态重口高h | 美国做爰xxxⅹ性视频 | 国产欧美一区二区三区国产幕精品 | 国产欧美久久久精品免费 | 99国产精品久久久久久久久久久 | 亚洲精品一区二区三区在线 | 午夜精品久久久久久久99黑人 | 一卡二卡三卡在线观看 | 亚洲AV无码精品久久一区二区 | 影音先锋男人站 | 成人免费视频国产在线观看 | 越南黄色一级片 | 风间由美在线视频 | 一级黄色免费观看 | 日本精品一区在线 | 成年人视频在线看 | 黄色一级大片 | 91自啪| 三级视频小说 | 男插女视频网站 | 国产激情在线视频 | 天堂а√在线最新版中文在线 | 久久精品一区二区在线观看 | 男生女生羞羞网站 | 中文亚洲av片在线观看 | 日韩tv| 日韩人妻无码精品久久免费 | 91精品国产自产91精品 | 91九色中文 | 自拍99| 91国自产精品中文字幕亚洲 | 久久色图| 蜜桃臀aⅴ精品一区二区三区 | 欧美日韩不卡一区二区三区 | 日韩中文字幕一区二区 | 91操碰| 精品日本一区二区 | 国产chinesehd天美传媒 | 九热这里只有精品 | 亚洲永久免费av | 波多野结衣中文字幕久久 | 中文字幕激情 | www.亚洲一区二区三区 | 在线视频麻豆 | 成人无遮挡| jizz久久| 亚洲黄色在线播放 | 国产日产精品一区 | 日日射天天操 | 婷婷丁香六月天 | 国产高清小视频 | 99国产精品久久久久久久成人热 | 77777av | 男女视频网站 | 亚洲色图17p | 美女网站在线 | 4438x全国最大成人 | 精东传媒在线 | 亚洲国产精品国自产拍av | 99久久精品国产一区二区成人 | 成人在线视频播放 | 成人在线视频免费看 | 91啪在线| 四房婷婷| 婷婷亚洲五月 | 91毛片网站 |