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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

二叉树学习之非递归遍历

發(fā)布時(shí)間:2024/8/23 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二叉树学习之非递归遍历 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

二叉樹遞歸遍歷可謂是學(xué)過數(shù)據(jù)結(jié)構(gòu)的同仁都能想一下就能寫出來,但在應(yīng)聘過程我們常常遇到的是寫出一個二叉樹非遞歸遍歷函數(shù),接著上篇文章寫二叉樹的非遞歸遍歷,先難后易,一步一步的來.

? 先上代碼:

?

#include "binarytree.h" #include <stack> #include <queue>#ifndef RECU #warning("RECU is not defined")/***前序遍歷(根左右)**1、當(dāng)前節(jié)點(diǎn)為非空,訪問當(dāng)前節(jié)點(diǎn),壓棧其右子節(jié)點(diǎn),考慮其左子節(jié)點(diǎn)*2、當(dāng)前節(jié)點(diǎn)為NULL,出棧**@param t to visit*@param visit point to a func*/ void pre_order(link t, void (*visit)(link)) {std::stack<link> myStack;while( t || !myStack.empty() ) {if ( t ) {visit(t);myStack.push(t->rchild);t = t->lchild;} else {t = myStack.top();myStack.pop();}} }/***中序序遍歷(左根右)**1、當(dāng)前節(jié)點(diǎn)為非空,在訪問當(dāng)前節(jié)點(diǎn)前要先訪問其左子節(jié)點(diǎn),* 壓棧當(dāng)前節(jié)點(diǎn),判斷其左子結(jié)點(diǎn),一直壓棧左子節(jié)點(diǎn)*2、當(dāng)前節(jié)點(diǎn)為NULL,出棧訪問,其左子結(jié)點(diǎn)比當(dāng)前節(jié)點(diǎn)出棧訪問早,* 此時(shí)當(dāng)前節(jié)點(diǎn)是其右節(jié)點(diǎn)的父節(jié)點(diǎn)的角色,考慮其右節(jié)點(diǎn)**在遍歷過程中角色轉(zhuǎn)換很重要**@param t to visit*@param visit point to a func*/ void in_order(link t, void (*visit)(link)) {std::stack<link> myStack;while( t || !myStack.empty() ) {if ( t ) {myStack.push(t);t = t->lchild;} else {t = myStack.top();myStack.pop();visit(t);t = t->rchild;}} }/***后序遍歷(左右根)**1、由于在訪問當(dāng)前樹的根結(jié)點(diǎn)時(shí),應(yīng)先訪問其左、右子樹,因而先將根結(jié)點(diǎn)入棧,* 接著將右子樹也入棧,然后考慮左子樹,重復(fù)這一過程直到某一左子樹為空*2、如果當(dāng)前考慮的子樹為空,* 1.若棧頂不為空,說明第二棧頂對應(yīng)的樹的右子樹未處理,* 則彈出棧頂,下次循環(huán)處理,并將一空指針入棧以表示其另一子樹已做處理;* 2.若棧頂也為空樹,說明第二棧頂對應(yīng)的樹的左右子樹或者為空,或者均已做處理,* 直接訪問第二棧頂?shù)慕Y(jié)點(diǎn),訪問完結(jié)點(diǎn)后,若棧仍為非空,說明整棵樹尚未遍歷完,* 則彈出棧頂,并入棧一空指針表示第二棧頂?shù)淖訕渲灰驯惶幚怼?*@param t to visit*@param visit point to a func*/ void post_order(link t, void (*visit)(link)) {std::stack<link> myStack;while( 1 ) {if ( t ) {myStack.push(t);myStack.push(t->rchild);t = t->lchild;} else {t = myStack.top();myStack.pop();if (!t) {t = myStack.top();myStack.pop();visit(t);if (myStack.empty())break;t = myStack.top();myStack.pop();}myStack.push(NULL);}} } #endif/***層遍歷**@param t to visit*@param visit point to a func*/ void level_order(link t, void (*visit)(link)) {std::queue<link> myQueue;if (t) {myQueue.push(t);while( !myQueue.empty() ) {link tmp = myQueue.front();myQueue.pop();visit(tmp);if (tmp->lchild != NULL)myQueue.push(tmp->lchild);if (tmp->rchild != NULL)myQueue.push(tmp->rchild);}} }

在非遞歸遍歷函數(shù)中我們用到了堆棧和隊(duì)列,為幾種注意力到一件事上,在堆棧和隊(duì)列的實(shí)現(xiàn)上,本人第一時(shí)間想到的是拿來主義,到github去下載別人的源碼來實(shí)現(xiàn).
下載了一個版本都沒達(dá)到想要的效果,于是乎目標(biāo)轉(zhuǎn)移到C++ STL上,最終版本是在C源文件上實(shí)現(xiàn)二叉樹的遞歸函數(shù),在CPP文件中實(shí)現(xiàn)二叉樹的非遞歸函數(shù).所以在make的時(shí)候定義一個變量recu=y來應(yīng)用遞歸函數(shù),其他情況則應(yīng)用非遞歸函數(shù)。

?

由于C與C++公用,那么咱們的頭文件就要動點(diǎn)手腳了,否就會有意外情況出現(xiàn)

?

/* binarytree.h */ #ifndef BINARYTREE_H #define BINARYTREE_H#ifdef __cplusplus extern "C" { #endiftypedef struct node *link; /***節(jié)點(diǎn)中的數(shù)據(jù)類型重定義*/ typedef unsigned char TElemType;struct node { TElemType item; link lchild, rchild; };link init(TElemType VLR[], TElemType LVR[], int n);void pre_order(link t, void (*visit)(link)); void in_order(link t, void (*visit)(link)); void post_order(link t, void (*visit)(link)); #ifndef RECU void level_order(link t, void (*visit)(link)); #endifvoid pprint(link t); int count(link t); int depth(link t); void destroy(link t);/** *http://www.cnblogs.com/bizhu/archive/2012/08/19/2646328.html 算法圖解 * *二叉排序樹(Binary Sort Tree)又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹, *它或者是一棵空樹;或者是具有下列性質(zhì)的二叉樹: *(1)若左子樹不空,則左子樹上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值; *(2)若右子樹不空,則右子樹上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值; *(3)左、右子樹也分別為二叉排序樹; *(4)排序二叉樹的中序遍歷結(jié)果是從小到大排列的. * *二叉查找樹相比于其他數(shù)據(jù)結(jié)構(gòu)的優(yōu)勢在于查找、插入的時(shí)間復(fù)雜度較低,為O(log n)。 *二叉查找樹是基礎(chǔ)性數(shù)據(jù)結(jié)構(gòu),用于構(gòu)建更為抽象的數(shù)據(jù)結(jié)構(gòu),如集合、multiset、關(guān)聯(lián)數(shù)組等。 * *搜索,插入,刪除的復(fù)雜度等于樹高,期望O(log n),最壞O(n)(數(shù)列有序,樹退化成線性表) *改進(jìn)版的二叉查找樹可以使樹高為O(logn),如SBT,AVL,紅黑樹等. * *程序來源于Linux C編程一站式學(xué)習(xí) */ link bstSearch(link t, TElemType key); link bstInsert(link t, TElemType key); link bstDelete(link t, TElemType key);/***http://baike.baidu.com/view/593144.htm?fr=aladdin*平衡二叉樹*/ #ifdef __cplusplus } #endif #endif

對于__cplusplus這個玩意糾結(jié)了很久,模模糊糊知道他是干什么用的,具體放在什么地方糾結(jié)了好一陣子,最后一狠心自己動手編譯試一下,暫且只定義響應(yīng)的空函數(shù),看看編譯連接是否OK,出人意料萬事OK。由此看來動手能力決定一切啊。

?

?

對Makefile文件改動如下:

?

#if you want to use recursive func,please make recu=y ifeq (y, $(recu))CFLAGS += -DRECU endififeq (y, $(debug))CFLAGS += -g endifCC = gcc CPLUS = g++ CFLAGS += -Wall TARGET = treeall:$(TARGET).c.o:$(CC) $(CFLAGS) -o $@ -c $<.cpp.o:$(CPLUS) $(CFLAGS) -o $@ -c $<$(TARGET): non_binarytree.o binarytree.o main.o$(CPLUS) $(CFLAGS) -o $@ $^test:@./tree > result.txt && python result.py | tree -b2.PHONY: all clean clean:$(RM) $(TARGET) *.o

在改動Makefile的工程中遇到了兩個問題:
1、本人認(rèn)為主程序是C程序,所以在連接的時(shí)候用的是gcc,隨后爆出"undefinedreference to '__gxx_personality_v0' " 錯誤。
重來沒有遇到過,只有問度娘,得出的結(jié)果如下:
對于 C++ 程序,編譯的時(shí)候用 gcc 或者 g++ 都可以。但是在進(jìn)行連接的時(shí)候最好用 g++,因?yàn)橛?g++ 會自動進(jìn)行 C++ 標(biāo)準(zhǔn)庫的連接;用 gcc 連接 C++ 程序也可以,但是需要人為指定連接 C++ 標(biāo)準(zhǔn)庫,否則就會出現(xiàn) undefined reference to `__gxx_personality_v/0' 之類的錯誤。可見-lstdc++ 所對應(yīng)的是標(biāo)準(zhǔn)C++庫
2、當(dāng)定義RECU這個宏后,發(fā)現(xiàn)函數(shù)重復(fù)定義,排查了一下函數(shù)定義,在C文件中函數(shù)定義用"#dedef RECU ?**** ?#endif",在C++文件中"#ifndef RECU ? ...... #endif"隔開了呀,用"#warning()"添加編譯過程中的打印信息,定義RECU與否總會編譯到非遞歸函數(shù),我去,奇了怪了。
在仔細(xì)排查,發(fā)現(xiàn)編譯C++文件時(shí)沒有定義RECU。
Makefile內(nèi)容改動如下:

?

?

%.o:%.c$(CC) $(CFLAGS) -o $@ -c $<%.o:%.cpp$(CPLUS) $(CFLAGS) -o $@ -c $< ================改成了================ .c.o:$(CC) $(CFLAGS) -o $@ -c $<.cpp.o:$(CPLUS) $(CFLAGS) -o $@ -c $<

問題是解決了,但這兩種寫法有什么不同還是沒有個所以然
======================================================================

?

腳本是自動化的神器,輸出的序列手動用tree工具轉(zhuǎn)換成圖形確實(shí)麻煩,于是乎想到之前有個博友測試計(jì)算公式的效率時(shí)用到python:
1、python輸出計(jì)算所需要的參數(shù),print函數(shù)就OK
2、測試程序用scanf判斷輸入的參數(shù)個數(shù)是否OK
3、實(shí)現(xiàn)就是python程序輸出的結(jié)構(gòu)通過管道送到測試程序
自動化測試用這個方法可能湊效

寫個腳本一行行的輸出測試程序的結(jié)果:

?

fp = open('result.txt') for line in fp.readlines():print(line)

Makefile添加如下語句:

?

?

test:@./tree > result.txt && python result.py | tree -b2

?

測試只需make test就OK

推薦閱讀:https://blog.csdn.net/LLZK_/article/details/52829525

總結(jié)

以上是生活随笔為你收集整理的二叉树学习之非递归遍历的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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