樹的基本概念以及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{k-1}-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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM