二叉树,非递归实现(前序、中序、后序)

一、结合栈的方式实现,先让右孩子入栈,再让左孩子入栈。栈为空后,结束遍历。

头文件.根据具体的函数名自己创建,另外需要使用栈,引用栈的头文件

stack.h

# pragma oncee
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<assert.h>
#define MAX_SIZE 10
extern struct BinTreeBTNode;//这个文件是在其他文件内部定义的,当前文件中没有,
//要到其他文件中去找
typedef struct BinTreeBTNode* PBTNode;
//指针的大小是确定的,要在当前文件中定义这种变量,必须知道当前类型的存在
//但是此类型定义于其他文件中,那么若是要定义出这种类型,编译器并不知道
//应该给多少个字节,所以此时需要使用指针(指针的大小是确定的)
typedef PBTNode DataTYpe;

typedef struct Stack
{
	DataTYpe _array[MAX_SIZE];//有效元素的个数
	int _top; //栈顶元素的位置
}Stack;

//初始化
void StackInit(Stack *s);

//入栈
void StackPush(Stack *s, DataTYpe data);

//出栈
void StackPop(Stack *s);

//取栈顶元素
DataTYpe StackTop(Stack *s);

//有效元素的个数
int StackSize(Stack *s);

//检测栈是否为空
int Stackempty(Stack *s);

1、前序遍历:

法1:

void PreOrderNor(PBTNode pRoot)
{
	Stack s;
	if (NULL == pRoot)
		return;
	StackInit(&s);
	StackPush(&s, pRoot);//把当前根节点入栈
	while (!Stackempty(&s))
	{
		//遍历:取栈顶元素
		PBTNode pCur = StackTop(&s);//取到栈顶元素,但是元素还在栈里
		printf("%c ", pCur->_data);
		//移除栈顶元素:后进先出
		StackPop(&s);
		if (pCur->_pRight)//优先让右孩子入栈
			StackPush(&s, pCur->_pRight);
		if (pCur->_pLeft)
			StackPush(&s, pCur->_pLeft);
	}
}

法2:

void PreOrderNor(PBTNode pRoot)
{
	Stack s;
	if (NULL == pRoot)
		return;
	StackInit(&s);
	StackPush(&s, pRoot);//把当前根节点入栈
	while (!Stackempty(&s)){
		PBTNode pCur = StackTop(&s);//取栈顶元素
		StackPop(&s);//把栈顶元素移除
		while (pCur){
			printf("%c ", pCur->_data);
			if (pCur->_pRight)
				StackPush(&s,pCur->_pRight);
			pCur = pCur->_pLeft;
		}
	}
}

2、中序遍历:找当前树最左边的节点,并保存所经路径中的所有节点

void InOrder(PBTNode pRoot)
{
	PBTNode pCur = pRoot;
	Stack s;
	if (NULL == pRoot)
		return;
	StackInit(&s);
	//找以pCur为根树的最左边的节点,并且保存所经路径中的所有节点
	while (pCur||!Stackempty(&s))
	{
		while (pCur){
			StackPush(&s, pCur);
			pCur = pCur->_pLeft;
		}
		pCur = StackTop(&s);
		printf("%c ", pCur->_data);
		pCur = pCur->_pRight;
	}
}

3、后序遍历:

void PostOrderNor(PBTNode pRoot)
{
	PBTNode pCur = pRoot, pTop;
	PBTNode pPrev = NULL;//标记最近访问过的节点
	Stack s;
	if (NULL == pRoot){
		return;
	}
	StackInit(&s);
	while (pCur||!Stackempty(&s))
	{
		//找最左边的节点并保存所经路径中的所有节点
		while (pCur){
			StackPush(&s, pCur);
			pCur = pCur->_pLeft;
		}
		pTop = StackTop(&s);
		if (NULL == pTop->_pRight||pTop->_pRight==pPrev){
			printf("%c  ", pTop->_data);
			pPrev = pTop;
			StackPop(&s);
		}
		else
		{
			pCur = pTop->_pRight;
		}
	}
}

 根据前序、中序;后序、中序可以还原二叉树;但是通过前序、后序不能还原二叉树。

通过前序和中序还原二叉树,程序实现:

void ReBuildBinTree(pre, PreSize, in, left,right)
{
	int index = 0;
	//pre:前序遍历的结果,in:中序遍历的结果;Size:遍历的元素个数
	if (PreSize != InSize)
		return;//前序后中序遍历的元素个数不相等则返回
 	pre[index];//确认根节点
	int i = left;
	while (in[i] != pre[index])
		i++;//没有找到根
	//确认左右子树,在中序遍历的结果中查找
	//重建根
	pRoot = BuyBinTreeBTNode(pre[index]);
	//重建根的左子树
	++index;
	ReBuildBinTree(pre, PreSize, left,i);
	//重建根的右子树
	++index;
	ReBuildBinTree(pre, PreSize, i+1,right);
}

a、前序、后序、中序--->递归和非递归速度的比较:循环没有空间开辟、给定是静态栈时,效率比较高,涉及扩容,则效率比较低。

我是借助stack实现的非递归,但是stack可分为静态栈和动态栈,动态栈需要扩容时需要(开辟新空间(新空间需要在系统中查找哪一块空间合适,找到了则返回,查找的过程也浪费时间)、搬移元素、释放旧空间);而递归中开辟新空间只需要执行几个指令,很快。

b、递归和循环遍历的时间复杂度和空间复杂度:

时间复杂度:递归的时间时间复杂度:递归的总次数(2n)*每次递归的次数=O(n)

时间复杂度:用了一个栈,时间复杂度变高O(n)

递归容易在成栈溢出

那么可以不使用栈,用循环的方式遍历二叉树么?线索化二叉树

二、二叉树的线索化(二叉树中总共右n个节点,那么有几个空的指针域:n+1;总共有2*n个指针域,有n-1个指针域已经用过了。【通过指针域的指向,使用循环的方式实现遍历,而不是使用递归的方式】

//对节点进行改造
typedef enum {
	LINK,//指向孩子
	THREAD,//指向后继
}PointerFlag;

//节点的类型
typedef struct BinTreeNode
{
	struct BinTreeNode* _pLeft;
	struct BinTreeNode* _pRight;
	DataTYpe _data;//值域
	//线索
	PointerFlag _leftThread;
	PointerFlag _rightThread;
}BinTreeNode;
//前序线索化
void PreOrderThd(BinTreeNode* pRoot, BinTreeNode* pPrev)
{
	//pPrev标记刚刚线索化过的节点
	if (pRoot)
	{
		//线索化当前节点的左指针域
		if (NULL == pRoot->_pLeft)
		{
			pRoot->_pLeft= pPrev;
			pRoot->_leftThread = THREAD;//左孩子指向前驱节点
		}
		//线索化当前节点的右指针域
		if (pPre&&NULL == pPrev->_pRight){
			pPrev->_pRight = pRoot;
			pPrev->_rightThread = THREAD;
		}
		pPrev = pRoot;
		//判断左孩子是否存在
		if (pRoot->_leftThread==LINK)//存在左孩子
		//线索化当前节点的左子树
		PreOrderThd(pRoot->_pLeft, pPrev);
		if (pRoot->_rightThread==LINK)//存在右孩子
		//线索化当前节点的右子树
		PreOrderThd(pRoot->_pRight, pPrev);
	}
}

猜你喜欢

转载自blog.csdn.net/xuruhua/article/details/81193066
今日推荐