树的基本概念以及java实现二叉树

树具有的特点有:

(1)每个结点有零个或多个子结点

(2)没有父节点的结点称为根节点

(3)每一个非根结点有且只有一个父节点

(4)除了根结点外,每个子结点可以分为多个不相交的子树。

树的基本术语有:

若一个结点有子树,那么该结点称为子树根的“双亲”,子树的根称为该结点的“孩子”。有相同双亲的结点互为“兄弟”。一个结点的所有子树上的任何结点都是该结点的后裔。从根结点到某个结点的路径上的所有结点都是该结点的祖先。

结点的度:结点拥有的子树的数目

叶子结点:度为0的结点

分支结点:度不为0的结点

树的度:树中结点的最大的度

层次:根结点的层次为1,其余结点的层次等于该结点的双亲结点的层次加1

树的高度:树中结点的最大层次

森林:0个或多个不相交的树组成。对森林加上一个根,森林即成为树;删去根,树即成为森林。

二叉树的性质

a、在非空二叉树的第i层上,至多有2^(i-1)个结点
假设这是一棵满二叉树,则1、2、3层分别有1、2、4个结点,满足以上性质

b、深度为k的二叉树至多有2^k-1个结点
假设这是一棵满二叉树,则4层有15个结点,满足以上的性质

c、对任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2+1
假设二叉树中度为1的结点数为n1,因为二叉树只有度为1,2,0的结点,所以有n=n0+n1+n2。再看二叉树分支条数e,因为二叉树除了根结点没有父结点,进入它的边数为0之外,其他每一结点都有一个且仅有一个父结点,进入它们的边数均为1,故二叉树中总的边数为e=n-1=n0+n1+n2-1。又由于每个度为2的结点发出2条边,每个度为1的结点发出1条边,每个度为0的结点发出0条边,因此总的边数e=2n2+1n1+0n0=2n2+n1,由以上两式可以得出n0= n2+1

上图中结点总数是10,n2(1、2、3、4)为4,n1(5)为1,n0(6、7、8、9、10)为5

d、具有n个结点的完全二叉树深度为⌈log2(n+1)⌉,对以2为底n+1对数进行向上取整(⌈⌉是向上取整符号)
可以由性质2得出,深度为k的完全二叉树最多有 n \leq 2{k}-1个结点,最少有2-1个,因此:

2^{k-1}-1 < n \leq 2^{k}-1

2^{k-1} < n+1 \leq 2^{k}

k-1 < log_{2}(n+1) \leq k

因为log_{2}(n+1)介于 K-1 和 K之间且不等于 K-1,深度又只能是整数,所以有⌈log_{2}(n+1)⌉

e、如果有一颗有n个结点的完全二叉树的结点按层次序编号,对任一层的结点i(1<=i<=n)有
如果i=1,则结点是二叉树的根,无双亲,如果i>1,则其双亲结点为⌊i/2⌋,向下取整
如果2i>n那么结点i没有左孩子,否则其左孩子为2i
如果2i+1>n那么结点没有右孩子,否则右孩子为2i+1
若结点i为奇数,且i!=1,它处于右兄弟位置,则它的左兄弟结点i-1
若结点i为偶数,且i!=n,它处于左兄弟位置,则它的右兄弟为结点i+1

https://github.com/mcrwayfun/java-data-structure/blob/master/doc/source/tree/树.md#23-二叉树的性质

递归实现二叉树的遍历

前序遍历

基本思想:若二叉树为空,则返回。否则从根结点开始,优先访问根结点,再前序遍历左子树,前序遍历右子树,即根——左——右

class TreeNode{

	int data;
	TreeNode leftChild;
	TreeNode rightChild;
}

 /**
     * 前序遍历(中左右)
     * output:A、B、D、G、H、C、E、I、F
     * @param root
     */
    public void preOrder(TreeNode root) {

        if (root == null) {
            return;
        } else {
            System.out.println("preOrder data:" + root.getData());
            preOrder(root.leftChild);
            preOrder(root.rightChild);
        }
    }

中序遍历

基本思想:若二叉树为空,则返回。否则优先中序遍历左子树,再访问根结点,再后序遍历右子树,即左——根——右

 /**
     * 中序遍历(左中右)
     * output:G、D、H、B、A、E、I、C、F
     * @param root
     */
    public void midOrder(TreeNode root) {

        if (root == null) {
            return;
        } else {
            midOrder(root.leftChild);
            System.out.println("midOrder data:" + root.getData());
            midOrder(root.rightChild);
        }
    }

后序遍历

基本思想:若二叉树为空,则返回。否则优先后序遍历左子树,再后序遍历右子树,最后访问根结点,,即左——右——根

 /**
     * 后序遍历(左右中)
     * output:G、H、D、B、I、E、F、C、A
     * @param root
     */
    public void postOrder(TreeNode root){

        if (root == null) {
            return;
        } else {
            postOrder(root.leftChild);
            postOrder(root.rightChild);
            System.out.println("postOrder data:" + root.getData());
        }
    }

满二叉树、完全二叉树和二叉查找树、 2-3查找树

1、满二叉树

定义:高度为h,并且由2h-1个结点组成的二叉树,称为满二叉树

2、完全二叉树

定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下层的叶结点集中在靠左的若干位置上,这样的二叉树称为完全二叉树。

特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。

3、二叉查找树

定义:二叉查找树又被称为二叉搜索树。设x为二叉查找树中的一个结点,x结点包含关键字key,结点x的key值计为key[x]。如果y是x的左子树中的一个结点,则key[y]<=key[x];如果y是x的右子树的一个结点,则key[y]>=key[x]

在二叉查找树种:

(1)若任意结点的左子树不空,则左子树上所有结点的值均小于它的根结点的值。

(2)任意结点的右子树不空,则右子树上所有结点的值均大于它的根结点的值。

(3)任意结点的左、右子树也分别为二叉查找树。

(4)没有键值相等的结点。

二叉查找树BST——Java实现
详细图文说明

https://blog.csdn.net/javazejian/article/details/53727333

2-3查找树

  1. 对于2节点,该节点保存一个key及对应value,以及两个指向左右节点的节点,左节点也是一个2-3节点,左节点所有的值都比该节点的key要小,右节点也是一个2-3节点,所有的值比该节点的key要大。

  2. 对于3节点,该节点保存两个key及对应value,以及三个指向左中右的节点。左节点也是一个2-3节点,所有的值均比两个key中的最小的key还要小;中间节点也是一个2-3节点,中间节点的key值在两个跟节点key值之间;右节点也是一个2-3节点,节点的所有key值比两个key中的最大的key还要大。

平衡二叉树 、 红黑树、替罪羊树、Treap、伸展树

平衡二叉树是一种特殊的二叉搜索树,在按顺序向插入二叉搜索树中插入值,最后会形成一个类似链表形式的树,而我们设计二叉搜索树的初衷,显然是看中了它的查找速度与它的高度成正比,如果每一颗二叉树都像链表一样,那就没什么意思了,所以就设计出来了平衡二叉树,相对于二叉搜索树,平衡二叉树的一个特点就是,在该树中,任意一个节点,它的左右子树的差的绝对值一定小于2。

1.本身首先是一棵二叉搜索树。

2.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。

也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。
如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵平衡二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理

平衡二叉树的旋转

左-左型:做右旋
右-右型:做左旋
左-右型:先做左旋,后做右旋
右-左型:先做右旋,后做左旋

这里假设结点X是失衡点,它必须重新恢复平衡,由于任意结点的孩子结点最多有两个,而且导致失衡的必要条件是X结点的两棵子树高度差为2(大于1),因此一般只有以下4种情况可能导致X点失去平衡:
① 在结点X的左孩子结点的左子树中插入元素
② 在结点X的左孩子结点的右子树中插入元素
③ 在结点X的右孩子结点的左子树中插入元素
④ 在结点X的右孩子结点的右子树中插入元素
以上4种情况,其中第①情况和第④情况是对称的,可以通过单旋转来解决,而第②种情况和第③情况是对称的,需要双旋转来解决。

左左单旋转(LL)需要右旋转

右右单旋转(RR)进行左旋转

https://blog.csdn.net/javazejian/article/details/53892797
https://www.jb51.net/article/154428.htm
https://blog.csdn.net/cqulun123/article/details/80399371
https://blog.csdn.net/m1179457922/article/details/81745013
https://blog.csdn.net/genius_wolf/article/details/85267253
https://www.jianshu.com/p/4f5eca987990
https://www.cnblogs.com/qm-article/p/9349681.html
https://blog.csdn.net/m0_38036210/article/details/100517125

《剑指offer》
https://www.cnblogs.com/mingyueanyao/p/10322643.html

https://algs4.cs.princeton.edu/33balanced/
http://pages.cs.wisc.edu/~ealexand/cs367/NOTES/AVL-Trees/index.html
https://visualgo.net/en/bst

红黑树

https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
平衡树(AVL)是为了解决 二叉查找树(BST)退化为链表的情况。
红黑树(RBT)是为了解决 平衡树 在删除等操作需要频繁调整的情况。

红黑树5个特征

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

  1. 节点是红色或黑色。

  2. 根节点是黑色。

  3. 每个叶节点(NIL节点,空节点)是黑色的。

  4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

  5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

红黑树是一种具有红色和黑色链接的平衡查找树,同时满足:

红色节点向左倾斜
一个节点不可能有两个红色链接
整个树完全黑色平衡,即从根节点到所以叶子结点的路径上,黑色链接的个数都相同。
如果我们将红色的连线水平绘制,那么他链接的两个2-node节点就是2-3树中的一个3-node节点了。

红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(logn),效率非常之高。
例如,Java集合中的TreeSet和TreeMap,C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的。

https://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html
https://blog.csdn.net/eson_15/article/details/51144079
https://blog.csdn.net/v_july_v/article/details/6105630

平衡二叉树红黑树两者的区别

1、红黑树并不追求“完全平衡”——它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。红黑树能够以O(log2 n) 的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,还有一些更好的,但实现起来更复杂的数据结构 能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高。当然,红黑树并不适应所有应用树的领域。如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。在实际的系统中,例如,需要使用动态规则的防火墙系统,使用红黑树而不是散列表被实践证明具有更好的伸缩性,典型的用途是实现关联数组。

2、AVL树是最先发明的自平衡二叉查 找树。在AVL树中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

B树、B_树、B+树

B树(B-tree)是一种树状数据结构,它能够存储数据、对其进行排序并允许以O(log n)的时间复杂度运行进行查找、顺序读取、插入和删除的数据结构。B树,概括来说是一个节点可以拥有多于2个子节点的二叉查找树。与自平衡二叉查找树不同,B-树为系统最优化大块数据的读和写操作。B-tree算法减少定位记录时所经历的中间过程,从而加快存取速度。普遍运用在数据库和文件系统。”

定义

B 树可以看作是对2-3查找树的一种扩展,即他允许每个节点有M-1个子节点。

根节点至少有两个子节点
每个节点有M-1个key,并且以升序排列
位于M-1和M key的子节点的值位于M-1 和M key对应的Value之间
其它节点至少有M/2个子节点

https://blog.csdn.net/u012124438/article/details/78109466
https://article.itxueyuan.com/wy3Bon
https://segmentfault.com/a/1190000020416577?utm_source=tag-newest
https://www.iteye.com/blog/uule-2429508
https://www.cnblogs.com/yangecnu/p/Introduce-B-Tree-and-B-Plus-Tree.html

B+树

B+树是对B树的一种变形树,它与B树的差异在于:

有k个子结点的结点必然有k个关键码;
非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中。
树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录。

二叉树基本知识

https://blog.csdn.net/qingtian_1993/article/details/80637917
https://segmentfault.com/a/1190000014743964
https://github.com/mcrwayfun/java-data-structure/blob/master/doc/source/tree/树.md

https://blog.csdn.net/m0_38036210/article/category/9225624

posted @ 2019-09-19 18:20  antball  阅读(850)  评论(0编辑  收藏  举报