From cnblogs yangecnu / cnblogs 有心故我在 / wikipedia 2-3 tree
定義
The 2-3 tree is also a search tree like the binary search tree, but this tree tries to solve the problem of the unbalanced tree.
Imagine that you have a binary tree to store your data. The worst possible case for the binary tree is that all of the data is entered in order. Then the tree would look like this:
This tree has basically turned into a linked list. This is definitely a problem, for with a tree unbalanced like this, all of the advantages of the binary search tree disappear: searching the tree is slow and cumbersome, and there is much wasted memory because of the empty left child pointers.
In computer science, a 2–3 tree is a tree data structure, where every node with children internal node has either two children (2-node) and one data element or three children (3-nodes) and two data elements. According to Knuth, "a B-tree of order 3 is a 2-3 tree." Nodes on the outside of the tree leaf nodes have no children and one or two data elements. 2?3 trees were invented by John Hopcroft in 1970.
2 node
3 node
The 2-3 tree tries to solve this by using a different structure and slightly different adding and removing procedure to help keep the tree more or less balanced. The biggest drawback with the 2-3 tree is that it requires more storage space than the normal binary search tree.
-
One big difference with the 2-3 tree is that each node can have up to two data fields. You can see the three children extending from between the two data fields.
2–3 trees are balanced, meaning that each right, center, and left subtree contains the same or close to the same amount of data.
<Wikipedia>
We say that an internal node is a 2-node if it has one data element and two children.
We say that an internal node is a 3-node if it has two data elements and three children.
We say that T is a 2–3 tree if and only if one of the following statements hold:
- T is empty. In other words, T does not have any nodes.
- T is a 2-node with data element a. If T has left child L and right child R, then
L and R are non-empty 2–3 trees of the same height;
a is greater than each element in L; and
a is less than or equal to each data element in R. - T is a 3-node with data elements a and b, where a < b. If T has left child L, middle child M, and right child R, then
L, M, and R are non-empty 2–3 trees of equal height;
a is greater than each data element in L and less than or equal to each data element in M; and
b is greater than each data element in M and less than or equal to each data element in R.
一棵2-3樹具有下例性質:
- 一個節點包含一個或者兩個關鍵碼;
- 每個內部節點有2個子女(如果它包含一個關鍵碼),或者3個子女(包含2個關鍵碼);
- 所有葉子節點在樹的同一層,因此樹總是高度平衡的。
- 2-3樹每一個節點的左子樹中所有后繼節點的值都小于其父節點第一個關鍵碼的值;
- 而中間子樹所有后繼節點的值都大于或等于其父節點第一個關鍵碼的值而小于第二個關鍵碼的值;
- 如果有右子樹,則右子樹所有后繼節點都大于或等于其父節點第二個關鍵碼的值。
另一種解釋:
- 對于2節點,該節點保存一個key及對應value,以及兩個指向左右節點的節點,左節點也是一個2-3節點,所有的值都比key有效,有節點也是一個2-3節點,所有的值比key要大。
- 對于3節點,該節點保存兩個key及對應value,以及三個指向左中右的節點。左節點也是一個2-3節點,所有的值均比兩個key中的最小的key還要??;中間節點也是一個2-3節點,中間節點的key值在兩個跟節點key值之間;右節點也是一個2-3節點,節點的所有key值比兩個key中的最大的key還要大。
如果中序遍歷2-3查找樹,就可以得到排好序的序列。在一個完全平衡的2-3查找樹中,根節點到每一個為空節點的距離都相同。
查找
在進行2-3樹的平衡之前,我們先假設已經處于平衡狀態,我們先看基本的查找操作。
2-3樹的查找和二叉查找樹類似,要確定一個樹是否屬于2-3樹,我們首先和其跟節點進行比較,如果相等,則查找成功;否則根據比較的條件,在其左中右子樹中遞歸查找,如果找到的節點為空,則未找到,否則返回。查找過程如下圖:
插入

一、往一個2-node節點插入
往2-3樹中插入元素和往二叉查找樹中插入元素一樣,首先要進行查找,然后將節點掛到未找到的節點上。2-3樹之所以能夠保證在最差的情況下的效率的原因在于其插入之后仍然能夠保持平衡狀態。如果查找后未找到的節點是一個2-node節點,那么很容易,我們只需要將新的元素放到這個2-node節點里面使其變成一個3-node節點即可。但是如果查找的節點結束于一個3-node節點,那么可能有點麻煩。
二、往一個3-node節點插入
往一個3-node節點插入一個新的節點可能會遇到很多種不同的情況,下面首先從一個最簡單的只包含一個3-node節點的樹開始討論。
(1)只包含一個3-node節點
如上圖,假設2-3樹只包含一個3-node節點,這個節點有兩個key,沒有空間來插入第三個key了,最自然的方式是我們假設這個節點能存放三個元素,暫時使其變成一個4-node節點,同時他包含四個子節點。然后,我們將這個4-node節點的中間元素提升,左邊的節點作為其左節點,右邊的元素作為其右節點。插入完成,變為平衡2-3查找樹,樹的高度從0變為1。
(2)節點是3-node,父節點是2-node
和第一種情況一樣,我們也可以將新的元素插入到3-node節點中,使其成為一個臨時的4-node節點,然后,將該節點中的中間元素提升到父節點即2-node節點中,使其父節點成為一個3-node節點,然后將左右節點分別掛在這個3-node節點的恰當位置。操作如下圖:
(3)節點是3-node,父節點也是3-node
當我們插入的節點是3-node的時候,我們將該節點拆分,中間元素提升至父節點,但是此時父節點是一個3-node節點,插入之后,父節點變成了4-node節點,然后繼續將中間元素提升至其父節點,直至遇到一個父節點是2-node節點,然后將其變為3-node,不需要繼續進行拆分。
(4)根節點分裂
當根節點到字節點都是3-node節點的時候,這是如果我們要在字節點插入新的元素的時候,會一直查分到跟節點,在最后一步的時候,跟節點變成了一個4-node節點,這個時候,就需要將跟節點查分為兩個2-node節點,樹的高度加1,這個操作過程如下:
(5)本地轉換
將一個4-node拆分為2-3node涉及到6種可能的操作。這4-node可能在跟節點,也可能是2-node的左子節點或者右子節點。或者是一個3-node的左,中,右子節點。所有的這些改變都是本地的,不需要檢查或者修改其他部分的節點。所以只需要常數次操作即可完成2-3樹的平衡。
(6)性質
這些本地操作保持了2-3樹的平衡。對于4-node節點變形為2-3節點,變形前后樹的高度沒有發生變化。只有當跟節點是4-node節點,變形后樹的高度才加一。如下圖所示:
分析
完全平衡的2-3查找樹如下圖,每個根節點到葉子節點的距離是相同的:
2-3樹的查找效率與樹的高度是息息相關的。
- 在最壞的情況下,也就是所有的節點都是2-node節點,查找效率為lgN
-
在最好的情況下,所有的節點都是3-node節點,查找效率為log3N約等于0.631lgN
距離來說,對于1百萬個節點的2-3樹,樹的高度為12-20之間,對于10億個節點的2-3樹,樹的高度為18-30之間。
對于插入來說,只需要常數次操作即可完成,因為他只需要修改與該節點關聯的節點即可,不需要檢查其他節點,所以效率和查找類似。下面是2-3查找樹的效率:
實現
直接實現2-3樹比較復雜,因為:
1.需要處理不同的節點類型,非常繁瑣
2.需要多次比較操作來將節點下移
3.需要上移來拆分4-node節點
4.拆分4-node節點的情況有很多種
2-3查找樹實現起來比較復雜,在某些情況插入后的平衡操作可能會使得效率降低。在2-3查找樹基礎上改進的紅黑樹不僅具有較高的效率,并且實現起來較2-3查找樹簡單。