二叉树的递归与非递归操作(详细)

二叉树介绍

二叉树

  • 二叉树是由节点(或称为顶点)组成的数据结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树的子树包括左子树和右子树,它们也都是二叉树。
    常见的特殊类型的二叉树类型有满二叉树、完全二叉树、平衡二叉树(AVL树)、二叉搜索树(BST树)等等。

二叉树的遍历

  • 二叉树遍历有几种常见的遍历方式:前序遍历、中序遍历、后序遍历、层序遍历。

前序遍历:先访问根节点,然后前序遍历左子树,最后前序遍历右子树。

中序遍历:先中序遍历左子树,然后访问根节点,最后中序遍历右子树。

后序遍历:先后序遍历左子树,然后后序遍历右子树,最后访问根节点。

层序遍历:按层级从上到下,从左到右访问每个节点。

二叉树的存储

链式存储:使用节点和指针,每个节点包含数据域和两个指针域。
数组存储:适用于完全二叉树,通过数组下标来表示节点之间的关系。

二叉树的应用

  • 二叉搜索树用于快速查找、插入和删除数据。
  • 堆是一种特殊的二叉树,用于实现优先队列。
  • 二叉树还可以用于排序和平衡算法,如AVL树和红黑树。

二叉树常见操作

在树状领域中,最常见的操作是树的创建以及几种遍历方式,还有销毁树。

实现这些操作拥有多种方式,常见的有递归方式非递归方式,均用到链式存储结构,下面进行介绍:

二叉树的递归操作

二叉链表结构定义

typedef char DataType;

typedef struct BTreeNode
{
	DataType data;
	struct BTreeNode* leftchild;//左子树
	struct BTreeNode* rightchild;//右子树
}BinTreeNode;

typedef BTreeNode* BinTree;

递归创建二叉树

BinTree CreateBinTree_Recursion()
{
	//code by FFNCL
	char ch;
	BinTree bt;
	scanf("%c", &ch);//读取输入的字符
	if (ch == '@')//输入@表示分支为空
		bt = NULL;
	else
	{
		bt = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		bt->data = ch;//数据域赋值
		bt->leftchild = CreateBinTree_Recursion();//递归构造左子树
		bt->rightchild = CreateBinTree_Recursion();//递归构造右子树
	}
	return bt;
}

递归先序遍历

void PreOrder_Recursion(BinTree bt)
{
	//code by FFNCL
	if (bt == NULL)
		return;
	printf("%c", bt->data);//先访问根节点
	PreOrder_Recursion(bt->leftchild);//递归访问左子树
	PreOrder_Recursion(bt->rightchild);//递归访问右子树
}

递归中序遍历

void InOrder_Recursion(BinTree bt)
{
	if (bt == NULL)
		return;
	InOrder_Recursion(bt->leftchild);//先访问左子树
	printf("%c", bt->data);	//访问根节点
	InOrder_Recursion(bt->rightchild);//递归访问右子树
}

递归后续遍历

void PostOrder_Recursion(BinTree bt)
{
	//code by FFNCL
	if (bt == NULL)
		return;	
	PostOrder_Recursion(bt->leftchild);//先访问左子树
	PostOrder_Recursion(bt->rightchild);
	printf("%c", bt->data);//最后访问根节点
}

递归层次遍历
层次遍历需要按照层级从左到右访问,所以需要用到队列辅助去解决,关于队列的操作可以看文章后面给出的文章:

void LevelOrder(BinTree bt)
{
	//code by FFNCL
	BinTree p;
	LinkQueue queue = SetNullQueue_link();
	if (bt == NULL)
		return;
	p = bt;
	EnQueue_link(queue, bt);
	while (!IsNullQueue_Link(queue))
	{
		p = FrontQueue_link(queue);
		DeQueue_link(queue);
		printf("%c ", p->data);
		if (p->leftchild != NULL)
			EnQueue_link(queue, p->leftchild);
		if (p->rightchild != NULL)
			EnQueue_link(queue, p->rightchild);
	}
	printf("\n");
}

递归销毁二叉树

void DestroyBinTree(BinTree bt)
{
	//code by FFNCL
	if (bt != NULL)
	{
		DestroyBinTree(bt->leftchild);
		DestroyBinTree(bt->rightchild);
		free(bt);
	}
}

二叉树的非递归操作

非递归的操作相对于递归操作来说比较麻烦,需要用到栈和队列去作为辅助实现

二叉树类型结构定义(与递归操作一样)

typedef char DataType;

typedef struct BTreeNode 
{
	DataType data;
	struct  BTreeNode* leftchild;
	struct BTreeNode* rightchild;
}BinTreeNode;

typedef BinTreeNode* BinTree;

非递归创建二叉树
非递归创建树需要用队列去辅助实现,队列的操作可以参考文章末尾给出的文章,下面是链队列的应用案例:

BinTree CreateBinTree_NRecursion()
{
	//code by FFNCL
	LinkQueue queue = SetNullQueue_link();//创建空队列
	BinTreeNode* s, * p, * bt=NULL;
	printf("按层次输入二叉树节点,以#结束:\n");
	char ch = getchar();//读取输入内容
	int count = -1;//用于分辨根节点或
	while (ch != '#')//以#代表空节点
	{
		s = NULL;//虚节点@
		if (ch != '@')
		{
			s = (BinTreeNode*)malloc(sizeof(BinTreeNode));//申请新节点
			s->data = ch;//数据域赋值
			s->leftchild = NULL;//指针域赋值
			s->rightchild = NULL;
		}
		EnQueue_link(queue, s);//入队
		count++;
		if (count == 0)//0为根节点
			bt = s;
		else
		{
			p = FrontQueue_link(queue);//取队头
			if (s != NULL && p != NULL)
			{
				if (count % 2 == 1)//奇数作为左孩子插入
					p->leftchild = s;
				else
					p->rightchild = s;//偶数作为右孩子插入
			}
			if (count % 2 == 0)
				DeQueue_link(queue);//左右孩子处理完,队头结点出队
		}
		ch = getchar();//读取下一个结点
	}
	return bt;
}

非递归层次遍历

void LevelOrder(BinTree bt)
{
	//code by FFNCL
	BinTree p;
	LinkQueue queue = SetNullQueue_link();
	if (bt == NULL)
		return;
	p = bt;
	EnQueue_link(queue, bt);
	while (!IsNullQueue_Link(queue))
	{
		p = FrontQueue_link(queue);
		DeQueue_link(queue);
		printf("%c ", p->data);
		if (p->leftchild != NULL)
			EnQueue_link(queue, p->leftchild);
		if (p->rightchild != NULL)
			EnQueue_link(queue, p->rightchild);
	}
	printf("\n");
}

非递归先序遍历

void PreOrder_NRecursion(BinTree bt)
{
	//code by FFNCL
    LinkStack lstack;//链栈定义
    lstack = SetNullStack_Link();//初始化
    BinTreeNode* p;
    Push_link(lstack, bt);//根节点入栈
    while (!IsNullStack_link(lstack))
    {
        p = Pop_seq_return(lstack);//取栈头结点值
        Pop_link(lstack);//出栈
        printf("%c", p->data);//访问根结点
        if (p->rightchild)//右子树不空则进栈
        Push_link(lstack, p->rightchild);
        if (p->leftchild)//左子树不空进栈
        Push_link(lstack, p->leftchild);
    }
}

非递归中序遍历

void InOrder_NRecursion(BinTree bt)
{
	//code by FFNCL
    LinkStack lstack;//链栈定义
    lstack = SetNullStack_Link();//初始化
    BinTree p = bt;
    if (p == NULL)
        return;
    Push_link(lstack, bt);//根结点入栈
    p = p->leftchild;//进入左子树
    while (p || !IsNullStack_link(lstack))
    {
        while (p != NULL)
        {
            Push_link(lstack, p);
            p = p->leftchild;
        }
        p = Pop_seq_return(lstack);//取栈头结点值
        Pop_link(lstack);//出栈
        printf("%c", p->data);//访问结点
        p = p->rightchild;//右子树非空则扫描右子树
    }
}

非递归后序遍历

void PostOrder_NRecursion(BinTree bt)
{
	//code by FFNCL
    LinkStack lstack;//定义链栈
    lstack = SetNullStack_Link();//初始化
    BinTree p = bt;
    if (p == NULL)
    return;
    while (p || !IsNullStack_link(lstack))
    {
        while (p != NULL)
        {
            Push_link(lstack, p);//进栈
            p = p->leftchild ? p->leftchild : p->rightchild;
        }
        p = Pop_seq_return(lstack);
        Pop_link(lstack);
        printf("%c", p->data);//访问结点
        if (!IsNullStack_link(lstack) && (Pop_seq_return(lstack)->leftchild == p))
            p = (Pop_seq_return(lstack))->rightchild;//从左子树退回,进入右子树
        else
            p = NULL;//从右子树退回,返回上一层
    }
}

总结

二叉树是数据结构中树状类型的重要点,二叉树的基本操作尤为重要,是理解更复杂数据结构和算法的基础。

参考文章:
队列的操作和应用
栈的操作和使用

在这里插入图片描述

创作不易,感谢支持(q≧▽≦q)

评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值