C语言二叉树的遍历,递归和非递归

原创 2015年11月21日 15:03:11

代码包含如下几个文件:


下面一一贴出来:

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语言实现二叉树的递归遍历与非递归遍历

本文实现了对二叉树的递归遍历和非递归遍历,当然还包括了一些栈操作。           二叉树的遍历本质上其实就是入栈出栈的问题,递归算法简单且容易理解,但是效率始终是个问题。非递归算法可以清楚的知道...
  • B_boyi
  • B_boyi
  • 2016年05月14日 10:35
  • 548

<数据结构>二叉树的递归、非递归以及层次遍历算法C语言实现

二叉树是数据结构中一种非常重要的结构,熟练的掌握二叉树的创建,遍历是打好编程基础的关键。对于遍历,不能仅仅只掌握递归遍历,还应掌握效率更高地非递归遍历。对于非递归的先序、中序、后序遍历要用到栈(在之前...
  • fzh1900
  • fzh1900
  • 2013年11月02日 17:12
  • 3607

二叉树的四种遍历的递归和非递归的实现

二叉树的三种遍历为:前序遍历,中序遍历和后序遍历。 遍历的实现可分为递归和非递归。递归法与二叉树的定义相似,非递归法采用栈去模拟实现。 一、前序遍历的次序为:根结点——左结点——右结点。 递归法实现:...
  • xiaominkong123
  • xiaominkong123
  • 2016年06月02日 16:50
  • 471

浅谈C语言递归机制和非递归转换

一、什么是递归 很多数据结构的定义都是根据递归性质来进行定义的,是因为这些结构固有的性质。递归是指某个函数直接或间接的调用自身。问题的求解过程就是划分成许多相同性质的子问题的求解,而小问题的求解过程...
  • koudaidai
  • koudaidai
  • 2012年10月19日 10:49
  • 1223

C语言:递归和非递归实现二分查找

二分查找是将有序数列不断地缩小,直到找到改元素或折半区域的首元素位置高于尾元素位置为止。//递归写二分查找 int BinarySearchD(int arr[], int x, int begin,...
  • TwinkleCapricorns
  • TwinkleCapricorns
  • 2016年12月04日 10:05
  • 481

快速排序的两种实现思路和非递归实现--C++实现

思路一:        第一种是根据算法导论上的思想:取数组的最后一个元素为主元,i初始化为最低位元素的前一个位置,j指向遍历数组中待排序的元素,当j所指元素比主元小的时候i= i + 1,然后交换...
  • u012691335
  • u012691335
  • 2016年09月14日 15:00
  • 737

【C语言】fibonacci数列 的递归和非递归 +浅谈递归优劣

一、基础概念: 斐波那契数列,又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F...
  • zhangchaoq
  • zhangchaoq
  • 2015年05月10日 15:24
  • 4234

回溯 八皇后问题(递归和非递归)

8皇后问题:如何在8 x 8的国际象棋棋盘上安排8个皇后,使得没有两个皇后能互相攻击?( 如果两个皇后处在同一行、同一列或同一条对角线上,则她们能互相攻击。) 解向量为长度为8的数组,记为solut...
  • march_on
  • march_on
  • 2011年11月30日 16:35
  • 5252

C语言递归与非递归实现求第n个斐波那契数

一、非递归实现第N个菲波那切数列: 程序如下: #include int fib(int n) { int a1 = 1; int a2 = 1; int a3 = 0; if( n 2)...
  • ArchyLi
  • ArchyLi
  • 2016年11月10日 20:49
  • 1204

二叉树的三种遍历方法(递归和非递归)(转载)

#include #include //STL #include using namespace std; class Tree { public: Tree *Left; Tre...
  • acdnjjjdjkdckjj
  • acdnjjjdjkdckjj
  • 2011年03月10日 17:24
  • 4184
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C语言二叉树的遍历,递归和非递归
举报原因:
原因补充:

(最多只允许输入30个字)