24考研数据结构-树与森林

5.4树、森林

在这里插入图片描述

5.4.1树的存储结构

1. 双亲表示法(顺序存储):

在这里插入图片描述

每个结点中保存指向双亲的指针
数据域:存放结点本身信息。
双亲域:指示本结点的双亲结点在数组中的位置。

#define MAX_TREE_SIZE 100  //树中最多结点数

typedef struct{      //树的结点定义
   ElemType data; 
   int parent;      //双亲位置域
}PTNode;

typedef struct{                   //树的类型定义
   PTNode nodes[MAX_TREE_SIZE];   //双亲表示
   int n;                         //结点数
}PTree;


基本操作:

  • 增:新增数据元素,无需按逻辑上的次序存储,只要在最后增加并且写上其父节点(需要更改结点数n)
  • 删(叶子结点):① 将伪指针域设置为-1;②用后面的数据填补(不会中间出现空数据);(需要更改结点数n)
  • 查询:①优点-查指定结点的双亲很方便;②缺点-查指定结点的孩子只能从头遍历,空数据导致遍历更慢;
  • 所以删除时用②用后面的数据填补(不会中间出现空数据);(需要更改结点数n)这个方法更好
  • 求双亲很方便,但是求结点的孩子需要遍历整个结构

2. 孩子表示法(顺序+链式)

孩子链表:把每个结点的孩子结点排列起来,看成是一个线性表,用单链表存储,则n个结点有n个孩子链表(叶子的孩子链表为空表)。而n个头结点又组成一个线性表,用顺序表(含n个元素的结构数组)存储
在这里插入图片描述
问题在于:找孩子方便,找双亲不方便,需要遍历整个结构(n个结点的孩子链表指针域指向的n个孩子链表)

struct CTNode{
   int child;    //孩子结点在数组中的位置
   struct CTNode *next;    // 下一个孩子
};

typedef struct{
   ElemType data;
   struct CTNode *firstChild;    // 第一个孩子
}CTBox;

typedef struct{
   CTBox nodes[MAX_TREE_SIZE];
   int n, r;   // 结点数和根的位置
}CTree;


3. 孩子兄弟表示法(链式)

第一个孩子与右兄弟
特点:

  1. 最大的优点是实现树转换成二叉树和相互转换
  2. 易于查找结点的孩子
  3. 缺点是从当前结点查找双亲很麻烦,可以为每个结点设置一个parent指针指向父结点
  4. 孩子表示法存储的树,在物理上是二叉树

在这里插入图片描述

typedef struct CSNode{
   ElemType data;                               //数据域
   struct CSNode *firstchild, *nextsibling;     //第一个孩子和右兄弟指针, *firstchild 看作左指针,*nextsibling看作右指针
}CSNode. *CSTree;


5.4.2树、森林与二叉树的转换

本质:森林中各个树的根结点之间视为兄弟关系

在这里插入图片描述
在这里插入图片描述

5.4.3树、森林的遍历

在这里插入图片描述
在这里插入图片描述

1. 树的遍历

先根后根都是深度优先,层次是广度优先遍历

先根遍历
  • 若树非空,先访问根结点,再依次对每棵子树进行先根遍历;(与对应二叉树的先序遍历序列相同树的深度优先遍历
void PreOrder(TreeNode *R){
   if(R!=NULL){
      visit(R);    //访问根节点
      while(R还有下一个子树T)
         PreOrder(T);      //先跟遍历下一个子树
   }
}


在这里插入图片描述

后根遍历

树的深度优先遍历

  • 若树非空,先依次对每棵子树进行后根遍历,最后再返回根节点;(与对应二叉树的中序遍历序列相同但是直接看的话还是后序遍历序列,不转化成二叉树来看的话就直接用后序遍历求解

在这里插入图片描述

void PostOrder(TreeNode *R){
   if(R!=NULL){
      while(R还有下一个子树T)
         PostOrder(T);      //后跟遍历下一个子树
      visit(R);    //访问根节点
   }
}


层序遍历(队列实现)

广度优先遍历

若树非空,则根结点入队;
若队列非空,队头元素出队并访问,同时将该元素的孩子依次入队;
重复以上操作直至队尾为空;

2. 森林的遍历

先序遍历:等同于依次对各个树进行先根遍历;也可以先转换成与之对应的二叉树,对二叉树进行先序遍历;
中序遍历:等同于依次对各个树进行后根遍历;也可以先转换成与之对应的二叉树,对二叉树进行中序遍历;

数据结构:树和森林的存储结构与遍历方式

树和森林是在计算机科学中常见的非线性数据结构,它们在组织和存储数据方面具有重要的作用。本文将介绍树和森林的存储结构,并详细解释它们的遍历方式。

树的存储结构

树是一种由节点和边构成的数据结构,其中有一个特殊的节点被称为根节点,其他节点可以分层次地连接在根节点下面。每个节点可以有零个或多个子节点,而每个子节点可以继续拥有自己的子节点,形成了一个层次化的结构。

树的存储结构:链式存储结构

树的链式存储结构是通过节点之间的指针连接来表示树的。每个节点都包含一个数据域和多个指向子节点的指针。根节点没有父节点,而其他节点有且仅有一个父节点。

struct TreeNode {
    int data;
    TreeNode* parent;
    vector<TreeNode*> children;
};
树的存储结构:数组存储结构

树的数组存储结构是通过数组来表示树的。将树的节点按层次遍历的顺序依次存储在数组中,通过数组下标可以找到节点之间的关系。

struct TreeNode {
    int data;
};

TreeNode tree[MAX_SIZE];

森林的存储结构

森林是由多个不相交的树组成的集合,每个树都是独立的。每个树的根节点都不属于其他任何树的子节点,因此它们是相互独立的树结构。

森林的存储结构:链式存储结构

森林的链式存储结构是通过多个树的链式存储结构组合在一起构成的。每个树都是一个独立的链式存储结构。

vector<TreeNode*> forest;
森林的存储结构:数组存储结构

森林的数组存储结构是通过多个数组存储结构组合在一起构成的。每个数组存储结构表示一棵树。

TreeNode forest[MAX_TREES][MAX_SIZE];

树和森林的遍历方式

树和森林的遍历方式是指访问树或森林中所有节点的方法。常见的树和森林遍历方式有三种:前序遍历、中序遍历和后序遍历。这三种遍历方式是基于节点的访问顺序来定义的。

前序遍历

前序遍历是指先访问根节点,然后按照从左到右的顺序依次访问每个子节点的遍历方式。在树和森林的存储结构中,前序遍历可以通过递归或栈的方式来实现。

中序遍历

中序遍历是指先按照从左到右的顺序依次访问每个子节点,然后再访问根节点的遍历方式。在树和森林的存储结构中,中序遍历可以通过递归或栈的方式来实现。

后序遍历

后序遍历是指先按照从左到右的顺序依次访问每个子节点,然后再访问根节点的遍历方式。在树和森林的存储结构中,后序遍历可以通过递归或栈的方式来实现。

结论

树和森林是非常重要的数据结构,它们在计算机科学中有着广泛的应用。通过链式存储结构和数组存储结构,我们可以灵活地表示树和森林,并实现它们的遍历方式。掌握树和森林的存储结构和遍历方式,对于学习和理解更复杂的数据结构和算法有着重要的意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VengaZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值