数据结构与算法----树(中)

hey,我们继续上篇文章学习树。上篇文章,我们主要讲了树的一些基本概念、定义,抽象数据结构。今天,我们要学习它的数据结构,让我们开始学习吧。

树的存储结构:

一讲到存储结构,就会想到顺序存储与链式存储,让我们来回顾一下它们的概念。顺序存储,就是用一组连续的内存地址来存储数据元素,我们一般用一维数组来表示连续的内存地址。链式存储,用一块儿空闲的内存区域来存放数据元素。存放数据的地址不需要连续,通过元素中的指针域来表示逻辑关系。像之前我们学习的线性表,因为它是有唯一先驱、唯一后继。所以,顺序存储可以很好的表示出它的逻辑关系,链式存储也可很好得表示出它们的逻辑关系。而树这种数据结构,它有多棵子树,多个孩子结点,单是使用顺序存储、链式存储,是不能很好的显示出它们的逻辑关系的。我们需要通过集合这两种存储结构来存储树。

一、双亲表示法:

树虽然很多棵子树,但是子树的根结点是唯一确定的。所以,我们可以采用存储结点双亲的方式来存储树。

data是数据域,存放结点数据。parent是指针域,存放该结点的双亲结点的位置。我们来定义下树的双亲表示法结点的结构:

     /*树的双亲表示法的结点结构定义*/
     #define MAX_TREE_SIZE 100
    type int TElemType /*树结点的数据类型,目前暂定为int*/
    typedef struct PTNode  /*结点结构*/
    {
     TElemType data;  /*结点数据*/
    PTNode   parent;  /*双亲位置*/
   }PTNode;

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

,它所对应的双亲表示法应该为像下图这样子:

因为根结点没有双亲, 所以parent指针域为-1.

我们要想查询某结点的双亲,可以通过parent指针,快速查询。但是,如果需要查询孩子结点,那么只能整个遍历。

二、多重链表表示法:

因为树会有多棵子树,所以我们可以使用双链表来表示。就是说,每个结点有多个指针域,分别指向该结点子树的根结点。我们把这种表示法,称为多重链表表示法。但是,每个结点的度数是不同的,也就是每个结点的指针域个数是不同的。这里,我们有两种思路。

第一种:

让每个结点的度数都等于树的度数(树的度数,等于所有结点中度数最大的),其结构如下图:

\

其中,data存放结点数据,child1….childd存放该结点子树的根结点地址。

通过上图,大家可以发现,如果结点的度数相差太大,那么会出现很多没用指针域。

第二种:

我们在结点中,加一个计数器,专门记录该结点的度数。

其中data是数据域,存放结点的数据。degree是计数器,存放结点的度数。child1….childd是指针域,指向该结点子树的根结点。

这样一来,就不存在浪费指针域的情况了。可是,这种存储结构也是有弊端的。因为各个结点的结构不同,计数器难以维护,会造成时间上的弊端。

三、孩子表示法:

我们可以通过改进多重链表表示法,来设计出高效的存储结构。首先,我们把所有结点以顺序存储结构存放入一个一维数组中,这样就构成了一个线性表。我们再把每个结点的孩子结点以链式存储结构存入单链表中。如下图:

我们设计两种结点结构,一种是孩子链表的存储结构如下图:

其中child存放某结点的孩子结点在线性表中的数组下标,next指针域,指向下个孩子结点在单链表中的位置。

另一种结点结构,是线性表中表头结点,如下图:

data存放结点数据,firstchild指针域,指向第一个孩子结点在单链表中的位置。

/*树的孩子表示法结构定义*/
#define MAX_TREE_SIZE 100
typedef struct CTNode  /*孩子结点*/
{
     int child;
    struct CTNode  *next;

}*ChildPtr;

typedef struct   /*表头结构*/
{
   TElemType data;
  ChildPtr firstchild;
}CTBox;

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

以上是树的孩子表示法结构定义。对于孩子表示法,需要查找结点的孩子结点、兄弟结点,我们查看单链表就可以查到。对于,遍历整棵树,只需遍历表头线性表就可以。

四、孩子兄弟表示法:

以上三种表示法,都是从双亲、孩子的角度来思考的。我们换一下思路,从兄弟的角度来思考一下。如果树中的结点的左孩子存在,即是唯一的。如果右兄弟结点存在,即是唯一的。我们设置两个指针,分别指向该结点的第一个孩子和该结点的右兄弟。如下图:

data是数据域,存放结点的数据。firstchild、rightsib是指针域,分别指向结点的左孩子,右兄弟。

/*树的孩子表示法结构定义*/
typedef struct CSNode
{
    TElemType data;
   struct CSNode * firstchild,*rightsib;
}CSNode,*CSTree;

兄弟孩子表示法,对查找孩子、兄弟结点提供了方便。我们将上图整理一下:

上图其实就是一棵二叉树,我们可以通过二叉树的性质来操作树。关于二叉树,我们留在下一章讲。我们来复习一下,这章讲的知识。

归纳总结:

这章主要讲了树的几种存储结构,因为树不同与线性表,它的子树个数不确定。单单使用顺序存储、链式存储不能表示树的逻辑结构。所以,需要顺序存储与链式存储配合使用。

我们讲了双亲表示法:因为树中结点的双亲结点是唯一的,我们可以通过记录双亲的方法来表示树的存储结构。多重链表表示法:我们把结点的所有孩子结点都记录下来,这样的方法就是多重链表表示法。孩子表示法:将所有结点以顺序存储的方式放入一维数组中,再用单链表存储孩子结点。孩子兄弟表示法:记录左孩子、有兄弟的方法,来表示树的结构。

时间: 2024-10-06 15:01:11

数据结构与算法----树(中)的相关文章

数据结构与算法----树(下)

  大家好,今天继续学习树的数据结构.在上一章,我们讲树的孩子兄弟表示法时,提到了二叉树.今天,我们就来学习二叉树的相关性质.  一.二叉树定义: 二叉树(Binary Tree):n(n≥0)个结点的有限集合,该集合或者为空集(为空时,称为空树),或者由一个根结点.两棵互不相交.称为根结点的左子树.右子树的二叉树组成.(Note:大家注意了,我们在给出二叉树定义时,我们利用了递归概念.就是先给出二叉树概念,再用二叉树概念去解释二叉树.递归是一种很重要的方法,在数据结构中是很重要的,我们会在后面

数据结构与算法-树-二叉树与郝夫曼树

二叉树的遍历 二叉树的遍历指的是从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次. 二叉树的遍历方法: 前序遍历:规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树. 1 void PreOrderTraverse(BiTree T) 2 { 3 if(T == NULL) 4 return; 5 printf("%c",T->data);/*显示结点数据,可以更改为其他对结点操作*/ 6 PreOr

数据结构与算法->树

代码: 兵马未动,粮草先行 作者: 传说中的汽水枪 如有错误,请留言指正,欢迎一起探讨. 转载请注明出处. 目录 一. 2-3-4树的定义 二. 2-3-4树的可以得到几个推论 三. 2-3-4树数据结构定义 四. 2-3-4树节点相关方法定义与解释 五. 2-3-4树查找逻辑解释和代码实现 六. 2-3-4树插入逻辑解释和代码实现 一. 2-3-4树的定义

数据结构与算法之线性表

前言 上一篇<数据结构和算法之时间复杂度和空间复杂度>中介绍了时间复杂度的概念和常见的时间复杂度,并分别举例子进行了一一说明.这一篇主要介绍线性表. 线性表属于数据结构中逻辑结构中的线性结构.回忆一下,数据结构分为物理结构和逻辑结构,逻辑结构分为线性结构.几何结构.树形结构和图形结构四大结构.其中,线性表就属于线性结构.剩余的三大逻辑结构今后会一一介绍. 线性表 基本概念 线性表(List):由零个或多个数据元素组成的有限序列. 注意: 1.线性表是一个序列. 2.0个元素构成的线性表是空表.

数据结构和算法之时间复杂度和空间复杂度

前言 上一篇<数据结构和算法>中我介绍了数据结构的基本概念,也介绍了数据结构一般可以分为逻辑结构和物理结构.逻辑结构分为集合结构.线性结构.树形结构和图形结构.物理结构分为顺序存储结构和链式存储结构.并且也介绍了这些结构的特点.然后,又介绍了算法的概念和算法的5个基本特性,分别是输入.输出.有穷性.确定性和可行性.最后说阐述了一个好的算法需要遵守正确性.可读性.健壮性.时间效率高和存储量低.其实,实现效率和存储量就是时间复杂度和空间复杂度.本篇我们就围绕这两个"复杂度"展开

数据结构与算法---字符串(下)

前面两篇文章,分别介绍了字符串的概念.抽象数据类型.KMP模式匹配算法.这篇文章,我们来学习字符串的一些常用算法. 字符串的相关操作算法 StrAssign: /* 功能:生成一个其值等于Chars的串T */ Status StrAssign(String T, char *chars) { int i; if (chars[0] > MAXSIZE) return ERROR; T[0] = chars[0]; //chars[0]存放的是字符chars的长度 T[0]存放着的是串T的长度

再也不怕数据结构和算法之开篇

为什么要学习算法和数据结构 算法和数据结构是程序员的基本内功,基本内功修炼不好,以后修炼一些招式,如设计模式.架构,新的技术热点如区块链,新的技术语言go等,都会感觉非常吃力. 喜欢看武侠小说的知道,张无忌正是因为内功精纯,再加乾坤大挪移加持,学习任何武功招式都如探囊取物,短时间内即可融汇贯通.程序员的内功-数据结构和算法,乾坤大挪移-设计模式. 说实话,作为一个渣渣程序员,非CS专业出身,基础本就比较薄弱.正好借着写文章的机会,把数据结构和算法及设计模式都系统的学习一遍,并且把这些以比较容易理

数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] 树 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树 二叉树的创建,关系建立 二叉树的创建,关系建立2 三叉链表法 双亲链表: 二叉树的遍历 遍历的分析PPT 计算二叉树中叶子节点的数目:使用全局变量计数器 计算二叉树中叶子节点的数目:不使用全局变量计数器 无论是先序遍历,中序遍历,后序遍历,求叶子的数字都不变;因为本质都是一样的,任何一个节点都会遍历3趟 求二叉树的高度 二叉树的拷

python数据结构与算法 38 分析树

分析树 树的结构完成以后,该是时候看看它能做点什么实事儿了.这一节里,我们研究一下分析树.分析树能够用于真实世界的结构表示,象语法或数学表达式一类的. 图1 一个简单语句的分析树 图1所示是一个简单语句的层级结构,把语句表示为树结构可以让我们用子树来分析句子的组成部分. 图2 ((7+3)?(5?2))的分析树 我们也可以把数学表达式如((7+3)?(5?2))表示为分析树,如图2.此前我们研究过完全括号表达式,这个表达式表达了什么呢?我们知道乘法的优先级比加减要高,但因为括号的关系,在做乘法之