java树_Java树

树(tree)是一种抽象数据类型(ADT),用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点通过连接它们的边组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

cb6887331bed

树1

①、节点:上图的圆圈,比如A,B,C等都是表示节点。节点一般代表一些实体,在java面向对象编程中,节点一般代表对象。

②、边:连接节点的线称为边,边表示节点的关联关系。一般从一个节点到另一个节点的唯一方法就是沿着一条顺着有边的道路前进。在Java当中通常表示引用。

树的常用术语

cb6887331bed

树2

①、路径:顺着节点的边从一个节点走到另一个节点,所经过的节点的顺序排列就称为“路径”。

②、根:树顶端的节点称为根。一棵树只有一个根,如果要把一个节点和边的集合称为树,那么从根到其他任何一个节点都必须有且只有一条路径。A是根节点。

③、父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;B是D的父节点。

④、子节点:一个节点含有的子树的根节点称为该节点的子节点;D是B的子节点。

⑤、兄弟节点:具有相同父节点的节点互称为兄弟节点;比如上图的D和E就互称为兄弟节点。

⑥、叶节点:没有子节点的节点称为叶节点,也叫叶子节点,比如上图的H、E、F、G都是叶子

⑦、子树:每个节点都可以作为子树的根,它和它所有的子节点、子节点的子节点等都包含在子树中。

⑧、节点的层次:从根开始定义,根为第一层,根的子节点为第二层,以此类推。

⑨、深度:对于任意节点n,n的深度为从根到n的唯一路径长

⑩、高度:对于任意节点n,n的高度为从n到一片树叶的最长路径长

cb6887331bed

树的高度与深度

高度

如上图,K节点在树的底层,是一个叶子节点,则一般定义为K的高度在最低为1,以此类推,O的高度也是为1,P的节点也是为1。M节点是叶子节点O的父节点,从下往上数,M节点高度为2。那么G节点的高度是多少呢?从G-L的高度为2,从G-M-O节点高度为3,到底G节点高度为多少呢,正确答案是3,要取最长。

子节点的个数,如E的度是1,A的度是2

二叉树(Binary Tree)

树的每个节点最多只能有两个子节点,这种树就叫做二叉树。

上图的“树1”B节点有DEF三个子节点,就不是二叉树,称为多路树;而“树2”每个节点最多只有两个节点,是二叉树,并且二叉树的子节点称为“左子节点”和“右子节点”

如果我们给二叉树加一个额外的条件,就可以得到一种被称作二叉搜索树(binary search tree)的特殊二叉树。

二叉树的遍历

四种遍历的思想为:

前序遍历:根结点 ---> 左子树 ---> 右子树

中序遍历:左子树--->根结点 ---> 右子树

后序遍历:左子树 ---> 右子树 ---> 根结点

层次遍历:仅仅需按层次遍历就可以

比如求以下二叉树的各种遍历:

cb6887331bed

二叉树的遍历

前序遍历:1 2  4 5 7 8 3 6

中序遍历:4 2 7 5 8 1 3 6

后序遍历:4 7 8 5 2 6 3 1

层次遍历:1  2  3  4  5  6  7  8

二叉搜索树(Binary Search Tree)

二叉搜索树要求:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

cb6887331bed

二叉搜索树

平衡二叉树(Balance Binary Tree)

学习过了二叉查找树,想必大家有遇到一个问题。例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况。有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本。而只有建立的树如图2,才能够最大地体现二叉树的优点。

cb6887331bed

cb6887331bed

平衡之意,如天平,即两边的分量大约相同。如定义,假如一棵树的左右子树的高度之差超过1,如左子树的树高为2,右子树的树高为0,子树树高差的绝对值为2就打破了这个平衡。如依次插入1,2,3三个结点(如下图)后,根结点的右子树树高减去左子树树高为2,树就失去了平衡。

cb6887331bed

最小失衡子树:在新插入的结点向上查找,以第一个平衡因子的绝对值超过1的结点为根的子树称为最小不平衡子树。也就是说,一棵失衡的树,是有可能有多棵子树同时失衡的,如下。而这个时候,我们只要调整最小的不平衡子树,就能够将不平衡的树调整为平衡的树。

在图7中。2结点(左子树树高-右子树树高)的绝对值=2。同理,3结点的平衡因子也为2.此时同时存在了两棵不平衡子树,而以3为根的树是最小的不平衡子树。我们只要将其以3为中心,将最小不平衡树向左旋转,即可得到平衡二叉树,如图8。具体方法后续讲解。

cb6887331bed

哈夫曼树(Huffman Tree)

理解哈夫曼数首先要理解四个概念:

1.什么是路径

在一棵树中,从一个结点到另一个结点所经过的所有结点,被我们称为两个结点之间的路径。

cb6887331bed

A到H的路径

上图中A到H的路径就是A->B->D->H

2.路径长度

从一个结点到另一个结点所经过的“边”的数量,被我们称为两个结点之间的路径长度。

cb6887331bed

路径长度

如上图中A到H的路径长度为3。

3.结点的带权路径长度

树的每一个结点,都可以拥有自己的“权重”(Weight),权重在不同的算法当中可以起到不同的作用。结点的带权路径长度,是指树的根结点到该结点的路径长度,和该结点权重的乘积。

cb6887331bed

带权路径长度

如上图结点H的带权路径长度是 3 X 3 = 9。

4.树的带权路径长度

在一棵树中,所有叶子结点的带权路径长度之和,被称为树的带权路径长度,也被简称为WPL。以上图为例,树的带权路径长度为:

3*3+6*3+1*2+4*2+8*2=53

刚才我们了解了树的带权路径长度(WPL),而哈夫曼树(Huffman Tree)是在叶子结点和权重确定的情况下,带权路径长度最小的二叉树,也被称为最优二叉树。

举个例子,给定权重分别为1,3,4,6,8的叶子结点,我们应当构建怎样的二叉树,才能保证其带权路径长度最小?

原则上,我们应该让权重小的叶子结点远离树根,权重大的叶子结点靠近树根。

下图左侧的这棵树就是一颗哈夫曼树,它的WPL是46,小于之前例子当中的53

cb6887331bed

构建哈夫曼树:

假设有6个叶子结点,权重依次是2,3,7,9,18,25

首先找到权重最小的两个节点(2,3)构成子树,其根节点为两数之和

cb6887331bed

然后从节点队列中去除这两个最小的节点,并增加一个新节点,其值为去除的两个子节点之和(5);

再从节点队列中选出两个最小的节点(5,7)。。。

以此类推生成n-1个树(n为初始节点队列的长度),再按二叉搜索树拼接成哈夫曼树。

最后生成的Huffman树如下图所示

cb6887331bed

2,3,7,9,18,25  的哈夫曼树

B树(Balance-Tree 平衡多路 查找树)

全称Balance-tree(平衡多路查找树),平衡的意思是左边和右边分布均匀。多路的意思是相对于二叉树而言的,二叉树就是二路查找树,查找时只有两条路,而B-tree有多条路,即父节点有多个子节点。

Q:为什么不使用二叉查找树或者平衡二叉树代替B树?

A:虽然二叉树效率很高,但是二叉树的深度一般较深,不适用于磁盘IO、数据库等系统。

cb6887331bed

如上图,若想查找到10节点,磁盘IO得查找4次。9->13->11->10

使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。这个数据结构一般用于数据库的索引,综合效率较高。

要想了解B树,得先知道树的阶:

对于一棵m阶B-tree,每个结点至多可以拥有m个子结点。

即遍观整棵树,子节点最多的个数是m,那么这棵树就是m阶树。

cb6887331bed

三阶树

B树的定义:

1.对于一个m阶B树中每个结点至多有m棵子树

2.根结点至少有两个子女。

3.每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m

4.每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m

5.所有的叶子结点都位于同一层。

B树的结构:

所有的非叶子结点中包含以下数据:(n,A0,K1,A1,K2,…,Kn,An)

Ki(i=1,2,…,n)为关键码,且Ki

Ai为指向儿子的指针(i=0,1,…,n),且指针Ai-1 所指子树中所有结点的关键码均小于Ki (i=1,2,…,n),An 所指子树中所有结点的关键码均大于Kn。(注:每个ki数据两旁各安放了一个指针,即Ai-1和Ai,左边的子树数据统统小于ki,右边子树的数据统统大于ki,总体来看指针数量比数据数量多1)

n为关键码的个数(Ceil(m/2)-1<=n<=m-1)。

红黑树(Red Black Tree)

红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须满足下面性质:

1.每个节点要不是红色要不是黑色

2.根节点是黑色

3.每个叶子节点是黑色

4.每个红色节点的两个子节点一定是黑色

5.任意一结点到每个叶子结点的路径都包含数量相同的黑结点(不能有挨着的红节点)。

红黑树的插入:

RBTree为二叉搜索树,我们按照二叉搜索树的方法对其进行节点插入

RBTree有颜色约束性质,因此我们在插入新节点之后要进行颜色调整

具体步骤如下:

根节点为NULL,直接插入新节点并将其颜色置为黑色

根节点不为NULL,找到要插入新节点的位置并设置为红色

断新插入节点对全树颜色的影响,更新调整颜色

在调整颜色之前先看看节点的旋转

cb6887331bed

树的旋转

旋转后,原来“左小右大”的特点不会受到影响;影响的是左右子树的高度,右旋左子树高度+1,右子树-1;左旋右子树高度+1,左子树-1。

比如某棵树的左子树高度已经达到3,而右子树只有1,只需要右旋一下,左右子树高度都将调整为2。整棵树来看,高度就相当于降低了1(3 -> 2),这就是高度的“平衡”。

红黑树颜色的调整:

case1:父节点为黑色

直接插入

case2:父节点为红,uncle(父节点的兄弟节点)存在且为红

将父节点,uncle节点改为黑,祖父改为红,然后把祖父节点当成需要调整的节点,继续向上调整。

cb6887331bed

case1

case3:父节点为红,uncle为黑,父节点为祖父节点的左子,当前结点(N)为父节点的左子。

此时以祖父节点(GP)为支点进行右旋;然后将P涂黑,将GP涂红。

cb6887331bed

case3

case4:父节点为红,uncle为黑,父节点为祖父节点的左子,当前结点(N)为父节点的左子。

此时以祖父节点(GP)为支点进行左旋;将P涂黑,将GP涂红。

cb6887331bed

case4

case5:父节点为红,uncle为黑,父节点是祖父节点的左子,N为父节点的右子。

此时,以父节点(P)进行左旋,旋转后,以P作为新的平衡节点N,转至 case3 处理。

cb6887331bed

case5

case6:父节点为红,uncle为黑,父节点是祖父节点的右子,N为父节点的左子。

此时,以父节点(P)进行右旋,旋转后,以P作为新的平衡节点,此时再进行case4处理。

cb6887331bed

case6

算法

1.二叉树的先序遍历public void preOrder(TreeNode root) {

if (root != null) {

System.out.print(root.val+"  ");

preOrderTraverse1(root.left);

preOrderTraverse1(root.right);

}

}

2.二叉树的中序遍历public void inOrder(TreeNode root) {

if (root != null) {

inOrderTraverse1(root.left);

System.out.print(root.val+"  ");

inOrderTraverse1(root.right);

}

}

3.二叉树的后序遍历public void postOrderTraverse1(TreeNode root) {

if (root != null) {

postOrderTraverse1(root.left);

postOrderTraverse1(root.right);

System.out.print(root.val+"  ");

}

}

4.二叉树的层次遍历public void levelTraverse(TreeNode root) {

if (root == null) {

return;

}

LinkedList queue =new LinkedList<>();

queue.offer(root);

while (!queue.isEmpty()) {

TreeNode node = queue.poll();

System.out.print(node.val+"  ");

if (node.left != null) {

queue.offer(node.left);

}

if (node.right != null) {

queue.offer(node.right);

}

}

}

5.二叉树获取数的深度public static int getDepth(Node node,int depth){

int newdepth = depth +1;

int left =0;

int right =0;

if(node.leftChildNode==null&&node.rightChildNode==null){

return depth;

}

if(node.leftChildNode!=null){

left=getDepth(node.leftChildNode,newdepth);

}

if(node.rightChildNode!=null){

right =getDepth(node.rightChildNode,newdepth);

}

return left>=right?left:right;

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值