C语言实现二叉树的非递归中序遍历

创建一个栈

注意,这个栈的目的时用来保存结点地址的。因为我们在出栈时,还需判断结点的右节点的情况,如果只是保存结点的值,是无法实现中序遍历的。

现在我们来创建一个栈。首先定义一个栈的结构,不过之前还需定义一个节点结构

节点定义

typedef struct BinaryTreeNode{
	int data;
	struct BinaryTreeNode *lchild, *rchild;//左右孩子指针 
}BinaryTreeNode, *pBinaryTreeNode;

栈结构定义

typedef struct {
	pBinaryTreeNode *stack;//栈的指针,由于入栈的是节点地址,所以必须为二级指针
	int top;//标识栈顶位置
	int stacksize;//标识栈的容量
}MyStack;

栈的操作函数

  1. 栈的初始化函数。
    初始化栈结构的数据成员:确认栈的大小,申请一块栈空间。
void initstack(MyStack *_s,int _stacksize)
{
	//1.初始化栈内部变量
	_s->stacksize = _stacksize; //确认栈的大小
	_s->top = -1; //初始栈顶位置为-1
	//2.申请内存空间
	_s->stack = (pBinaryTreeNode*)malloc(sizeof(pBinaryTreeNode)*(_s->stacksize));
}
  1. 栈的Empty函数
    判断栈是否为空,为空返回1。为空的条件是栈结构中的数据成员top<0
int StackEmpty(MyStack *_s)
{
	if (_s->top < 0) return 1;
	return 0;
}
  1. 栈的Push函数
    传入树节点的地址。注意栈满了是当栈顶top达到栈的大小stacksize。由于top从0开始,所以是top= stacksize-1为栈满
void StackPush(MyStack *_s, pBinaryTreeNode _pdata)
{
	if (_s->top == _s->stacksize - 1)
		//栈满了
		exit(1);
	else{
		_s->stack[++(_s->top)] = _pdata;
	}
}
  1. 栈的Pop函数
    删除栈顶数据。
void StackPop(MyStack *_s)
{
	if (StackEmpty(_s) == 1)
		//栈为空
		exit(1);
	else{
		_s->top--;
	}
}
  1. 栈的Top函数
    返回栈顶数据。
pBinaryTreeNode StackTop(MyStack *_s)
{
	if (StackEmpty(_s) == 1)
		//栈为空
		exit(1);
	else{
		return _s->stack[_s->top];
	}
}

怎样实现非递归中序遍历

从中序遍历的顺序可以看出,先打印的一定是最左节点。所第一步是找到最左节点,找到之后可以立马打印数据。第二步是判断已打印数据的右节点,为空则继续出栈;不空则重复第一步的操作。依次循环这两步,直到栈为空。

int inorder(pBinaryTreeNode root){
	MyStack s;
	initstack(&s, 10);
	pBinaryTreeNode current = root;

	if (current == nullptr) return 0;

	while (current || !StackEmpty(&s)){
		if (current){
			StackPush(&s, current);
			current = current->lchild;
		}
		else{
			current = StackTop(&s);
			StackPop(&s);

			printf("%d",current->data);//打印数据
			current = current->rchild;
		}
	}
	return 1;
}

完整代码和测试结果

完整代码:

#include<stdio.h>
#include<stdlib.h>

//二叉树节点定义 
typedef struct BinaryTreeNode{
	int data;
	struct BinaryTreeNode *lchild, *rchild;//左右孩子指针 
}BinaryTreeNode, *pBinaryTreeNode;

//定义栈
typedef struct {
	pBinaryTreeNode *stack;
	int top;
	int stacksize;
}MyStack;

//初始化栈
void initstack(MyStack *_s,int _stacksize)
{
	//1.初始化栈内部变量
	_s->stacksize = _stacksize;
	_s->top = -1;
	//2.申请内存空间
	_s->stack = (pBinaryTreeNode*)malloc(sizeof(pBinaryTreeNode)*(_s->stacksize));
}

//判断栈是否为空
int StackEmpty(MyStack *_s)
{
	if (_s->top < 0) return 1;
	return 0;
}
//栈的push操作
void StackPush(MyStack *_s, pBinaryTreeNode _pdata)
{
	if (_s->top == _s->stacksize - 1)
		//栈满了
		exit(1);
	else{
		_s->stack[++(_s->top)] = _pdata;
	}
}
//栈的top操作:返回栈顶指针
pBinaryTreeNode StackTop(MyStack *_s)
{
	if (StackEmpty(_s) == 1)
		//栈为空
		exit(1);
	else{
		return _s->stack[_s->top];
	}
}
//栈的pop操作:删除栈顶数据
void StackPop(MyStack *_s)
{
	if (StackEmpty(_s) == 1)
		//栈为空
		exit(1);
	else{
		//free(_s->stack[_s->top]);//释放内存
		_s->top--;
	}
}
//中序遍历
int inorder(pBinaryTreeNode root){
	MyStack s;
	initstack(&s, 10);
	pBinaryTreeNode current = root;

	if (current == nullptr) return 0;

	while (current || !StackEmpty(&s)){
		if (current){
			StackPush(&s, current);
			current = current->lchild;
		}
		else{
			current = StackTop(&s);
			StackPop(&s);

			printf("%d",current->data);//打印数据
			current = current->rchild;
		}
	}
	return 1;
}

//创建二叉树 
pBinaryTreeNode CreatBinaryTree(){
	pBinaryTreeNode node;
	int _data;

	scanf("%d", &_data);

	//确认递归的结束的条件
	if (_data < 0)//由于是用户输入节点,当用户输入9999时,递归结束
		return nullptr;

	node = (pBinaryTreeNode)malloc(sizeof(BinaryTreeNode));
	node->data = _data;

	node->lchild = CreatBinaryTree();//生成左子树 
	node->rchild = CreatBinaryTree();//生成右子树 

	return node;
}

int main(){
	
	printf("请按照先序遍历输入二叉树:\n");

	//方法一:动态的创建一课树
	pBinaryTreeNode rootDyn = nullptr; 
	rootDyn = CreatBinaryTree();

	printf("二叉树创建成功!\n");
	printf("\n中序非递归遍历:\n");
	inorder(rootDyn);

	system("pause");
	return 0;
}

打印结果:
在这里插入图片描述
注意输入二叉树时,每个数据之间有空格,<0表示空节点。节点的输入是按照树的前序遍历顺序。上面输入的二叉树如下图所示。
在这里插入图片描述

有关如何递归法动态创建一颗二叉树,可参考:递归创建二叉树(C版)

本人水平有限,欢迎各位朋友批评指正。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值