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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

二叉树的四种遍历方式(递归和非递归双重实现)

發布時間:2024/10/14 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二叉树的四种遍历方式(递归和非递归双重实现) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫在前面:博主是一位普普通通的19屆雙非軟工在讀生,平時最大的愛好就是聽聽歌,逛逛B站。博主很喜歡的一句話花開堪折直須折,莫待無花空折枝:博主的理解是頭一次為人,就應該做自己想做的事,做自己不后悔的事,做自己以后不會留有遺憾的事,做自己覺得有意義的事,不浪費這大好的青春年華。博主寫博客目的是記錄所學到的知識并方便自己復習,在記錄知識的同時獲得部分瀏覽量,得到更多人的認可,滿足小小的成就感,同時在寫博客的途中結交更多志同道合的朋友,讓自己在技術的路上并不孤單。

目錄:
1.二叉樹的先序遍歷
???? ?? 先序遍歷思想
???? ?? 先序遍歷遞歸實現
???? ?? 先序遍歷非遞歸實現
2.二叉樹的中序遍歷
???? ?? 中序遍歷思想
???? ?? 中序遞歸實現
???? ?? 中序非遞歸實現
3.二叉樹的后序遍歷
???? ?? 后序遍歷思想
???? ?? 中序遞歸實現
???? ?? 中序非遞歸實現
4.二叉樹的層序遍歷
???? ?? 代碼實現

博客中的二叉樹存儲方式如下

typedef struct BiTNode{TElemType data;//數據域struct BiTNode *lchild,*rchild;//左右孩子指針 }BiTNode,*BiTree;

1.二叉樹的先序遍歷

1.1二叉樹先序遍歷的實現思想是:

  • 訪問根節點;
  • 訪問當前節點的左子樹;
  • 若當前節點無左子樹,則訪問當前節點的右子樹;
  • 上圖先序遍歷結果為:1 2 4 5 3 6 7

    1.2先序遍歷遞歸實現

    void PreOrderTraverse(BiTree T){if (T) {printf("%d ",T->data);PreOrderTraverse(T->lchild);//訪問該結點的左孩子PreOrderTraverse(T->rchild);//訪問該結點的右孩子}//如果結點為空,返回上一層return; }

    1.3先序遍歷非遞歸實現

    而遞歸的底層實現依靠的是棧存儲結構,因此,二叉樹的先序遍歷既可以直接采用遞歸思想實現,也可以使用棧的存儲結構模擬遞歸的思想實現

    //先序遍歷非遞歸算法 int top=-1;//top變量時刻表示棧頂元素所在位置 //前序遍歷使用的進棧函數 void push(BiTNode** a,BiTNode* elem){a[++top]=elem; } //彈棧函數 void pop( ){if (top==-1) {return ;}top--; } //模擬操作結點元素的函數,輸出結點本身的數值 void displayElem(BiTNode* elem){printf("%d ",elem->data); } //拿到棧頂元素 BiTNode* getTop(BiTNode**a){return a[top]; } void PreOrderTraverse(BiTree Tree){BiTNode* a[20];//定義一個順序棧BiTNode * p;//臨時指針push(a, Tree);//根結點進棧while (top!=-1) {p=getTop(a);//取棧頂元素pop();//彈棧while (p) {displayElem(p);//調用結點的操作函數//如果該結點有右孩子,右孩子進棧if (p->rchild) {push(a,p->rchild);}p=p->lchild;//一直指向根結點最后一個左孩子}} }

    2.二叉樹的中序遍歷

    2.1二叉樹中序遍歷思想

  • 訪問當前節點的左子樹;
  • 訪問根節點;
  • 訪問當前節點的右子樹
  • 上圖中遍歷結果:4 2 5 1 6 3 7

    2.2中序遍歷遞歸實現

    //中序遍歷 void INOrderTraverse(BiTree T){if (T) {INOrderTraverse(T->lchild);//遍歷左孩子printf("%d ",T->data);INOrderTraverse(T->rchild);//遍歷右孩子}//如果結點為空,返回上一層return; }

    2.3中序遍歷非遞歸實現

    而遞歸的底層實現依靠的是棧存儲結構,因此,二叉樹的先序遍歷既可以直接采用遞歸思想實現,也可以使用棧的存儲結構模擬遞歸的思想實現。
    中序遍歷的 非遞歸方式實現思想 是:從根結點開始,遍歷左孩子同時壓棧,當遍歷結束,說明當前遍歷的結點沒有左孩子,從棧中取出來調用操作函數,然后訪問該結點的右孩子,繼續以上重復性的操作。除此之外, 還有另一種實現思想:中序遍歷過程中,只需將每個結點的左子樹壓棧即可,右子樹不需要壓棧。當結點的左子樹遍歷完成后,只需要以棧頂結點的右孩子為根結點,繼續循環遍歷即可。

    第一種非遞歸思路

    int top=-1;//top變量時刻表示棧頂元素所在位置 //前序和中序遍歷使用的進棧函數 void push(BiTNode** a,BiTNode* elem){a[++top]=elem; } //彈棧函數 void pop( ){if (top==-1) {return ;}top--; } //模擬操作結點元素的函數,輸出結點本身的數值 void displayElem(BiTNode* elem){printf("%d ",elem->data); } //拿到棧頂元素 BiTNode* getTop(BiTNode**a){return a[top]; } //中序遍歷非遞歸算法 void InOrderTraverse1(BiTree Tree){BiTNode* a[20];//定義一個順序棧BiTNode * p;//臨時指針push(a, Tree);//根結點進棧while (top!=-1) {//top!=-1說明棧內不為空,程序繼續運行while ((p=getTop(a)) &&p){//取棧頂元素,且不能為NULLpush(a, p->lchild);//將該結點的左孩子進棧,如果沒有左孩子,NULL進棧}pop();//跳出循環,棧頂元素肯定為NULL,將NULL彈棧if (top!=-1) {p=getTop(a);//取棧頂元素pop();//棧頂元素彈棧displayElem(p);push(a, p->rchild);//將p指向的結點的右孩子進棧}} }

    第二種非遞歸思路:

    //中序遍歷實現的另一種方法 void InOrderTraverse2(BiTree Tree){BiTNode* a[20];//定義一個順序棧BiTNode * p;//臨時指針p=Tree;//當p為NULL或者棧為空時,表明樹遍歷完成while (p || top!=-1) {//如果p不為NULL,將其壓棧并遍歷其左子樹if (p) {push(a, p);p=p->lchild;}//如果p==NULL,表明左子樹遍歷完成,需要遍歷上一層結點的右子樹else{p=getTop(a);pop();displayElem(p);p=p->rchild;}} }

    3.二叉樹的后序遍歷

    3.1后序遍歷思想

    從根節點出發,依次遍歷各節點的左右子樹,直到當前節點左右子樹遍歷完成后,才訪問該節點元素。

    上圖后序遍歷的結果為:4 5 2 6 7 3 1

    3.2后序遍歷的遞歸實現

    void PostOrderTraverse(BiTree T){if (T) {PostOrderTraverse(T->lchild);//遍歷左孩子PostOrderTraverse(T->rchild);//遍歷右孩子printf("%d ",T->data);}//如果結點為空,返回上一層return; }

    3.2后序遍歷的非遞歸實現

    后序遍歷是在遍歷完當前結點的左右孩子之后,才調用操作函數,所以需要在操作結點進棧時,為每個結點配備一個標志位。當遍歷該結點的左孩子時,設置當前結點的標志位為 0,進棧;當要遍歷該結點的右孩子時,設置當前結點的標志位為 1,進棧。
    這樣,當遍歷完成,該結點彈棧時,查看該結點的標志位的值:如果是 0,表示該結點的右孩子還沒有遍歷;反之如果是 1,說明該結點的左右孩子都遍歷完成,可以調用操作函數。

    int top=-1;//top變量時刻表示棧頂元素所在位置 //彈棧函數 void pop( ){if (top==-1) {return ;}top--; } //模擬操作結點元素的函數,輸出結點本身的數值 void displayElem(BiTNode* elem){printf("%d ",elem->data); } //后序遍歷非遞歸算法 typedef struct SNode{BiTree p;int tag; }SNode; //后序遍歷使用的進棧函數 void postpush(SNode *a,SNode sdata){a[++top]=sdata; } //后序遍歷函數 void PostOrderTraverse(BiTree Tree){SNode a[20];//定義一個順序棧BiTNode * p;//臨時指針int tag;SNode sdata;p=Tree;while (p||top!=-1) {while (p) {//為該結點入棧做準備sdata.p=p;sdata.tag=0;//由于遍歷是左孩子,設置標志位為0postpush(a, sdata);//壓棧p=p->lchild;//以該結點為根結點,遍歷左孩子}sdata=a[top];//取棧頂元素pop();//棧頂元素彈棧p=sdata.p;tag=sdata.tag;//如果tag==0,說明該結點還沒有遍歷它的右孩子if (tag==0) {sdata.p=p;sdata.tag=1;postpush(a, sdata);//更改該結點的標志位,重新壓棧p=p->rchild;//以該結點的右孩子為根結點,重復循環}//如果取出來的棧頂元素的tag==1,說明此結點左右子樹都遍歷完了,可以調用操作函數了else{displayElem(p);p=NULL;}} }

    4.二叉樹的層序遍歷

    照二叉樹中的層次從左到右依次遍歷每層中的結點。具體的實現思路是:通過使用隊列的數據結構,從樹的根結點開始,依次將其左孩子和右孩子入隊。而后每次隊列中一個結點出隊,都將其左孩子和右孩子入隊,直到樹中所有結點都出隊,出隊結點的先后順序就是層次遍歷的最終結果。

    上圖層序遍歷結果:1 2 3 4 5 6 7

    #include <stdio.h> #define TElemType int //初始化隊頭和隊尾指針開始時都為0 int front=0,rear=0; typedef struct BiTNode{TElemType data;//數據域struct BiTNode *lchild,*rchild;//左右孩子指針 }BiTNode,*BiTree; void CreateBiTree(BiTree *T){*T=(BiTNode*)malloc(sizeof(BiTNode));(*T)->data=1;(*T)->lchild=(BiTNode*)malloc(sizeof(BiTNode));(*T)->rchild=(BiTNode*)malloc(sizeof(BiTNode));(*T)->lchild->data=2;(*T)->lchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));(*T)->lchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));(*T)->lchild->rchild->data=5;(*T)->lchild->rchild->lchild=NULL;(*T)->lchild->rchild->rchild=NULL;(*T)->rchild->data=3;(*T)->rchild->lchild=(BiTNode*)malloc(sizeof(BiTNode));(*T)->rchild->lchild->data=6;(*T)->rchild->lchild->lchild=NULL;(*T)->rchild->lchild->rchild=NULL;(*T)->rchild->rchild=(BiTNode*)malloc(sizeof(BiTNode));(*T)->rchild->rchild->data=7;(*T)->rchild->rchild->lchild=NULL;(*T)->rchild->rchild->rchild=NULL;(*T)->lchild->lchild->data=4;(*T)->lchild->lchild->lchild=NULL;(*T)->lchild->lchild->rchild=NULL; } //入隊函數 void EnQueue(BiTree *a,BiTree node){a[rear++]=node; } //出隊函數 BiTNode* DeQueue(BiTNode** a){return a[front++]; } //輸出函數 void displayNode(BiTree node){printf("%d ",node->data); } int main() {BiTree tree;//初始化二叉樹CreateBiTree(&tree);BiTNode * p;//采用順序隊列,初始化創建隊列數組BiTree a[20];//根結點入隊EnQueue(a, tree);//當隊頭和隊尾相等時,表示隊列為空while(front<rear) {//隊頭結點出隊p=DeQueue(a);displayNode(p);//將隊頭結點的左右孩子依次入隊if (p->lchild!=NULL) {EnQueue(a, p->lchild);}if (p->rchild!=NULL) {EnQueue(a, p->rchild);}}return 0; }

    本篇博客轉載C語言中文網

    總結

    以上是生活随笔為你收集整理的二叉树的四种遍历方式(递归和非递归双重实现)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。