1. 程式人生 > >[二叉樹] 遍歷方法總結--遞迴與非遞迴--純C實現

[二叉樹] 遍歷方法總結--遞迴與非遞迴--純C實現

非遞迴方法:

  1. 思路一:根據訪問次序來入棧並輸出
  2. 思路二:模擬訪問過程
  3. 思路三:使用識別符號mark來記錄已經第幾次訪問該結點

在這裡插入圖片描述

/*
@Desc:二叉連結串列 無頭結點
@Vesrion:0.0.1
@Time:20180922建立
*/

#include<stdio.h>
#include<stdlib.h>

#ifndef BASE
#define BASE
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef
int Status; typedef int bool; #endif #define TElemType char //固定為char,若修改需要修改方法 typedef struct BiTNode { // 結點結構 TElemType data; struct BiTNode *lchild, *rchild; // 左右孩子指標 }BiTNode, *BiTree; void visit(TElemType e) { printf("%c ", e); } #define maxSize 50 //本檔案中 佇列、棧 最大的內容 Status PreCreate
(BiTree *pT); // 先序遍歷建立二叉樹 int BiTreeDepth(BiTree T); // 求二叉樹深 void LevelOrder(BiTree T);// 層次遍歷DFS // ----------------------------- 遍歷 遞迴實現 void PreOrder(BiTree T); // 先序遍歷二叉樹 void InOrder(BiTree T); // 中序遍歷二叉樹 void PostOrder(BiTree T); // 後序遍歷二叉樹 // ----------------------------- 遍歷 非遞迴實現 // - 思路一:根據訪問次序來入棧並輸出 // -- 缺點:沒有模擬遍歷的實質--對一個結點的三次的訪問
void PreOrderNonrecursive1(BiTree T); //先序遍歷 void PostOrderNonrecursive1(BiTree T); //後序遍歷 // - 思路二:模擬訪問過程 // -- 步驟:走到最左下角,直到走不通-->退回去,往右走一步-->往復 // -- 缺點:只模擬出前兩次訪問,沒有模擬出最後一次訪問-->所以該方法不能實現後序遍歷 void PreOrderNonrecursive2(BiTree T); //先序遍歷 Status InOrderNonrecursive2_1(BiTree T); //中序遍歷-第一種 Status InOrderNonrecursive2_2(BiTree T); //中序遍歷-第二種 // - 思路三:使用識別符號mark來記錄已經第幾次訪問該結點 // -- 優點:該方法可以模擬出遍歷的實質--同一個結點將會三次訪問 --> 可以完成三種遍歷的任何一種 // -- 缺點:構造了一個結構體,開銷大 typedef struct{ BiTNode *ptr; enum {ZERO, ONE, TWO} mark; // 標識第幾次訪問 }PMType; //有mark域的結點指標型別 void PreOrderNonrecursive3(BiTree T); //先序遍歷 void InOrderNonrecursive3(BiTree T); //中序遍歷 void PostOrderNonrecursive3(BiTree T); //後序遍歷 int main() { BiTree T; PreCreate(&T); //測試資料:ABC##DE#G##F### printf("遍歷測試:\n"); printf("---遞迴演算法---\n"); printf("PreOrder():");PreOrder(T);printf("\n"); printf("InOrder():");InOrder(T);printf("\n"); printf("PostOrder():");PostOrder(T); printf("\n---非遞迴演算法-----\n"); printf("PreOrderNonrecursive1():");PreOrderNonrecursive1(T);printf("\n"); printf("PostOrderNonrecursive1():");PostOrderNonrecursive1(T);printf("\n"); printf("PreOrderNonrecursive2():");PreOrderNonrecursive2(T);printf("\n"); printf("InOrderNonrecursive2_1():");InOrderNonrecursive2_1(T);printf("\n"); printf("InOrderNonrecursive2_2():");InOrderNonrecursive2_2(T);printf("\n"); printf("PreOrderNonrecursive3():");PreOrderNonrecursive3(T);printf("\n"); printf("InOrderNonrecursive3():");InOrderNonrecursive3(T);printf("\n"); printf("PostOrderNonrecursive3():");PostOrderNonrecursive3(T);printf("\n"); printf("---層次遍歷---\n"); LevelOrder(T);printf("\n"); return 0; } // 先序遍歷建立二叉樹 Status PreCreate(BiTree *pT) { char ch; scanf("%c", &ch); if ('#' == ch ) *pT=NULL; else { *pT = (BiTNode *)malloc(sizeof(BiTNode)); if (!*pT) exit(OVERFLOW); (*pT)->data = ch; PreCreate( &(*pT)->lchild ); PreCreate( &(*pT)->rchild ); } return OK; } // 先序遍歷二叉樹 void PreOrder(BiTree T) { // - 遞迴 if (!T) return ; visit(T->data); PreOrder(T->lchild); PreOrder(T->rchild); } // 中序遍歷二叉樹 void InOrder(BiTree T) { // - 遞迴 if (!T) return ; InOrder(T->lchild); visit(T->data); InOrder(T->rchild); } // 後序遍歷二叉樹 void PostOrder(BiTree T) { // - 遞迴 if (!T) return ; PostOrder(T->lchild); PostOrder(T->rchild); visit(T->data); } // 層次遍歷DFS void LevelOrder(BiTree T) { BiTNode *queue[maxSize]; int front,rear; BiTNode *p; if (!T) return; front=rear=0; queue[rear] = T;rear = (rear+1)%maxSize; while (front!=rear) { p = queue[front];front=(front+1)%maxSize; visit(p->data); if (p->lchild) { queue[rear] = p->lchild; rear = (rear+1)%maxSize; } if (p->rchild) { queue[rear] = p->rchild; rear = (rear+1)%maxSize; } } } // 求二叉樹深 int BiTreeDepth(BiTree T) { int l,r,tmp; if (!T) return 0; else if (!T->lchild && !T->rchild) return 1; else { l = BiTreeDepth(T->lchild); r = BiTreeDepth(T->rchild); tmp = l>=r?l:r; return 1+tmp; } } // 遍歷 - 非遞迴 // - 思路一:根據訪問次序來入棧並輸出 // -- 缺點:沒有模擬遍歷的實質--對一個結點的三次的訪問 void PreOrderNonrecursive1(BiTree T) { //先序遍歷 /*方法原理: 1. 先序:根左右 2. 訪問根,然後把右、左入棧(先入棧後輸出,所以將右子樹先入棧) */ BiTNode *p; BiTNode *Stack[maxSize]; //自己實現棧,適合做題 int top=-1; //top指向當前元素 if (!T) return ; Stack[++top] = T; //根結點入棧 while (top!=-1) { p = Stack[top--]; visit(p->data); // 右孩子先入棧,先入棧後輸出 if (p->rchild) Stack[++top]=p->rchild; //把右孩子入棧 if (p->lchild) Stack[++top]=p->lchild; //把左孩子入棧 } } void PostOrderNonrecursive1(BiTree T) { /* 方法原理: 思路: 1. 先序:根左右 2. 後序:左右根 --> 逆後序:根右左 3. 比較【先序】和【逆後序】:發現根是一樣的,知識左右換了一下 結論: 1. 與PreOrderNonrecursive1方法類似,只是先將左孩子先入棧(先入棧後輸出),得到逆後序序列 2. 將逆後序數列倒過來輸出 */ BiTNode *p; BiTNode *Stack[maxSize]; int top1=-1; BiTNode *InPostOrderStack[maxSize]; int top2=-1; Stack[++top1] = T; while (top1!=-1) { p = Stack[top1--]; InPostOrderStack[++top2]=p; if (p->lchild) Stack[++top1]=p->lchild; if (p->rchild) Stack[++top1]=p->rchild; } while (top2!=-1) { p = InPostOrderStack[top2--]; visit(p->data); } } // - 思路二:模擬訪問過程 // -- 步驟:走到最左下角,直到走不通-->退回去,往右走一步-->往復 // -- 缺點:只模擬出前兩次訪問,沒有模擬出最後一次訪問-->所以該方法不能實現後序遍歷 void PreOrderNonrecursive2(BiTree T) { //先序遍歷 BiTNode *Stack[maxSize];int top=-1; //SqStack S; BiTNode *p; Stack[++top]=T;//Push(&S, T); while (top!=-1) { //棧不為空 //向左走到盡頭 while (p=Stack[top]) { visit(p->data); Stack[++top]=p->lchild; } --top; //上一步多將一個NULL放入棧了,刪除它 if (top!=-1) { //退一步,並向右走一步 p=Stack[top--]; Stack[++top]=p->rchild; } } } Status InOrderNonrecursive2_1(BiTree T) { //中序遍歷 BiTNode *p; BiTNode *Stack[maxSize];int top=-1; //建立棧 Stack[++top]=T; //根指標進棧 while (top!=-1) { while (p=Stack[top]) Stack[++top] = p->lchild;//向左走到盡頭 --top;//空指標出棧 if (top!=-1) {//訪問結點,向右一步 p=Stack[top--]; visit(p->data); Stack[++top]=p->rchild; } } return OK; } Status InOrderNonrecursive2_2(BiTree T) { //中序遍歷 BiTNode *p; BiTNode *Stack[maxSize];int top=-1; //建立棧 p=T; while (p || top!=-1 ) { if (p) { //根指標進棧,遍歷左子樹 Stack[++top]=p; p=p->lchild; } else { //根指標退棧,訪問根結點,遍歷右子樹 p=Stack[top--]; visit(p->data); p=p->rchild; } } return OK; } // - 思路三:使用識別符號mark來記錄已經第幾次訪問該結點 // -- 優點:該方法可以模擬出遍歷的實質--同一個結點將會三次訪問 --> 可以完成三種遍歷的任何一種 // -- 缺點:構造了一個結構體,開銷大 void PreOrderNonrecursive3(BiTree T) { //先序遍歷 PMType pm; PMType stack[maxSize];int top=-1; //棧 pm.mark=ZERO;pm.ptr=T;stack[++top]=pm; //根結點入棧 while (top!=-1) { //棧不空 pm = stack[top--]; //取出棧頂 switch (pm.mark) { case ZERO: //第一次訪問該結點 visit(pm.ptr->data); pm.mark=ONE;stack[++top]=pm; //修改mark域,再放入棧 if (pm.ptr->lchild) {//往左走 pm.mark = ZERO;pm.ptr=pm.ptr->lchild; stack[++top] = pm; } break; case ONE: //左子樹處理返回,第二次訪問 pm.mark=TWO;stack[++top]=pm; //修改mark域,再放入棧 if (pm.ptr->rchild) { //往右走 pm.mark=ZERO;pm.ptr=pm.ptr->rchild; stack[++top]=pm; } break; case TWO: //右子樹處理訪問,第三次訪問 break; //空操作 } } } void InOrderNonrecursive3(BiTree T) { //中序遍歷 PMType pm; PMType stack[maxSize];int top=-1; //棧 pm.mark=ZERO;pm.ptr=T;stack[++top]=pm; //根結點入棧 while (top!=-1) { //棧不空 pm = stack[top--]; //取出棧頂 switch (pm.mark) { case ZERO: //第一次訪問該結點 pm.mark=ONE;stack[++top]=pm; //修改mark域,再放入棧 if (pm.ptr->lchild) {//往左走 pm.mark = ZERO;pm.ptr=pm.ptr->lchild; stack[++top] = pm; } break; case ONE: //左子樹處理返回,第二次訪問 visit(pm.ptr->data); pm.mark=TWO;stack[++top]=pm; //修改mark域,再放入棧 if (pm.ptr->rchild) { //往右走 pm.mark=ZERO;pm.ptr=pm.ptr->rchild; stack[++top]=pm; } break; case TWO: //右子樹處理訪問,第三次訪問 break; //空操作 } } } void PostOrderNonrecursive3(BiTree T) { //後序遍歷 PMType pm; PMType stack[maxSize];int top=-1; //棧 pm.mark=ZERO;pm.ptr=T;stack[++top]=pm; //根結點入棧 while (top!=-1) { pm = stack[top--]; switch (pm.mark) { case ZERO: //剛剛訪問此結點 pm.mark=ONE;stack[++top]=pm; //修改mark域 if (pm.ptr->lchild) { pm.mark = ZERO;pm.ptr = pm.ptr->lchild; stack[++top] = pm; //訪問左子樹 } break; case ONE: //左子樹處理返回 pm.mark=TWO;stack[++top]=pm; //修改mark域 if (pm.ptr->rchild) { pm.mark = ZERO;pm.ptr=pm.ptr->rchild; stack[++top] = pm; //訪問右子樹 } break; case TWO: //右子樹處理返回 visit(pm.ptr->data); } }

相關推薦

[] 方法總結----C實現

非遞迴方法: 思路一:根據訪問次序來入棧並輸出 思路二:模擬訪問過程 思路三:使用識別符號mark來記錄已經第幾次訪問該結點 /* @Desc:二叉連結串列 無頭結點 @Vesrion:0.0.1 @Time:20180922建立 */ #include

面試中很值得聊的方法——Morris

Morris遍歷 通過利用空閒指標的方式,來節省空間。時間複雜度O(N),額外空間複雜度O(1)。普通的非遞迴和遞迴方法的額外空間和樹的高度有關,遞迴的過程涉及到系統壓棧,非遞迴需要自己申請棧空間,都具有O(N)的額外空間複雜度。 Morris遍歷的原則: 1. 假設當前節點為cur, 2. 如果cur沒有左

總結(先序||中序||後序||按層||之字&&||

先序遍歷:8 6 5 7 10 9 11 後序遍歷:5 7 6 9 11 10 8 中序遍歷:5 6 7 8 9 10 11 按層遍歷:8 6 10 5 7 9 11 之字遍歷:8 10 6 5 7

理解——方法中棧的利用

1.二叉樹介紹 二叉樹是每個節點最多有兩個子樹的樹結構,遍歷方法有深度優先(包括:先序、中序、後序遍歷)和寬度優先(層序遍歷),層序遍歷通過佇列可以實現。這裡主要介紹深度優先遍歷的方法以及其中棧的應用,幫助理解二叉樹的結構、遞迴和非遞迴中棧的應用。程式pyth

歸算法——中序

spa tdi str max logs nor 算法實現 中序遍歷 非遞歸   二叉樹中序遍歷的非遞歸算法同樣可以使用棧來實現,從根結點開始,將根結點的最左結點全部壓棧,當結點p不再有最左結點時,說明結點p沒有左孩子,將該結點 出棧,訪問結點p,然後對其右孩子做同樣的處理

算法總結

使用 preorder 說明 stack height type pri content 結構圖 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

總結

struct left else oot nor 節點 操作 preorder AC   節點定義如下 1 // Definition for a binary tree node. 2 struct TreeNode { 3 int val; 4 Tre

c++實現層序、前序創建實現

log ios cst ack ret 出棧 隊列 結點 非遞歸實現 #include <iostream> #include <cstdio> #include <stdio.h> #include <string> #i

演算法

作者:石鍋拌飯  原文連結 二叉樹的遍歷演算法有多種,典型的有先序遍歷、中序遍歷、後序遍歷以及層序遍歷。而且這些遍歷的遞迴演算法較為簡單,程式碼很少,容易實現,本文就是彙總二叉樹遍歷的遞迴演算法,非遞迴演算法將在下一篇文章中進行總結。本文中用到的二叉樹例項如下:

(迴圈和

遞迴 1.前序遍歷 void preorder(BinTree *T) { if(T==NULL) return; cout << T->data; preorder(T->left); preorder(T->rig

演算法

二叉樹遍歷的非遞迴演算法(java實現) package com.mpackage.tree; import java.util.*; public class TreeSolution { //先根遍歷 public static ArrayList

:前序,中序,後序,層序的以及實現

樹,是一種在實際程式設計中經常遇到的資料結構,它的邏輯很簡單:除根節點之外每個節點都有且只有一個父節點,除葉子節點之外所有節點都有一個或多個子節點。我們說的二叉樹,就是指子節點最多2個的樹。 二叉樹中,最重要的操作就是遍歷。二叉樹的遍歷分為: 1.前序遍歷:先訪問根節點,

演算法實現

linux c++ 模板類 討論範圍 本部落格只實現二叉樹非遞迴演算法的遍歷,請自行學習二叉樹和模板類等相關知識。程式碼中附帶大量註釋,所以就不在進行詳細說明。 中序遍歷 template <typename T>void Post<T>

(前序)(+

題目 Binary Tree Preorder Traversal Given a binary tree, return the preorder traversal of its nodes’ values. For example: Given binary

(中序)(+

Binary Tree Inorder Traversal(二叉樹中序遍歷) Given a binary tree, return the inorder traversal of its nodes’ values. For example: Given binary tree{

/ 模板(??)

遞迴版 void First_order_traversal(int i) //先序 { printf("%d\n", key[i]); First_order_traversal(lc[i]);

演算法(實現先序中序和後續)(實現中序和先續)

二叉樹遍歷 這兩天抓緊把二叉樹遍歷複習了一遍,遞迴實現還是一如既往地簡潔,迭代版本寫了好久還是隻實現了先序和中序,後續一直沒搞明白,有空了再更新。 遞迴實現 void RecursionBackTree(TreeNode * root) {

(已知中序和按層求先序

二叉樹遍歷(flist) 時間限制: 1000 ms         記憶體限制: 65536 KB 提交數: 8     通過數: 6  【題目描述】 樹和二叉樹基本上都有先序、中序、後序、按層遍歷等遍歷順序,給定中序和其它一種遍歷的序列就可以確定一棵二叉樹的結構。

(四種方式、迭代及實現

二叉樹的常見遍歷方式主要有前序,中序和後序,以及層次遍歷(從上到下,從左到右)四種方法。 前、中、後遍歷分別順序如下: 分別通過遞迴和迴圈的方式實現(Python): # -*- coding:utf-8 -*- class TreeNode: def __

演算法

在前一篇文章二叉樹遍歷遞迴演算法對二叉樹遍歷的遞迴演算法做了總結,這篇文章就來對二叉樹遍歷的非遞迴演算法做個彙總。還是與上一篇文章一樣的順序,一一彙總先序、中序、後序以及層序遍歷的非遞迴演算法。 1、先序遍歷(非遞迴演算法) 先序遍歷非遞迴訪問,使用棧即可實現。先序遍