自己动手写数据结构(5)——树

自己动手写数据结构总目录

具体内容:

该文章的源代码仓库为:

上一节介绍了二叉树,这一节简要介绍一下树。我们知道二叉树,每个节点至多有2个孩子,而普通的树则没有了这种限制,每个节点可以有多个孩子。

一、树中的相关定义

  • 1.度:节点拥有的孩子个数是节点的度,树的度为树中节点度的最大值。
  • 2.高度:树的最大层次为树的高度或深度。
  • 3.森林:m(m≥0)可互不相交的树的集合。

二、树的存储结构

树有三种存储结构:双亲表示法、孩子表示法、孩子兄弟表示法

1.双亲表示法

线性表存储树,每个节点必须保存其双亲在数组中的下标,也可为了访问方便保存其第一个孩子的下标、右兄弟下标等。如下图所示(来自《大话数据结构》)的树,在这里插入图片描述
每个节点保存双亲下标和右兄弟下标,用双亲表示法表示为:
在这里插入图片描述

  • 优点: 数据结构简单,访问双亲方便,如果存储了第一个孩子节点或右兄弟等信息,则访问这些信息也会比较方便。
  • 缺点: 获取所有的孩子很困难,且如果每个节点存储类似第一个孩子节点或右兄弟等信息,很浪费存储空间(这些信息属于冗余信息)。且这种结构,遍历树很不方便。

2.孩子表示法

链式结构存储树,即每个节点有多个指针域,每个指针指向一颗子树的根节点。但由于每个节点的孩子不同,指针的个数就不同,对此,解决办法是,把每个结点的孩子排列起来,以单链表形式存储,则n个节点有n个孩子链表,如果是叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存在一个一维数组中,上面的树用孩子表示法如下所示:
在这里插入图片描述
但此时,找节点的双亲仍然不方便,故可以在每个头节点中,存储其双亲信息。如下所示:
孩子表示法

  • 优点: 在头结点中增加双亲定义后,查找双亲、孩子都很方便
  • 缺点: 查找兄弟节点不方便

3.孩子兄弟表示法

任意一棵树,它的节点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,每个节点设置两个指针,分别指向该节点的第一个孩子和该节点的右兄弟。对于最上面的那棵树,用此类方法表示为:
在这里插入图片描述
**此种方式最大的好处是将树变成了一颗二叉树。**将上图中的节点位置整理一下,得到下图:
在这里插入图片描述

  • 优点: 将树转换成一颗二叉树,可以对其应用二叉树的一些特性,而且这种方式可以很方便地获取节点的孩子(先找到节点的第一个孩子节点a,再找a的兄弟b,再找b的兄弟c,如此不断重复),也可以很方便地获取节点的兄弟。
  • 缺点: 查找双亲不方便,但这个可以通过二叉树的一些其他结构来弥补(如将二叉树线索化)。

三、赫夫曼树

1.定义

用n个结点构建一棵树时,如果构建的这棵树的带权路径长度和最小,那称这棵树为“最优二叉树”,也叫赫夫曼树。其特点是:权重越大的结点距根节点越近

2.赫夫曼树的构建

赫夫曼树的构建过程为:

  • (1)有n个节点组成的集合s,从集合s中,取出权重最小的两个节点,将其作为一个二叉树的左子树和右子树,其根节点的权值为两个节点的和。
  • (2)将(1)中生成的根节点放入到s中,重复执行(1)过程,直到s中的元素全部取出。
    整个过程如下图所示(图片来源于):
    赫夫曼树的生成过程

3.赫夫曼树代码

我这里基于二叉树的二叉树的实现,来构建二叉树。这里只用Java实现,C++类似,我这里就不再实现了。
因为赫夫曼树中经常需要涉及到节点的比较,所以我们首先定义一个基础数据类型,该基础数据类型中包含该数据的id和权重,且包含一个比较函数,用于比较两个数据的大小。

  • 数据基类
public class HuffBaseType{
   
    protected String id;//节点ID
    protected int weight;//权重

    public HuffBaseType
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MeteorChenBo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值