通俗易懂講解C語(yǔ)言與Java中二叉樹的三種非遞歸遍歷方式
詳解二叉樹的三種非遞歸遍歷方式(附C、java源碼)
前言
二叉樹的遞歸遍歷方式很簡(jiǎn)單,三種遞歸遍歷方式的區(qū)別,只是printf放的位置不一樣而已,這里就不多講了。把前序遍歷代碼貼在這里:
//結(jié)點(diǎn)
struct Node
{
int val;
struct Node* left, * right;
};
//前序遍歷
void pre(Node* root)
{
if (root == null)
return;
printf("%d ",root->val);
pre(root->left);
pre(root->right);
}
前序、中序和后序這三種非遞歸的遍歷方式,中序是最為簡(jiǎn)單的,其次是前序,再者就是后序,只是個(gè)人感覺??赡苊總€(gè)人感覺都不一樣吧。
一、非遞歸中序遍歷
中序遍歷順序: 左子樹->頭結(jié)點(diǎn)->右子樹。
如圖—出自于《大話數(shù)據(jù)結(jié)構(gòu)》

所以我們首先需要考慮的是將左手邊(左子樹)的結(jié)點(diǎn)壓入棧,當(dāng)?shù)竭_(dá)底部時(shí)(NULL),我們就輸出此時(shí)棧頂?shù)脑亍?/p>
然后轉(zhuǎn)而去添加當(dāng)前結(jié)點(diǎn)的右手邊(右子樹)的結(jié)點(diǎn)到棧里。
#define MAXSIZE 20 //整棵樹最大的結(jié)點(diǎn)數(shù),用于開辟數(shù)組當(dāng)棧使用
typedef struct Node Node;
void in(Node* root)
{
Node* stack[MAXSIZE] = { 0 };
int size = 0; //用于指向arr數(shù)組,也是用于表示這個(gè)數(shù)組還有幾個(gè)元素
while (size != 0 || root != NULL)
{
if (root != NULL)
{
stack[size++] = root;
root = root->left; //繼續(xù)往左子樹走
}
else
{
//此時(shí)root為NULL,說(shuō)明來(lái)到了左子樹的最底部,此時(shí)輸出棧頂元素,root往右子樹走即可
printf("%c ", stack[--size]->val);
root = stack[size]->right;
}
}
}
二、非遞歸前序遍歷
前序遍歷順序: 頭結(jié)點(diǎn)->左子樹-> 右子樹
我記得我在B站學(xué)算法的時(shí)候,聽左程云老師所說(shuō),一些的遞歸行為,都可以自己用棧來(lái)實(shí)現(xiàn)。
確實(shí),三種非遞歸的遍歷方式實(shí)則也是需要自己實(shí)現(xiàn)棧的功能。接下來(lái)的前序遍歷方式,要用到寬度優(yōu)先遍歷的思想,如圖:
圖片出自《大話數(shù)據(jù)結(jié)構(gòu)》


先加入第一層的全部數(shù)據(jù),然后在棧中使用第一層數(shù)據(jù)的同時(shí),判斷加入第二層的全部數(shù)據(jù),第三層的也是一樣…
#define MAXSIZE 20 //整棵樹最大的結(jié)點(diǎn)數(shù),用于開辟數(shù)組當(dāng)棧使用
typedef struct Node Node;
void pre(Node* root)
{
if (root == NULL)
return;
Node* stack[MAXSIZE] = { 0 }; //模擬棧
int size = 0; //代表此時(shí)棧有多少元素
arr[size++] = root;
while (size != 0)
{
Node* node = stack[--size];
printf("%c ", node->val);
//先壓入右孩子,再壓入左孩子。這樣在彈出的時(shí)候才是 先彈出左孩子 然后才是右孩子
//頭 左 右
if (node->right != NULL)
stack[size++] = node->right;
if (node->left != NULL)
stack[size++] = node->left;
}
}
三、非遞歸后序遍歷
在講解了非遞歸的前序遍歷,其實(shí)我們?cè)谇靶虮闅v的基礎(chǔ)之上改一下就能完成后序遍歷。我們?cè)趯⑶靶虮闅v時(shí),在while循環(huán)里,加入左右孩子結(jié)點(diǎn)時(shí),先加入棧的是右孩子,然后才是左孩子,只有這樣,我們彈出來(lái)的順序才是先左后右。
現(xiàn)在我們只需要改一下加入左右孩子的順序時(shí),我們先壓入棧是左孩子,然后再壓入右孩子。 這樣彈出來(lái)就是先右再左的順序。那此時(shí)再加上頭結(jié)點(diǎn),那就是 頭結(jié)點(diǎn)->右孩子->左孩子 。 此時(shí)我們從后面往前面讀,就是 左孩子 -> 右孩子 ->頭結(jié)點(diǎn)。這樣就變成了后序遍歷了。。。
圖片出自《大話數(shù)據(jù)結(jié)構(gòu)》

#define MAXSIZE 20 //整棵樹最大的結(jié)點(diǎn)數(shù),用于開辟數(shù)組當(dāng)棧使用
typedef struct Node Node;
void postorder(Node* root)
{
if (root == NULL)
return;
Node* stack1[MAXSIZE] = { 0 }; //主要棧
Node* stack2[MAXSIZE] = { 0 }; //輔助棧
int size1 = 0; //主要棧:代表數(shù)組的元素個(gè)數(shù)
int size2 = 0; //輔助棧: 代表數(shù)組的元素個(gè)數(shù)
stack1[size1++] = root;
while (size1 != 0)
{
Node* node = stack1[--size1];
stack2[size2++] = node; //暫時(shí)存入輔助棧
//先壓入左孩子,再壓入右孩子
if (node->left != NULL)
stack1[size1++] = node->left;
if (node->right != NULL)
stack1[size1++] = node->right;
}
//倒著輸出輔助棧的數(shù)據(jù)即可
while (size2-- != 0)
printf("%c ", stack2[size2]->val);
}
非遞歸與遞歸方式的遍歷,有些相似之處,總結(jié)兩種不同的方法,就能更深刻的理解這些方法。最后,C/C++的同學(xué),記得回收malloc開辟的空間哦!??!
下期見啦?。?!
到此這篇關(guān)于通俗易懂講解C語(yǔ)言中二叉樹的三種非遞歸遍歷方式的文章就介紹到這了,更多相關(guān)C 二叉樹非遞歸遍歷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vs2019+win10配置boost庫(kù)的詳細(xì)教程
這篇文章主要介紹了vs2019+win10配置boost庫(kù),本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
總結(jié)UNIX/LINUX下C++程序計(jì)時(shí)的方法
本文總結(jié)了下UNIX/LINUX下C++程序計(jì)時(shí)的一些函數(shù)和方法,對(duì)日常使用C++程序的朋友很有幫助,有需要的小伙伴們可以參考學(xué)習(xí),下面一起來(lái)看看吧。2016-08-08
Linux下semop等待信號(hào)時(shí)出現(xiàn)Interrupted System Call錯(cuò)誤(EINTR)解決方法
本篇文章是對(duì)在Linux下semop等待信號(hào)時(shí)出現(xiàn)Interrupted System Call錯(cuò)誤(EINTR)的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C/C++ Qt 數(shù)據(jù)庫(kù)與Chart歷史數(shù)據(jù)展示
這篇文章主要介紹了Qt利用Qchart組件展示數(shù)據(jù)庫(kù)中的歷史數(shù)據(jù)。文中的示例代碼講解清晰,具有一定的學(xué)習(xí)和工作價(jià)值,感興趣的小伙伴可以學(xué)習(xí)一下2021-12-12
LeetCode題解C++生成每種字符都是奇數(shù)個(gè)的字符串
這篇文章主要為大家介紹了LeetCode題解C++生成每種字符都是奇數(shù)個(gè)的字符串示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10

