C 語(yǔ)言二叉樹(shù)幾種遍歷方法詳解及實(shí)例
二叉樹(shù)的一些概念
二叉樹(shù)就是每個(gè)結(jié)點(diǎn)最多有兩個(gè)子樹(shù)的樹(shù)形存儲(chǔ)結(jié)構(gòu)。先上圖,方便后面分析。
1 滿二叉樹(shù)和完全二叉樹(shù)
上圖就是典型的二叉樹(shù),其中左邊的圖還叫做滿二叉樹(shù),右邊是完全二叉樹(shù)。然后我們可以得出結(jié)論,滿二叉樹(shù)一定是完全二叉樹(shù),但是反過(guò)來(lái)就不一定。滿二叉樹(shù)的定義是除了葉子結(jié)點(diǎn),其它結(jié)點(diǎn)左右孩子都有,深度為k的滿二叉樹(shù),結(jié)點(diǎn)數(shù)就是2的k次方減1。完全二叉樹(shù)是每個(gè)結(jié)點(diǎn)都與深度為k的滿二叉樹(shù)中編號(hào)從1到n一一對(duì)應(yīng)。
2 樹(shù)的深度
樹(shù)的最大層次就是深度,比如上圖,深度是4。很容易得出,深度為k的樹(shù),擁有的最大結(jié)點(diǎn)數(shù)是2的k次方減1。
3 樹(shù)的孩子,兄弟,雙親
上圖中,B,C是A的孩子,B,C之間互為兄弟,A是B,C的雙親。
二如何創(chuàng)建二叉樹(shù)
先說(shuō)說(shuō)二叉樹(shù)的存儲(chǔ)結(jié)構(gòu),跟很多其它模型一樣,也有順序和鏈?zhǔn)絻煞N方式。前者雖然使用簡(jiǎn)單,但是存在浪費(fèi)空間的問(wèn)題,舉個(gè)例子,下圖的二叉樹(shù),用順序的方式存儲(chǔ)(0表示空,沒(méi)有子樹(shù))是:
1 2 3 4 5 6 7 0 0 0 0 8 0 0 0
是不是相當(dāng)浪費(fèi)空間呢。
鏈?zhǔn)浇Y(jié)構(gòu)可以定義如下:
typedef struct _BiTNode { int data; _BiTNode *leftChild; _BiTNode *rightChild; }BiTNode, *pBiTree;
然后就可以寫(xiě)一個(gè)函數(shù)來(lái)創(chuàng)建二叉樹(shù),過(guò)程是在控制臺(tái)輸入a表示退出當(dāng)前這一層,不再為該層創(chuàng)建左右孩子。輸入其它字母表示繼續(xù)創(chuàng)建。比如下面的輸入序列:
創(chuàng)建了如下結(jié)構(gòu)的二叉樹(shù),
每個(gè)結(jié)點(diǎn)里的數(shù)值是隨機(jī)生成的小于100的數(shù)字。同時(shí)我也寫(xiě)了一個(gè)自動(dòng)的命令序列函數(shù),方便測(cè)試,不用手動(dòng)輸入,非自動(dòng)和自動(dòng)創(chuàng)建的函數(shù)如下:
//創(chuàng)建二叉樹(shù), 先序順序 int CreateBiTree(pBiTree *root) { char ch = 0; fflush(stdin); if ((ch = getchar()) == 'a')//控制樹(shù)的結(jié)構(gòu) { *root = NULL; } else { *root = (BiTNode *)malloc(sizeof(BiTNode)); if (!(*root)) { return RET_ERROR; } (*root)->data = GetRandom(); CreateBiTree(&(*root)->leftChild); CreateBiTree(&(*root)->rightChild); } return RET_OK; } int g_i = 0; //創(chuàng)建二叉樹(shù),自動(dòng)執(zhí)行,方便測(cè)試 int CreateBiTreeAuto(pBiTree *root) { char szOrder[] = "bbaabaa"; char ch = 0; if (szOrder[g_i++] == 'a')//控制樹(shù)的結(jié)構(gòu) { *root = NULL; } else { *root = (BiTNode *)malloc(sizeof(BiTNode)); if (!(*root)) { return RET_ERROR; } (*root)->data = GetRandom(); CreateBiTreeAuto(&(*root)->leftChild); CreateBiTreeAuto(&(*root)->rightChild); } return RET_OK; }
三遍歷順序
先序遍歷
先序遍歷是先訪問(wèn)根結(jié)點(diǎn),再左子樹(shù),再右子樹(shù),比如圖1中的右圖,先序遍歷的輸出如下:
A,B,D,H,I,E,J,K,C,F,G
根據(jù)上面的思想,很容易用遞歸的形式寫(xiě)出先序遍歷的代碼:
//先序遍歷 int PreOrderVisitTree(pBiTree T, VisitType pFuncVisit) { if (T) { (*pFuncVisit)(T->data); if (PreOrderVisitTree(T->leftChild, pFuncVisit) == RET_OK) { if (PreOrderVisitTree(T->rightChild, pFuncVisit) == RET_OK) { return RET_OK; } } return RET_ERROR; } else { return RET_OK; } }
中序遍歷和后序遍歷
有了先序的經(jīng)驗(yàn),這兩個(gè)就很好理解了,中序是先訪問(wèn)左子樹(shù), 再根結(jié)點(diǎn),再右子樹(shù), 后序是先訪問(wèn)左子樹(shù), 再右子樹(shù),再根結(jié)點(diǎn)。代碼更容易,只要改一下調(diào)用順序就可以了。
不過(guò)我這里給出一種非遞歸的實(shí)現(xiàn)。遞歸固然是清晰明了,但是存在效率低的問(wèn)題,非遞歸的方案用棧結(jié)構(gòu)來(lái)存結(jié)點(diǎn)信息,通過(guò)出棧訪問(wèn)來(lái)遍歷二叉樹(shù)。它思想是這樣的,當(dāng)棧頂中的指針?lè)强諘r(shí),遍歷左子樹(shù),也就是左子樹(shù)根的指針進(jìn)棧。當(dāng)棧頂指針為空時(shí),應(yīng)退至上一層,如果是從左子樹(shù)返回的,訪問(wèn)當(dāng)前層,也就是棧頂中的根指針結(jié)點(diǎn)。如果是從右子樹(shù)返回,說(shuō)明當(dāng)前層遍歷完畢,繼續(xù)退棧。代碼如下:
//中序遍歷, 非遞歸實(shí)現(xiàn) int InOrderVisitTree(pBiTree T, VisitType pFuncVisit) { ponyStack binaryTreeStack; InitStack(&binaryTreeStack, 4); Push(&binaryTreeStack, &T); pBiTree pTempNode; while (!IsEmptyStack(binaryTreeStack)) { while((GetTop(binaryTreeStack, &pTempNode) == RET_OK) && (pTempNode != NULL)) { Push(&binaryTreeStack, &(pTempNode->leftChild)); } Pop(&binaryTreeStack, &pTempNode); if (!IsEmptyStack(binaryTreeStack)) { Pop(&binaryTreeStack, &pTempNode); (*pFuncVisit)(pTempNode->data); Push(&binaryTreeStack, &(pTempNode->rightChild)); } } return RET_OK; }
代碼下載地址:http://xiazai.jb51.net/201701/yuanma/BinaryTreeDemo-master(jb51.net).rar
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
欄 目:C語(yǔ)言
下一篇:淺談十進(jìn)制小數(shù)和二進(jìn)制小數(shù)之間的轉(zhuǎn)換
本文標(biāo)題:C 語(yǔ)言二叉樹(shù)幾種遍歷方法詳解及實(shí)例
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/1843.html
您可能感興趣的文章
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用函數(shù)刪除字符
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)式函數(shù)庫(kù)
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)數(shù)怎么表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段函數(shù)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排序法函數(shù)
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段函數(shù)
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎么打出三角函數(shù)的值
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求階乘


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載