在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

4中二叉樹的遍歷方式介紹

lviY_AI_shequ ? 來源:未知 ? 作者:胡薇 ? 2018-04-27 17:23 ? 次閱讀

對于一種數據結構而言,遍歷是常見操作。二叉樹是一種基本的數據結構,是一種每個節點的兒子數目都不多于2的樹。二叉樹的節點聲明如下:

typedef struct TreeNode *PtrToNode;

typedef struct TreeNode *BinTree;

struct TreeNode

{

int Data; //為簡單起見,不妨假設樹節點的元素為int型

BinTree Left;

BinTree Right;

};

二叉樹的遍歷主要有先序遍歷,中序遍歷,后序遍歷,層序遍歷四種方式,下面一一介紹。

1. 先序遍歷

在先序遍歷中,對節點的訪問工作是在它的左右兒子被訪問之前進行的。換言之,先序遍歷訪問節點的順序是根節點-左兒子-右兒子。由于樹可以通過遞歸來定義,所以樹的常見操作用遞歸實現常常是方便清晰的。遞歸實現的代碼如下:

void PreOrderTraversal(BinTree BT)

{

if( BT )

{

printf(“%d\n”, BT->Data); //對節點做些訪問比如打印

PreOrderTraversal(BT->Left); //訪問左兒子

PreOrderTraversal(BT->Right); //訪問右兒子

}

}

由遞歸代碼可以看出,該遞歸為尾遞歸(尾遞歸即遞歸形式在函數末尾或者說在函數即將返回前)。尾遞歸的遞歸調用需要用棧存儲調用的信息,當數據規模較大時容易越出棧空間。雖然現在大部分的編譯器能夠自動去除尾遞歸,但是即使如此,我們不妨自己去除。非遞歸先序遍歷算法基本思路:使用堆棧

a. 遇到一個節點,訪問它,然后把它壓棧,并去遍歷它的左子樹;

b. 當左子樹遍歷結束后,從棧頂彈出該節點并將其指向右兒子,繼續a步驟;

c. 當所有節點訪問完即最后訪問的樹節點為空且棧空時,停止。

實現代碼如下:

void PreOrderTraversal(BinTree BT)

{

BinTree T = BT;

Stack S = CreatStack(MAX_SIZE); //創建并初始化堆棧S

while(T || !IsEmpty(S))

{

while(T) //一直向左并將沿途節點訪問(打印)后壓入堆棧

{

printf("%d\n", T->Data);

Push(S, T);

T = T->Left;

}

if (!IsEmpty(S))

{

T = Pop(S); //節點彈出堆棧

T = T->Right; //轉向右子樹

}

}

}

2. 中序遍歷

中序遍歷的遍歷路徑與先序遍歷完全一樣。其實現的思路也與先序遍歷非常相似。其主要的不同點是訪問節點順序不同:中序遍歷是訪問完所有左兒子后再訪問根節點,最后訪問右兒子,即為左兒子-根節點-右兒子。

遞歸實現的代碼如下:

void InOrderTraversal(BinTree BT)

{

if(BT)

{

InOrderTraversal(BT->Left);

printf("%d\n", BT->Data);

InOrderTraversal(BT->Right);

}

}

非遞歸輔助棧實現代碼如下:

void InOrderTraversal(BinTree BT)

{

BinTree T = BT;

Stack S = CreatStack(MaxSize); //創建并初始化堆棧S

while(T || !IsEmpty(S))

{

while(T) //一直向左并將沿途節點壓入堆棧

{

Push(S,T);

T = T->Left;

}

if(!IsEmpty(S))

{

T = Pop(S); //節點彈出堆棧

printf("%d\n", T->Data); //(訪問) 打印結點

T = T->Right; //轉向右子樹

}

}

}

非遞歸不用輔助棧實現中序遍歷:

試設計一個非遞歸算法,按中根順序遍歷非線索二叉樹,但不得用任何輔助棧。在執行算法期間,允許改變左孩子指針和右孩子指針的值。

算法:右線索化+回溯

若當前樹的根節點p有左孩子且未被線索化:將其左孩子的最右結點(可為左孩子本身)指向p,即右線索化,然后p = p->lChild;

若p有左孩子但已被線索化,說明該p是回溯上來的,即左孩子已經被訪問了,則釋放線索化的指針;

若p無左孩子,打印p,向上回溯(即p = p->rChild)。

代碼如下:

/*

輸入:ABDH##I##E##CF#J##G##

*/

#include

typedef struct BTNode* Position;

typedef Position BTree;

typedef char ElementType;

struct BTNode {

ElementType data;

Position lChild, rChild;

};

BTree CreateBTree(void);

void Inorder(BTree bt);

int main()

{

BTree bt = CreateBTree();

Inorder(bt);

return 0;

}

void Inorder(BTree bt)

{

Position p = bt;

while (p)

{

Position pLeft = p->lChild;

if (pLeft)

{

while (pLeft->rChild && pLeft->rChild != p) //找到以p為根結點的樹的最右孩子

pLeft = pLeft->rChild;

if (pLeft->rChild == NULL) //線索化

{

pLeft->rChild = p;

p = p->lChild;

continue;

}

else //線索化后已被訪問

{

pLeft->rChild = NULL; //釋放指向根節點(祖先)的指針

}

}

printf("%c ", p->data); //打印

p = p->rChild; //向上回溯或者轉向右子樹

}

printf("\n");

}

BTree CreateBTree() //按照先序序列建立二叉樹

{

BTree bt = NULL;

char ch;

scanf("%c", &ch);

if (ch != '#') //'#'代表空節點

{

bt = new BTNode;

bt->data = ch;

bt->lChild = CreateBTree();

bt->rChild = CreateBTree();

}

return bt;

}

運行結果:

參考博客:http://m.blog.csdn.net/blog/Raito__/40618257

3. 后序遍歷

后序遍歷與中序遍歷,先序遍歷的路徑也完全一樣。主要的不同點是后序遍歷訪問節點的順序是先訪問左兒子和右兒子,最后訪問節點,即左兒子-右兒子-根節點。

遞歸實現思路與中序遍歷和先序遍歷相似,代碼如下:

void PostOrderTraversal(BinTree BT)

{

if (BT)

{

PostOrderTraversal(BT->Left);

PostOrderTraversal(BT->Right);

printf("%d\n", BT->Data);

}

}

后序遍歷的非遞歸實現

思路一:

對于一個節點而言,要實現訪問順序為左兒子-右兒子-根節點,可以利用后進先出的棧,在節點不為空的前提下,依次將根節點,右兒子,左兒子壓棧。故我們需要按照根節點-右兒子-左兒子的順序遍歷樹,而我們已經知道先序遍歷的順序是根節點-左兒子-右兒子,故只需將先序遍歷的左右調換并把訪問方式打印改為壓入另一個棧即可。最后一起打印棧中的元素。代碼如下:

void PostOrderTraversal(BinTree BT)

{

BinTree T = BT;

Stack S1 = CreatStack(MAX_SIZE); //創建并初始化堆棧S1

Stack S2 = CreatStack(MAX_SIZE); //創建并初始化堆棧S2

while(T || !IsEmpty(S1))

{

while(T) //一直向右并將沿途節點訪問(壓入S2)后壓入堆棧S1

{

Push(S2, T);

Push(S1, T);

T = T->Right;

}

if (!IsEmpty(S1))

{

T = Pop(S1); //節點彈出堆棧

T = T->Left; //轉向左子樹

}

}

while(!IsEmpty(S2)) //訪問(打印)S2中元素

{

T = Pop(S2);

printf("%d\n", T->Data);

}

}

思路一的優點是由于利用了先序遍歷的思想,代碼較簡潔,思路較清晰。缺點是需要用一個棧來存儲樹的所有節點,空間占用較大。

思路二:

要訪問一個節點的條件上一個訪問的節點是右兒子。我們可以增加一個變量Prev來判斷當前節點Curr的上一個節點與它的關系來執行相應的操作。

若Prev為空(Curr節點是根節點)或者Prev是Curr的父節點,將Curr節點的左孩子和右孩子分別壓入棧;

若Prev是Curr的左兒子,則將Curr的右兒子壓入棧;

否則Prev是Curr的右兒子,訪問Curr;

代碼如下:

void PostOrderTraversal(BinTree BT)

{

if(BT == NULL)

return ;

Stack S = CreatStack(MAX_SIZE);

BinTree Prev = NULL , Curr = NULL; //初始化

s.push(BT);

while(!IsEmpty(S))

{

Curr = Top(S); //將棧頂元素賦給Curr

if(Prev == NULL || Prev->Left == Curr || Prev->Right == Curr) //若Prev為NULL或是Curr的父節點

{

if(Curr->Left != NULL)

Push(S, Curr->Left);

else if(Curr->Right != NULL)

Push(S, Curr->Right);

}

else if(Curr->Left == Prev) //若Prev是Curr的左兒子

{

if(Curr->Right != NULL)

Push(S, Curr->Right);

}

else

{

printf("%d\n", Curr->Data); //訪問當前節點

Pop(S); //訪問后彈出

}

Prev = Curr; //處理完當前節點后將Curr節點變為Prev節點

}

}

4. 層序遍歷

二叉樹遍歷的核心問題是二維結構的線性化。我們通過節點訪問其左右兒子時,存在的問題是訪問左兒子后,右兒子怎么訪問。因此我們需要一個存儲結構保存暫時不訪問的節點。前面三種遍歷方式的非遞歸實現,我們是通過堆棧來保存。事實上也可以通過隊列來保存。

隊列實現的基本思路:遍歷從根節點開始,首先將根節點入隊,然后執行循環:節點出隊,訪問(訪問)根節點,將左兒子入隊,將右兒子入隊,直到隊列為空停止。

這種遍歷方式的結果是將二叉樹從上到下,從左至右一層一層的遍歷,即層序遍歷,代碼實現如下:

void LevelOrderTraversal(BinTree BT)

{

BinTree T;

Queue Q; //聲明一個隊列

if (BT == NULL)

return; //如果樹為空,直接返回

Q = CreatQueue(MAX_SIZE); //創建并初始化隊列

AddQ(Q, BT); //將根節點入隊

while (!IsEmpty(Q))

{

T = DeleteQ(Q); //節點出隊

printf("%d\n", T->Data); //訪問出隊的節點

if (T->Left) AddQ(Q, T->Left); //若左兒子不為空,將其入隊

if (T->Right) AddQ(Q, T->Right) //若右兒子不為空,將其入隊

}

}

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 節點
    +關注

    關注

    0

    文章

    220

    瀏覽量

    24527
  • 二叉樹
    +關注

    關注

    0

    文章

    74

    瀏覽量

    12375

原文標題:二叉樹的遍歷:先序中序后序遍歷的遞歸與非遞歸實現及層序遍歷

文章出處:【微信號:AI_shequ,微信公眾號:人工智能愛好者社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    基于二叉樹的時序電路測試序列設計

    為了實現時序電路狀態驗證和故障檢測,需要事先設計一個輸入測試序列。基于二叉樹節點和樹枝的特性,建立時序電路狀態二叉樹,按照電路二叉樹節點(狀態)與樹枝(輸入)的層次邏輯
    發表于 07-12 13:57 ?0次下載
    基于<b class='flag-5'>二叉樹</b>的時序電路測試序列設計

    二叉樹層次遍歷算法的驗證

    實現二叉樹的層次遍歷算法,并對用”A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”創建的二叉樹進行測試。
    發表于 11-28 01:05 ?2119次閱讀
    <b class='flag-5'>二叉樹</b>層次<b class='flag-5'>遍歷</b>算法的驗證

    詳解電源二叉樹到底是什么

    作為數據結構的基礎,分很多種,像 AVL 、紅黑二叉搜索....今天我想分享的是關于二叉樹
    的頭像 發表于 06-06 15:05 ?1w次閱讀
    詳解電源<b class='flag-5'>二叉樹</b>到底是什么

    C語言二叉樹代碼免費下載

    本文檔的主要內容詳細介紹的是C語言二叉樹代碼免費下載。
    發表于 08-27 08:00 ?1次下載

    面試算法之重建二叉樹

    那么問題來了,只知道前序遍歷能不能反推二叉樹呢?我們就試一下,比如題目中所述,{1,2,4,7,3,5,6,8},根據前序遍歷,根、左、右,1 肯定是 根節點,那么一下2,
    的頭像 發表于 11-27 15:59 ?2594次閱讀

    面試二叉樹看這11個就夠了

    根據前、遍歷的特點,(根左右、左根右),先根據前序遍歷確定根節點,然后在遍歷知道該根節點的左右
    的頭像 發表于 11-27 16:25 ?3365次閱讀

    二叉樹操作的相關知識和代碼詳解

    見的二叉樹操作作個總結: 前序遍歷遍歷,后序遍歷; 層次遍歷; 求
    的頭像 發表于 12-12 11:04 ?2089次閱讀
    <b class='flag-5'>二叉樹</b>操作的相關知識和代碼詳解

    二叉樹的前序遍歷非遞歸實現

    我們之前說了二叉樹基礎及二叉的幾種遍歷方式及練習題,今天我們來看一下二叉樹的前序遍歷非遞歸實現。
    的頭像 發表于 05-28 13:59 ?2000次閱讀

    C語言數據結構:什么是二叉樹

    完全二叉樹:完全二叉樹是效率很高的數據結構。對于深度為K,有n個節點的二叉樹,當且僅當每一個節點都與深度為K的滿二叉樹編號從1至n的節點一
    的頭像 發表于 04-21 16:20 ?2699次閱讀

    怎么就能構造成二叉樹呢?

    一直跟著公眾號學算法的錄友 應該知道,我在二叉樹:構造二叉樹登場!,已經講過,只有 序與后序 和 序和前序 可以確定一顆唯一的二叉樹
    的頭像 發表于 07-14 11:20 ?1655次閱讀

    二叉樹的最大深度

    精簡之后的代碼根本看不出是哪種遍歷方式,也看不出遞歸三部曲的步驟,所以如果對二叉樹的操作還不熟練,盡量不要直接照著精簡代碼來學。
    的頭像 發表于 07-26 11:28 ?1137次閱讀

    使用C語言代碼實現平衡二叉樹

    這篇博客主要總結平衡二叉樹,所以,二叉排序樹知識不會提及,但是會用到。
    的頭像 發表于 09-21 11:00 ?1154次閱讀

    二叉樹的代碼實現

    二叉樹的主要操作有遍歷,例如有先序遍歷遍歷、后序遍歷。在
    的頭像 發表于 01-18 10:41 ?1277次閱讀
    <b class='flag-5'>二叉樹</b>的代碼實現

    C++自定義二叉樹并輸出二叉樹圖形

    使用C++構建一個二叉樹并輸出。
    的頭像 發表于 01-10 16:29 ?1810次閱讀
    C++自定義<b class='flag-5'>二叉樹</b>并輸出<b class='flag-5'>二叉樹</b>圖形

    解析LeetCode第226號題目:反轉二叉樹

    *簡單講就是把每個節點的左子樹和右子樹進行交換** 。 顯然,這需要我們能夠遍歷二叉樹。 那么遍歷二叉樹就有兩種經典的解法:深度優先
    的頭像 發表于 02-17 14:52 ?898次閱讀
    解析LeetCode第226號題目:反轉<b class='flag-5'>二叉樹</b>
    主站蜘蛛池模板: 欧美一级免费片 | 午夜视频h | 91三级在线 | 午夜免费看片 | 色屁屁www影院免费观看视频 | 激情.com| 性夜影院爽黄a爽在线看香蕉 | 午夜影院黄 | 日日夜夜操天天干 | 黄色成人免费网站 | 理论片免费午夜 | 不卡视频一区二区三区 | 五月天丁香激情 | 直接在线观看的三级网址 | 欧美色综合高清视频在线 | 日本啪啪小视频 | 美女性爽视频国产免费 | 欧美爽爽爽爽爽爽视频 | 色综合激情| 天天色视频 | 色五月在线视频 | cijilu刺激 国产免费的 | 伊人精品视频在线 | 伊人成人在线 | 欧美一级特黄aaaaaa在线看片 | 欧美性f | 校园 春色 欧美 另类 小说 | 国产成人精品一区二区仙踪林 | 亚洲欧洲一区二区三区在线 | 久青草视频免费视频播放线路1 | 亚洲成人免费在线 | 超级乱淫视频播放日韩 | 黄色免费在线视频 | 国产成人精品亚洲日本在线 | 奇米影视四色7777 | www射射一区 | 一级无毛片 | 狼色影院 | 天天做人人爱夜夜爽2020毛片 | a天堂影院 | xx综合网|