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

代码包含如下几个文件:

C语言二叉树的遍历,递归和非递归_第1张图片

下面一一贴出来:

Stack.h文件:

#ifndef STACK_H_
#define STACK_H_

#include "BinaryTree.h"
#include 
#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
#include 
#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 

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 
#include 
#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
#include 
#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;
}

测试用的二叉树如下图:

C语言二叉树的遍历,递归和非递归_第2张图片

代码运行结果如下图:

C语言二叉树的遍历,递归和非递归_第3张图片


总结:

在实现这几个算法的过程中,遇到了一些坑:
(1)首先是栈的初始化,在为栈底指针分配内存空间时,忘了乘以栈容量,导致后来测试一直不对
(2)然后是栈的数据结构定义,栈中存储的应该是指向二叉树节点指针的指针,开始我直接定义的指向二叉树节点的指针,导致在后序非递归算法中一直出问题,修改了某个节点的isPrintOut值后,再取出来发现值没有变,问题出在Push节点到栈,如果栈中存的是二叉树节点的指针,则入栈时代码是下面这样的:
这时候入栈就相当于重新分配了空间,导致修改isPrintOut的值不是原来的节点的值,所以后序遍历一直不对,修改了栈的数据结构,让栈存储指向二叉树节点指针的指针后,再运行就没问题了

你可能感兴趣的:(数据结构)