1. 程式人生 > >C語言二叉樹的遍歷,遞迴和非遞迴

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檔案:
#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
BinaryTree.c檔案:
#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