数据结构——线索二叉树、树和森林的自习作业

数据结构让交自学笔记,我就写在博客里吧


1)什么是线索二叉树以及线索的作用

指向前驱和后继的指针称为线索,相应的二叉树就称为线索二叉树。

线索的作用:因为空地址存放指向结点在某种遍历次序下的前驱和后继结点的地址,所以可以找到一个结点的前驱后继,无需再遍历一次。

二叉树的线索化

在这里插入图片描述
如图,把这棵树按照中序遍历,将所有空指针域rchid 改为指向它的后继结点。例如,H的后继结点为D。

2)二叉树的线索化

为解决明确某一结点lchild是指向左孩子还是前驱,rchild是指向右孩子还是后继的问题,对每个结点再设置两个标志域ltag和rtag,存放布尔型的0或1变量。(如表
在这里插入图片描述
应用起来如下图:
在这里插入图片描述
线索化的过程就是在遍历的过程中修改空指针的过程。

3)线索二叉树结构的实现和中序遍历线索化

二叉树的线索存储结构定义代码如下:

typedef char TElemType;                     
 
typedef enum { Link, Thread } PointerTag;       //Link==0,表示指向左右孩子指针
                                                //Thread==1,表示指向前驱或后继的线索
//二叉树线索结点存储结构
typedef struct BiThrNode {
  TElemType data;                       //结点数据
  struct BiThrNode *lchild, *rchild;    //左右孩子指针
  PointerTag LTag;                      
  PointerTag RTag;                      //左右标志
}BiThrNode, *BiThrTree;

中序遍历线索化的顶柜函数代码如下:

BiThrTree pre;//全局变量,始终指向刚刚访问过的结点
void InThreading(BiThrTree B,BiThrTree *pre) {
  if(B){ 
  InThreading(B->lchild,pre);   
  if(!B->lchild){                   //没有左孩子 
    B->LTag = Thread;               //修改标志域为前驱线索
    B->lchild = *pre;               //左孩子指向前驱结点
  }
 
  if(!(*pre)->rchild){              //没有右孩子
    (*pre)->RTag = Thread;          //修改标志域为后继线索
    (*pre)->rchild = B;             //前驱右孩子指向当前结点
  }
  pre = B;                         //保持pre指向p的前驱
  InThreading(B->rchild);
}
}

4)树的存储结构,如何实现,各自的特点?

树的存储结构主要有:双亲表示法,孩子表示法,双亲孩子表示法和孩子兄弟表示法。

- 双亲表示法:

  • 实现: 定义结构数组存放树的结点,每个结点含两个域:

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

  • 特点 :找双亲容易,找孩子难。

  • 类型定义:

typedef struct PTNode  //结点结构
{
	TElemType data;
	int parent;        //双亲位置域
}PTNode;

#define MAX_TREE_SIZE 100
typedef struct                   //树结构
{
	PTNode nodes[MAX_TREE_SIZE];
	int r, n;                    //根结点的位置和结点个数
}PTree;

- 孩子链表

  • 实现: 把每个结点的孩子结点排列起来,看成是一个线性表,用单链表存储,则n个结点有n个孩子链表(叶子的孩子链表为空表)。而n个头指针又组成一个线性表,用顺序表(含n个元素的结构数组)存储。
  • 类型定义
typedef struct CTNode
{
	int child;
	struct CTNode *next;
}*ChildPtr;
//孩子结点结构

typedef struct
{
	TElemType data;
	ChildPtr firstchild;     //孩子链表的头指针
}CTBox;
//双亲结点结构

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

- 双亲孩子表示法

  • 在孩子链表的基础上,为了解决找双亲难得问题,可以在双亲结点里增设一个指针域,存放双亲结点的下标——带双亲的孩子链表。

- 孩子兄弟表示法

  • 实现: 用二叉链表作树的存储结构,链表中每个结点的两个指针域分别指向其第一个孩子结点和下一个兄弟结点
  • 类型定义
typedef struct CSNode
{
	ElemType daya;
	struct CSNode *firstchild, *nextsibling;
}CSNode,*CSTree;

  • 特点: 找孩子容易,找孩子的兄弟容易,找双亲难。
    可以给每个结点增设一个指针域,从而解决找双亲难的问题

5)如何将树转化为二叉树

  • 1,加线:树中所有相邻兄弟之间加一条连线
  • 2,去线:树中的每个节点,只保留其与第一个孩子节点之间的连线,删去其与其他孩子节点之间的连线
  • 3,层次调整:以树根节点为轴心,将整棵树顺时针旋转一定角度,使其更直观 注意:和树对应的二叉树,其左,右子树的概念已经变为:左是孩子,右是兄弟。在这里插入图片描述

6)如何将森林转化为二叉树

  • 将森林中的每棵树转换成相应的二叉树
  • 第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根节点作为前一棵二叉树根节点的右孩子,当所有二叉树连在一起后,所得到的二叉树就是由森林转换得到的二叉树。
    在这里插入图片描述

7)二叉树转化为树

  • 加线:若某结点的左孩子结点存在,则将这个左孩子的n个右孩子结点都作为此结点的孩子。则将该结点与这些右孩子结点用线连接起来。
  • 去线:删除原二叉树中所有结点与其右孩子结点的连线。
  • 层次分明:是指结构层次分明。

在这里插入图片描述

8)二叉树转换为森林

  • 从根节点开始,若右孩子存在,则把与右孩子结点的连线删除,再查看分离后的二叉树,若右孩子存在,则连线删除…知道所有右孩子连线都删除为止,得到分离的二叉树。
  • 再将每棵分离后的二叉树转换为树即可。

在这里插入图片描述

9)树的遍历

树的遍历分为两种方式

  • 一种是先根遍历树,即先访问树的根节点,然后依次先根遍历根的每棵子树。
  • 另一种是后根遍历,即先依次后根遍历每棵子树,然后再访问根结点。

10)森林的遍历

  • 前序遍历:先访问森林中的第一棵树的根节点,再一次先根遍历根的每棵树,再依次用同样方式遍历除去第一棵树的剩余树构成的森林。
  • 后序遍历:是先访问森林中第一棵树,后根遍历的方式遍历每棵树,然后访问根节点,再依次同样方式遍历除去第一棵树的剩余树构成的森林。

11)二叉树、树和森林的遍历关系?

树的先根遍历和后根遍历,森林的前序遍历和后续遍历完全可以借用二叉树的前序遍历和中序遍历的算法实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值