C語言二叉樹的遍歷,遞迴和非遞迴
程式碼包含如下幾個檔案:
下面一一貼出來:
Stack.h檔案:
#ifndef STACK_H_ #define STACK_H_ #include "BinaryTree.h" #include <stdbool.h> #define STACK_INIT_SZIE 20 #define STACK_INCREMENT_SIZE 10 typedef struct { int size;/** 棧的容量 */ BiTreeNode** base;/** 棧底指標,注意這裡是指向二叉樹節點指標的指標 */ BiTreeNode** top;/** 棧頂指標 */ }Stack; Stack *InitStack();/** 初始化棧 */ void Push(Stack *stack, BiTreeNode* node);/** 入棧 */ BiTreeNode* GetTop(Stack *stack);/** 獲取棧頂資料 */ BiTreeNode* Pop(Stack *stack);/** 棧頂元素出棧 */ bool isStackEmpty(Stack* stack);/** 判斷棧是否為空 */ #endif
Stack.c檔案:
#include<stdio.h> #include <stdlib.h> #include "Stack.h" #include "BinaryTree.h" /** 初始化棧 */ Stack *InitStack() { Stack *stack = (Stack*)malloc(sizeof(Stack)); //下面這句遇到坑了,stack->base應該申請sizeof(BiTreeNode) * STACK_INIT_SZIE的空間,開始忘了*STACK_INIT_SZIE,導致一直出錯 stack->base = (BiTreeNode**)malloc(sizeof(BiTreeNode) * STACK_INIT_SZIE); stack->top = stack->base; stack->size = STACK_INIT_SZIE; return stack; } /** 入棧 */ void Push(Stack *stack, BiTreeNode* node) { if (stack->top - stack->base >= stack->size)//棧滿,重新分配更大的空間 { stack->base = (BiTreeNode**)realloc(stack->base, sizeof(BiTreeNode) * (stack->size + STACK_INCREMENT_SIZE)); if (!stack->base)//分配空間失敗 { printf("stack increment size error!\n"); exit(0); } stack->top = stack->base + stack->size;//修改棧頂指標 stack->size += STACK_INCREMENT_SIZE;//修改新的棧容量大小 //printf("stack increment size 10, now stack size is %d\n", stack->size); } if(node) *(stack->top) = node; else//入棧的是空節點,則用值為#的節點代替空節點 { BiTreeNode* emptyNode = (BiTreeNode*)malloc(sizeof(BiTreeNode)); emptyNode->val = '#'; emptyNode->left = NULL; emptyNode->right = NULL; *(stack->top) = emptyNode; } (stack->top)++; //printf("push node %c to stack, now stack has %d elements, stack size is %d\n", node->val, stack->top - stack->base, stack->size); } /** 獲取棧頂元素 */ BiTreeNode* GetTop(Stack *stack) { if (stack->base == stack->top)//棧空 return NULL; //printf("get stack top: %c\n", (stack->top - 1)->val); return *(stack->top - 1); } /** 出棧 */ BiTreeNode* Pop(Stack *stack) { if (stack->base == stack->top)//棧空 return NULL; --(stack->top); //printf("stack pop: %c\n", stack->top->val); return *stack->top; } /** 判斷棧是否為空 */ bool isStackEmpty(Stack* stack) { if(stack) return stack->base == stack->top; return true; }
BinaryTree.h檔案:
BinaryTree.c檔案:#ifndef BINARY_TREE_H_ #define BINARY_TREE_H_ #include <stdbool.h> typedef struct Node{ struct Node *left;/** 左孩子 */ struct Node *right;/** 右孩子 */ char val;/** 節點中的資料 */ bool isPrintOut;/** 後序非遞迴遍歷時用到,為false表示該節點未輸出,為true表示該節點已輸出 */ }BiTreeNode; BiTreeNode* CreateBinaryTree();/** 建立二叉樹,使用先序建立 */ void PreOrderBiTree(BiTreeNode*);/** 先序遍歷遞迴 */ void PreOrderBiTree1(BiTreeNode*);/** 先序遍歷非遞迴 */ void InOrderBiTree(BiTreeNode*);/** 中序遍歷遞迴 */ void InOrderBiTree2(BiTreeNode*);/** 中序遍歷非遞迴1 */ void InOrderBiTree3(BiTreeNode*);/** 中序遍歷非遞迴2 */ void PostOrderBiTree(BiTreeNode*);/** 後序遍歷遞迴 */ void PostOrderBiTree1(BiTreeNode*);/** 後序遍歷非遞迴 */ bool IsChildsAllPrintOut(BiTreeNode*);/** 判斷某個節點的孩子節點是否全部輸出 */ #endif
#include <stdio.h>
#include <stdlib.h>
#include "BinaryTree.h"
#include "Stack.h"
/** 先序建立二叉樹,使用遞迴的方式建立 */
BiTreeNode* CreateBinaryTree()
{
char c;
scanf("%c", &c);
BiTreeNode* node;
if (c == '#')
node = NULL;
else
{
node = (BiTreeNode*)malloc(sizeof(BiTreeNode));
node->val = c;
node->left = CreateBinaryTree();
node->right = CreateBinaryTree();
node->isPrintOut = false;
}
return node;
}
/** 先序遍歷,遞迴 */
void PreOrderBiTree(BiTreeNode* root)
{
if (root)
{
printf("%c ", root->val);
PreOrderBiTree(root->left);
PreOrderBiTree(root->right);
}
}
/** 先序遍歷,非遞迴 */
void PreOrderBiTree1(BiTreeNode* root)
{
BiTreeNode* p = root;
Stack* stack = InitStack();
while (p || !isStackEmpty(stack))
{
if (p)
{
printf("%c ", p->val);
Push(stack, p);
p = p->left;
}
else
{
p = Pop(stack);
p = p->right;
}
}
}
/** 中序遍歷,遞迴 */
void InOrderBiTree(BiTreeNode* root)
{
if (root)
{
InOrderBiTree(root->left);
printf("%c ", root->val);
InOrderBiTree(root->right);
}
}
/** 中序遍歷,非遞迴方法一 */
void InOrderBiTree2(BiTreeNode* root)
{
Stack *stack = InitStack();
Push(stack, root);
BiTreeNode* p;
while (!isStackEmpty(stack))
{
while ((p = GetTop(stack))->val != '#')
Push(stack, p->left);
Pop(stack);
if (!isStackEmpty(stack))
{
BiTreeNode* node = Pop(stack);
if (node)
{
printf("%c ", node->val);
Push(stack, node->right);
}
}
}
}
/** 中序遍歷,非遞迴方法二 */
void InOrderBiTree3(BiTreeNode* root)
{
Stack* stack = InitStack();
BiTreeNode* p = root;
while (p || !isStackEmpty(stack))
{
if (p)
{
Push(stack, p);
p = p->left;
}
else
{
p = Pop(stack);
printf("%c ", p->val);
//printf("中序非遞迴遍歷遇到節點%c,指標地址為%ld\n", p->val, p);
p = p->right;
}
}
}
/** 後序遍歷,遞迴 */
void PostOrderBiTree(BiTreeNode* root)
{
if (root)
{
PostOrderBiTree(root->left);
PostOrderBiTree(root->right);
printf("%c ", root->val);
}
}
/** 後序遍歷,非遞迴 */
void PostOrderBiTree1(BiTreeNode* root)
{
Stack* stack = InitStack();
BiTreeNode* p = root;
while (p || !isStackEmpty(stack))
{
if (p)
{
Push(stack, p);
p = p->left;
}
else
{
p = GetTop(stack);
if (IsChildsAllPrintOut(p))
{
printf("%c ", p->val);
/** 輸出一個節點,就把該節點的isPrintOut設定為true */
p->isPrintOut = true;
p = Pop(stack);
p = NULL;
}
else
p = p->right;
}
}
}
/** 判斷一個節點的所有孩子節點是否都輸出了 */
bool IsChildsAllPrintOut(BiTreeNode* node)
{
bool leftPrintOut = false;
bool rightPrintOut = false;
if (!node->left)//節點為空則認為該節點已輸出
leftPrintOut = true;
else
leftPrintOut = node->left->isPrintOut;
if (!node->right)
rightPrintOut = true;
else
rightPrintOut = node->right->isPrintOut;
return leftPrintOut && rightPrintOut;
}
main.c檔案:
#include<stdio.h>
#include <stdlib.h>
#include "Stack.h"
void printResult(char *msg, void(*p)(BiTreeNode*), BiTreeNode* node)
{
printf("\n---------%s---------\n", msg);
p(node);
printf("\n---------%s---------\n", msg);
}
int main()
{
printf("使用先序建立二叉樹,#表示空節點,請輸入二叉樹的資料:\n");
BiTreeNode* root = CreateBinaryTree();
printResult("先序遍歷遞迴演算法", PreOrderBiTree, root);
printResult("先序遍歷非遞迴演算法", PreOrderBiTree1, root);
printResult("中序遍歷遞迴演算法", InOrderBiTree, root);
printResult("中序遍歷非遞迴演算法1", InOrderBiTree2, root);
printResult("中序遍歷非遞迴演算法2", InOrderBiTree3, root);
printResult("後序遍歷遞迴演算法", PostOrderBiTree, root);
printResult("後序遍歷非遞迴演算法", PostOrderBiTree1, root);
return 0;
}
測試用的二叉樹如下圖:
程式碼執行結果如下圖:
總結:
在實現這幾個演算法的過程中,遇到了一些坑:
(1)首先是棧的初始化,在為棧底指標分配記憶體空間時,忘了乘以棧容量,導致後來測試一直不對
(2)然後是棧的資料結構定義,棧中儲存的應該是指向二叉樹節點指標的指標,開始我直接定義的指向二叉樹節點的指標,導致在後序非遞迴演算法中一直出問題,修改了某個節點的isPrintOut值後,再取出來發現值沒有變,問題出在Push節點到棧,如果棧中存的是二叉樹節點的指標,則入棧時程式碼是下面這樣的:
這時候入棧就相當於重新分配了空間,導致修改isPrintOut的值不是原來的節點的值,所以後序遍歷一直不對,修改了棧的資料結構,讓棧儲存指向二叉樹節點指標的指標後,再執行就沒問題了
相關推薦
C語言二叉樹 遍歷目錄樹
#include "stdio.h"#include "windows.h"#include <iostream>using namespace std;unsigned long sum = 0;//////////////////////////////////////////////////
資料結構實驗-C語言-二叉樹的建立,前、中、後序遍歷的遞迴演算法和非遞迴演算法,求葉子結點數目,求二叉樹深度,判斷二叉樹是否相似,求二叉樹左右子樹互換,二叉樹層序遍歷的演算法,判斷二叉樹是否是完全二叉樹
1.實驗目的 熟練掌握二叉樹的二叉連結串列儲存結構的C語言實現。掌握二叉樹的基本操作-前序、中序、後序遍歷二叉樹的三種方法。瞭解非遞迴遍歷過程中“棧”的作用和狀態,而且能靈活運用遍歷演算法實現二叉樹的其它操作。 2.實驗內容 (1)二叉樹的二叉連結串列的建立 (2)二叉樹的前、中、後
c語言二叉樹的建立,遍歷,求根的深度,葉子節點的個數
#include <stdio.h> #include <stdlib.h> typedef struct node { char data; struct node *rchild,*lchild; }node,*linklist;
題目1078:二叉樹遍歷(根據前序和中序遍歷結果,獲得後序遍歷)
題目描述: 二叉樹的前序、中序、後序遍歷的定義: 前序遍歷:對任一子樹,先訪問跟,然後遍歷其左子樹,最後遍歷其右子樹; 中序遍歷:對任一子樹,先遍歷其左子樹,然後訪問根,最後遍歷其右子樹; 後序遍歷:對任一子樹,先遍歷其左子樹,然後遍歷其右子樹,最後訪問根。 給定一棵二叉
Uva 248 Tree//二叉樹遍歷,遞迴
這道題剛開始糾結於輸入,還是題刷少了。囧!本來想用strchr函式和指標來操作的,但是在輸入的時候很糾結,就放棄了。這是poj 2255的加強版,不用真正的建樹後在遍歷,直接模擬建樹的過程就解決了。 下面是程式碼: #include<stdio.h&
第九周專案三C/C++利用二叉樹遍歷思想解決問題
/* *Copyright (c) 2017,煙臺大學計算機與控制工程學院 *All rights reserved. *檔名稱:.cpp *完成日期:2017年11月16日 *版 本 號:v1.0 * 利用二叉樹遍歷思想解決問題 /* 【利
二叉樹遍歷(前序)(遞迴+非遞迴)
題目 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{
C語言二叉樹的遍歷,遞迴和非遞迴
程式碼包含如下幾個檔案: 下面一一貼出來: Stack.h檔案: #ifndef STACK_H_ #define STACK_H_ #include "BinaryTree.h" #include <stdbool.h> #define STACK_INI
(C語言版)二叉樹遍歷演算法——包含遞迴前、中、後序和層次,非遞迴前、中、後序和層次遍歷共八種
#include <stdlib.h> #include <stdio.h> #include "BiTree.h" #include "LinkStack.h" #include "LinkQueue.h" //初始化二叉樹(含根節點) void InitBiTree(pBiTr
c++實現二叉樹層序、前序創建二叉樹,遞歸非遞歸實現二叉樹遍歷
log ios cst ack ret 出棧 隊列 結點 非遞歸實現 #include <iostream> #include <cstdio> #include <stdio.h> #include <string> #i
二叉樹遍歷C++(前、中、後序遍歷,層次遍歷、深度遍歷)
一.使用c++進行前中後遍歷,層次和深度遍歷(非遞迴) 二.程式碼 #include<iostream> #include<queue> #include<vector> #include<stack> using name
C語言 二叉樹的遍歷 遞迴和(多種)非遞迴演算法
//二叉樹遍歷 //作者:nuaazdh //時間:2011年12月1日 #include<stdio.h> #include<stdlib.h> #define OK 1 #define ERROR 0 #defi
C語言二叉樹的層序遍歷
在上一篇中我記錄了二叉樹的先序,中序,後序的遞迴和非遞迴遍歷方法,這一篇會接著上一篇的,記錄二叉樹的層序遍歷方法,層序遍歷用到了佇列的資料結構,下面直接上程式碼: 1、首先是鏈佇列的資料結構定義,Li
c語言使用指標實現二叉樹遍歷
使用指標實現二叉樹的定義,建立,以及前序遍歷,中序遍歷,後續遍歷。 /* 該程式實現了二叉樹的建立,以及樹的遍歷,前序遍歷,中序遍歷,後序遍歷。 */ #include <stdio.h> #include<stdlib.h> #include &
二叉樹遍歷 C#
這就是 中序 工作 class stat public 完全 每一個 前期準備 二叉樹遍歷 C# 什麽是二叉樹 二叉樹是每個節點最多有兩個子樹的樹結構 (1)完全二叉樹——若設二叉樹的高度為h,除第 h 層外,其它各層 (1~h-1) 的結
HDU 1710Binary Tree Traversals(已知前序中序,求後序的二叉樹遍歷)
pid http pan clu names pty efi images 樹遍歷 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1710 解題思路:可以由先序和中序的性質得到 : 先序的第一個借點肯定是當前子樹的根結點, 那
二叉樹——遍歷篇(c++)
比較 方便 || 遍歷二叉樹 找到 保存 們的 order out 二叉樹——遍歷篇 二叉樹很多算法題都與其遍歷相關,筆者經過大量學習並進行了思考和總結,寫下這篇二叉樹的遍歷篇。 1、二叉樹數據結構及訪問函數 #include <stdio.h> #includ
【樹】二叉樹遍歷算法(深度優先、廣度優先遍歷,前序、中序、後序、層次)及Java實現
order new link left 算法 很多 == 都是 off 二叉樹是一種非常重要的數據結構,很多其它數據結構都是基於二叉樹的基礎演變而來的。對於二叉樹,有深度遍歷和廣度遍歷,深度遍歷有前序、中序以及後序三種遍歷方法,廣度遍歷即我們平常所說的層次遍歷。因為樹的定義
二叉樹遍歷規則,先順遍歷/中序遍歷/後序遍歷
子節點 itl 根據 得到 mar spa 先序遍歷 bubuko 中序 二叉樹三種遍歷方式 先序遍歷:遍歷順序規則為【根左右】 先訪問根節點,在左葉子,右葉子 中序遍歷:遍歷順序規則為【左根右】 後序遍歷:遍歷順序規則為【左右根】 例題 先序遍歷:ABCDEFGHK