✅简介:与大家一起加油,希望文章能够帮助各位!!!!
💬保持学习、保持热爱、认真分享、一起进步!!!
一、二叉树的概括
二叉树可以分为链式二叉树和顺序存储二叉树。
链式二叉树是一种常见的二叉树存储结构,它使用节点和指针来表示二叉树的结构。每个节点包含一个数据元素以及指向其左子树和右子树的指针。节点通过指针连接在一起,形成了一个树结构。链式二叉树灵活性较高,可以动态地进行插入和删除操作,但访问节点的效率稍低。
顺序存储二叉树是使用一维数组来存储二叉树结构的一种表示方法。将二叉树中每个节点的数据元素按照层次顺序依次存储在数组中,用于子节点和父节点之间的关联。通过计算数组下标与树中节点之间的关系,可以在一维数组中有效地表示二叉树的结构。顺序存储二叉树的主要优点是访问节点的效率高,但其缺点是不灵活,无法动态地进行插入和删除操作。
这两种存储方式各有优缺点。
定义了一个结构体类型BiNode
,包含节点的值、左子树和右子树三个成员变量;同时,定义了指向结构体类型BiNode
的指针类型BiTree
。
二、顺序二叉树的遍历
顺序存储二叉树在进行查找操作时,可以通过数组下标来定位节点。具体地说,对于数组中索引为
i
的节点,其左子节点的索引为2*i+1
,右子节点的索引为2*i+2
,而其父节点的索引为(i-1)/2
。而遍历的话只需要使用循环即可。
三、链式二叉树
1.链式二叉树的定义
定义了一个结构体类型
BiNode
,包含节点的值、左子树和右子树三个成员变量;同时,定义了指向结构体类型BiNode
的指针类型BiTree
。代码如下:下面结构体里面的value不一定非要是int类型,可以是任意类型。
typedef struct _hh{
int value;
struct _hh *lchild,*rchild;
}BiNode,*BiTree;
2.二叉树的遍历方式
2.1递归
2.1.1递归——先序遍历
void PreOrderTraverse(BiTree p)
{
//如果p指针为空则结束
if(!p);
else{
//先输出根节点
printf("%d\t",p->value);
//接着调用自身,去遍历左子树
PreOrderTraverse(p->lchild);
//等待该层的左子树遍历完全,再调用自身遍历右子树
PreOrderTraverse(p->rchild);
}
}
2.1.2递归——中序遍历
void PreOrderTraverse(BiTree p)
{
//如果p指针为空则结束
if(!p);
else{
//先调用自身,去遍历左子树
PreOrderTraverse(p->lchild);
//等待最后一层左子树为NULL,接着输出上层的根节点
printf("%d\t",p->value);
//再调用自身遍历右子树,待右子树遍历完全返回上一级
PreOrderTraverse(p->rchild);
}
}
2.1.3递归——后序遍历
void PostOrderTraverse(BiTree p)
{
// 如果当前节点不为空
if (p != NULL) {
// 后序遍历左子树
PostOrderTraverse(p->lchild); // 递归调用,遍历当前节点的左子树
// 后序遍历右子树
PostOrderTraverse(p->rchild); // 递归调用,遍历当前节点的右子树
// 输出当前节点的值
printf("%d\t", p->value);
}
}
2.2非递归——中序遍历
通过栈的辅助,我们可以模拟递归的方式实现后序遍历的非递归版本。
栈——定义
下面代码段定义了一个包含数据和指向下一个节点的链栈结构体,通过
StackNode
和LinkStack
两个类型别名,使得使用栈节点和栈指针更加方便和简洁。
typedef struct __StackNode{
BiTree data;
struct __StackNode *next;
}StackNode, *LinkStack;
2.2.1栈的初始化
void InitStack(LinkStack* p)
{
*p=NULL;
}
2.2.2入栈
bool Push(LinkStack* p,BiTree data)
{
LinkStack q=(StackNode*)malloc(sizeof(StackNode));
if(!q) return false;
q->data=data;
q->next=*p;
*p=q;
return true;
}
2.2.3出栈
bool Pop(LinkStack* p,BiTree* data)
{
if(!*p) return false;
LinkStack q=*p;
*data=(*p)->data;
*p=(*p)->next;
free(q);
return true;
}
2.2.4中序遍历
void InOrder_unrec(BiTree T)
{
StackNode s;
LinkStack q;
q=&s;
InitStack(&q);
// 当T不为空或栈不为空时循环
while( T || q!=NULL){
//如果T不为空
if(T){
//栈顶元素始终都是T的双亲节点,直到T为叶子(叶子->lchild=NULL)
Push(&q,T);
T=T->lchild;
}else{
//T为空进入else,现在准备出栈,把栈顶元素弹出T,此时变成了原T的双亲
Pop(&q,&T);
//此时T的左孩子为空,根据in-oder规则,输出根节点T,然后再以相同的方式遍历他的右孩子
printf("%d ",T->value);
//输出根节点后,遍历右孩子
T=T->rchild;
}
}
}
总结
对于二叉树的遍历问题,递归方式通常更简洁,可读性更好,更容易去理解;非递归方式则具有更小的空间开销和更高的效率。具体使用哪种方式可以根据实际需求、问题规模和性能要求来选择。
以后也会持续更新!!!
成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。
以上均是个人的理解,如果有不对的地方请各位大佬帮忙斧正!