首页 > 其他分享 >二叉树层次建树+遍历

二叉树层次建树+遍历

时间:2024-02-13 15:44:06浏览次数:29  
标签:结点 遍历 TNode phead 二叉树 NULL LinkNode 建树

1.BiTree层次建树实现

使用二叉树的链式存储,必须要构造一个辅助链式队列,用pcur遍历树结点,实现代码如下:

代码实现
//二叉树层次建树+画图 2024-02-12
#include <iostream>
#include <cstdio>

using namespace std;

//树结点的数据结构
typedef char ElemType;
typedef struct TNode{
   ElemType c; //即data
   struct TNode *lchild, *rchild; //左右孩子指针
}TNode,*Tree;

//需要一个用于辅助的链式队列
typedef struct LinkNode{
   TNode * data; //用于存储树结点的地址,藏宝图
   struct LinkNode *pnext;
}LinkNode;

typedef struct {
   LinkNode *phead, *ptail;
}LinkQueue;

//链队列部分
//下次应该把TNode * 取个别名,这样代码更容易移植通用
bool IsEmpty(LinkQueue Q)
{
   return Q.phead == NULL && Q.ptail == NULL;
}
//获取队头元素值
bool GetTop(LinkQueue Q, TNode *&x)
{
   if(IsEmpty(Q))
   {
       return false;
   }
   x = Q.phead->data;
   return true;
}
//入队
bool EnQueue(LinkQueue &Q, TNode *x)
{
   LinkNode *pnew = (LinkNode*)calloc(1, sizeof(LinkNode));
   pnew->data = x;//因为是calloc就不用pnew->pnext = NULL; 
   Q.ptail->pnext = pnew;
   Q.ptail = pnew; //队尾指针指向新插入的最后一个结点
   return true;
}
//出队,队头出队
bool DeQueue(LinkQueue &Q, TNode *&x)
{
   if(IsEmpty(Q))
   {
       return false;
   }
   x = Q.phead->data;
   LinkNode *q = Q.phead;
   Q.phead = Q.phead->pnext;
   if(Q.phead == NULL)//如果删除的是最后一个结点
   {
       Q.ptail = Q.phead;
   }
   free(q);
   return true;
} 

//二叉树递归遍历
//先序遍历
void preOrder(Tree T)
{
   if(T != NULL)
   {
       printf("%c", T->c);
       preOrder(T->lchild);
       preOrder(T->rchild);
   }
}

//abcdefghij
int main()
{
   ElemType c;
   Tree T = NULL;
   LinkQueue Q;//定义一个用于辅助层次建树的链队列
   Q.phead = Q.ptail = NULL;
   LinkNode *pcur;
   while(scanf("%c", &c) != EOF)
   {
       if(c == '\n')
           break;
       if(NULL == T) //如果是第一个结点,就作为根结点
       {
           T = (Tree)calloc(1, sizeof(TNode)); //用calloc把整个结点数据置0,即NULL
           T->c = c;
           LinkNode *p = (LinkNode *)calloc(1, sizeof(LinkNode));
           p->data = T;
           Q.phead = Q.ptail = p;
           pcur = p;
           continue;
       }
       //不是第一个输入的结点
       TNode *tnew = (TNode *)calloc(1, sizeof(TNode));
       tnew->c = c;
       EnQueue(Q, tnew); //入队,入链队列
       if(pcur->data->lchild == NULL)//建树
       {
           pcur->data->lchild = tnew;
       }
       else if(pcur->data->rchild == NULL)
       {
           pcur->data->rchild = tnew;
           pcur = pcur->pnext;//左右孩子都满了指向链队列的下一个结点
       }
   }
   preOrder(T);
   printf("\n");
   return 0;
}

画示意图如图所示:
唐代大师_层次建树_真迹.png
注意,calloc和malloc函数的区别,就在于calloc分配空间的同时,会把该内存空间的数据置0,方便了我们不用加一行代码使指针变量值为NULL。

2.数据结构动画网址

很好用的数据结构动画网站,不过是国外的,可能用魔法访问速度快一点。

3.前/中/后序遍历

前序遍历也叫先序遍历,如果层次遍历是广度优先遍历,那么前序遍历就是深度优先遍历。以中序遍历为例,使用递归的方法是很容易理解和实现的,并且我们手动去写出遍历的结果,也可以参照递归代码的逻辑,每次只看一小棵子树,孩子结点总是紧挨着父结点。

3.1中序遍历非递归实现

中序遍历
//中序遍历递归
void InOrder(BiTree t)
{
	if (t)//要设置递归出口
	{
		InOrder(t->lchild);
		putchar(t->c);
		InOrder(t->rchild);
	}
}
//中序遍历非递归,需要构思
void InOrder2(BiTree t)
{
	SqStack S;
	InitStack(S); BiTree p = t;
	while (p || !StackEmpty(S))
	{
		if (p)
		{//不断压栈的过程中找到最左边的左孩子
			Push(S, p);
			p = p->lchild;
		}
		else {//弹出栈中元素并打印,获取打印元素的右结点
			Pop(S, p);
			putchar(p->c);
			p = p->rchild;
		}
	}
}

打印结果:
中序遍历非递归.jpg

4.层次遍历(层序遍历)

看着建好的二叉树图,按逻辑写下来即可,注意和层序建树一样,需要用到一个辅助的链式队列,为了节省空间,链队列只存树结点的地址。

层序遍历
//层序遍历,需要借助一个辅助链队列,广度优先遍历
void LevelOrder(BiTree t)
{
	LinkQueue Q;
	InitQueue(Q);
	BiTNode* p = t;
	EnQueue(Q, p);//树根入队
	while (!IsEmpty(Q))
	{
		DeQueue(Q, p);//出队当前结点并打印
		putchar(p->c);
		if (p->lchild)
		{
			EnQueue(Q, p->lchild);
		}
		if (p->rchild)
		{
			EnQueue(Q, p->rchild);
		}
	}
	printf("\n");
}

5.中序线索二叉树

线索二叉树在实际工业中没有应用场景,不重要,它其实就是认为空着的左右孩子指针,可以利用起来,指向对应的前驱或者后继。而前驱和后继这两个概念是线性表的,所以首先要把一棵二叉树按照中序遍历,遍历成一行,然后用数组,或者辅助队列存储,再次中序遍历这棵树,在遍历途中根据我们之前保存的辅助队列中的序列,指向相应的前驱和后继,这是一个比较简单粗暴的方法。
方法二就是采用递归,以中序为例,左根右,递归左子树,访问当前结点,递归右子树,并设置当前结点指针变量p,和指向前驱结点的指针变量pre。单步调试比较复杂,涉及函数堆栈,层层进栈出栈,如果不行,就先放弃。

5.参考资料

1.Markdown代码折叠

标签:结点,遍历,TNode,phead,二叉树,NULL,LinkNode,建树
From: https://www.cnblogs.com/paopaotangzu/p/18012608

相关文章

  • 力扣 递归 迭代 栈 广度 队列 之 226. 翻转二叉树
    给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。 示例1:输入:root=[4,2,7,1,3,6,9]输出:[4,7,2,9,6,3,1]示例2:输入:root=[2,1,3]输出:[2,3,1]示例3:输入:root=[]输出:[]栈/** *Definitionforabinarytreenode. *publicclassTreeNode......
  • 623 在二叉树中增加一行
    深度遍历,就是遍历:1.先要确定有几种情况,像这道题,深度为1,2就是最基本的情况,分为两种处理;2.根据不同情况,进行不同处理,不需要考虑后面递归的传递。3.确认传递的方式,如果函数返回的是指针,就需要left,right接住。完整代码:点击查看代码classSolution{public:TreeNode*ad......
  • 力扣递归 深度优先搜索 之 104. 二叉树的最大深度
    给定一个二叉树root,返回其最大深度。二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。 示例1: 输入:root=[3,9,20,null,null,15,7]输出:3示例2:输入:root=[1,null,2]输出:2/** *Definitionforabinarytreenode. *publicclassTre......
  • 力扣 145. 二叉树的后序遍历 递归 迭代
    递归/** *Definitionforabinarytreenode. *publicclassTreeNode{ *  intval; *  TreeNodeleft; *  TreeNoderight; *  TreeNode(){} *  TreeNode(intval){this.val=val;} *  TreeNode(intval,TreeNodelef......
  • 力扣 144. 二叉树的前序遍历 递归 迭代
    递归/** *Definitionforabinarytreenode. *publicclassTreeNode{ *  intval; *  TreeNodeleft; *  TreeNoderight; *  TreeNode(){} *  TreeNode(intval){this.val=val;} *  TreeNode(intval,TreeNodelef......
  • 力扣94. 二叉树的中序遍历 递归&迭代
    给定一个二叉树的根节点root,返回它的中序 遍历。 示例1:输入:root=[1,null,2,3]输出:[1,3,2]示例2:输入:root=[]输出:[]示例3:输入:root=[1]输出:[1] 递归/** *Definitionforabinarytreenode. *publicclassTreeNode{ *  intval;......
  • .NET(C#)遍历(for,foreach,while)字典(Dictionary)的几种方法
    ​ .NET(C#)中,Dictionary<TKey,TValue>是一种非常实用的集合类型,用于存储键值对的集合。遍历Dictionary的方法有多种,包括使用for循环、foreach循环和while循环。使用foreach循环是遍历Dictionary中所有键值对最常见和最简单的方法。for和while循环在遍历Dic......
  • 代码随想录算法训练营第十六天| 104.二叉树的最大深度 559.n叉树的最大深度 111.二
    104.二叉树的最大深度  题目链接:104.二叉树的最大深度-力扣(LeetCode)n叉树也一样思路:我的普通递归方法classSolution{public:intdepth(TreeNode*node,intd){intl=0,r=0;if(node->left==NULL&&node->right==NULL)returnd;if(node-......
  • (16/60)二叉树最大深度、最小深度、完全二叉树结点个数
    终于熬到了春节假~~有些手感了深度与高度深度是从根结点到叶结点的距离;高度是从叶结点到根结点的距离。深度从上往下(根为1);高度从下往上(叶为1)。二叉树最大深度leetcode:104.二叉树的最大深度后序递归法思路复杂度分析时间复杂度:O(N)。遍历了一遍。空间复杂度:和层数有关......
  • 005_二叉树
    1.用递归和非递归的方式实现二叉树的先序、中序、后序遍历先序遍历递归publicvoidpreOrderRecur(TreeNoderoot){if(root==null){return;}System.out.println(root.val+"");preOrderRecur(root.left);preOrderRecur(root.right);}......