浅析树(附常用算法及JAVA实现)

一、树的定义

树(Tree)是n(n≥0)个结点的有限集。n = 0时称为空树。在任意一颗非空树中:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T~1~、T~2~、……、T~m~,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。

1.当n>0时,每棵树的根结点是唯一的;
2.子树个数没有限制,但一定是唯一的。

二、相关概念

1.结点:一个数据元素以及若干指向子树的分支,度(结点拥有的子树数)为0的节点称为叶结点或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也成为内部结点。

树的度取树内各结点度的最大值。

2.结点关系:结点的子树的根称为该结点的孩子,则该结点为孩子的双亲,同一个双亲的孩子之间互称兄弟。结点的祖先是从跟到该结点所经分支上的所有结点,反之,以某结点为根的子树中的任一结点都称为该结点的子孙。

3.结点的层次:根为第一层,往下依次加一。树中结点的最大层次称为树的深度或高度。

4.森林:森林是m(m≥0)棵互不相交的树的集合。对树中每个结点而言,其子树的集合即为森林。

三、树的结构

1.双亲表示法:

以一串连续空间存储树的结点,在每个结点中设置一个指向双亲结点的指针,树的结构就可表示为结点数组和根结点位置组成的结构体;

结构代码如下:

#define MAX_TREE_SIZE 100

typedef int TElemType; /*树的结点数据类型,设为int*/

typedef struct PTNode  /*结点数组*/
{
    TElemType data;  /*结点数据*/

    int parent;  /*双亲位置*/
}PTNode;

typedef struct  /*树结构*/
{
    PTNode nodes[MAX_TREE_SIZE];  /*结点数组*/

    int r, n;      /*根的位置和结点数*/
}

2.孩子表示法:

每个结点有多个指针,指向其子树的根结点,这种表示法也叫多重链表表示法。具体方法是,将每个结点的孩子结点排列,以单链表存储,n个头指针组成线性表结构顺序存储,也可以在头结点加入指向双亲的指针,便于查找。

孩子表示法的结构代码如下:

#define MAX_TREE_SIZE 100

typedef struct CTNode      /*孩子结点*/
{
    int child;
    struct CTNode *next;
}*ChildPtr;

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

    int parent;               /*双亲位置*/
}CTBox;

typedef struct                /*树结构*/
{
    CTBox nodes[MAX_TREE_SIZE];
    int r,n;                 
}CTree;

3.孩子兄弟表示法:

在一个结点中设置两个指针,分别指向左孩子和右兄弟。

结构定义如下:

typedef struct CSNode
{
    TElemType data;

    struct CSNode *firstchild,*rightsib;
}CSNode,*CSTree;

四、二叉树

在孩子兄弟表示法中,可以看到,一棵树可以转化为二叉树。二叉树(Binary Tree)是n(n≥0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。

二叉树的特点:

  • 每个结点最多有两棵子树;
  • 左子树和右子树有顺序,不可颠倒。

二叉树的分类:

  • 斜树:所有结点只有左子树的二叉树叫左斜树,所有结点只有右子树的二叉树叫右斜树;
  • 满二叉树:在一棵二叉树中,如果所有结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树;
  • 完全二叉树:对一颗具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。

二叉树的性质:

  • 在二叉树的第i层上至多有2^i-1^个结点(i≥1);
  • 深度为k的二叉树至多有2^k^-1个结点(k≥1);
  • 叶子结点数为度为2的结点数加一;
  • n个结点的完全二叉树深度为(lgn+1);

二叉树的结构:

每个节点包括一个数据域、左指针和右指针。

二叉树的结构代码如下:

typedef struct BiTNode    /*节点结构*/
{
    TElemType data;
    struct BiTNode *lchild, *rchild;
}BiTNode,*BiTNode;

五、相关算法(源码内容)

1.二叉树遍历:

  • 先序遍历:
graph LR
-->
-->
  • 中序遍历:
graph LR
-->
-->
  • 后序遍历:
graph LR
-->
-->
  • 层序遍历:
graph LR
-->
-->
-->
-->

2.赫夫曼树:

构造方法:

  • 将每个字符看做一棵树,按权值从小到大排列为集合T;
  • 取最小权值的两棵树组合成一棵树,根结点的权值为两权值之和,在T中去掉这两棵树,换为根结点,重新排列。
  • 重复第二步,直到组合完成。

赫夫曼解码需要编码为前缀编码,可规定左边全为0,右边全为1。

赫夫曼结点结构如下:

class HuffNode {
    private Character data;
    private HuffNode lchild;
    private HuffNode Rchild;
    private HuffNode parent;   /*父结点*/
    private int weight;        /*结点权重*/
    private int Flag;          /*Flag为0表示未插入树中,为1表示已插入*/
    private String code;       /*结点的赫夫曼码*/
}

3.二叉排序树:

特点:

  • 若左子树不为空,左子树上所有的值小于其根结点的值;
  • 若右子树不为空,右子树上所有的值大于其根结点的值;
  • 它的左、右子树也分别为二叉排序树。

最好构建平衡二叉树,提高查找效率。

4.平衡二叉树(AVL树):

平衡二叉树是一种二叉排序树,其中每一个结点的左子树和右子树的高度至多等于1。

最小不平衡子树:

距离插入结点最近的,且平衡因子的绝对值大于1的结点为根的子树,称为最小不平衡子树。

平衡二叉树构建方法:

在构建二叉排序树的过程中,每当插入一个结点时,先检查是否破坏了树的平衡性,若是,则找出最小不平衡子树,调整各结点位置,进行相应的旋转,使之成为新的平衡二叉树。

平衡二叉树结点结构如下:

class AVLNode{
        private int data;
        private AVLNode lchild;
        private AVLNode rchild;
        private int height;                         //结点高度
}

5.红黑树:

红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树增加了如下的额外要求:

  • 节点是红色或黑色。
  • 根节点是黑色。
  • 每个叶节点(NIL节点,空节点)是黑色的。
  • 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  • 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

红黑树的结点结构:

class Node{
    private Key key;             //键
    private Value value;         //值
    private Node left, right;    //指向子树的链接:左子树和右子树.
    private int N;               //以该节点为根的子树中的结点总数
    boolean color;               //结点颜色,红或黑
 }

附上各个算法代码链接:

树相关算法链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值