1. 程式人生 > >avl樹的插入操作和刪除操作

avl樹的插入操作和刪除操作

avl樹相比於搜尋二叉樹每個結點是多了個平衡因子bf,avl樹時時刻刻要維持樹中的每個結點的平衡因子的絕對值小於等於1.

avl樹的插入操作:

avl樹因為要保證每個結點的平衡因子要時時刻刻都符合要求,則樹中每插入一個結點,都可能引起平衡被打破,所以每次插入一個結點,都要從插入的結點往上進行檢查是否有哪個結點需要調整. 要在插入新結點後進行平衡檢查,則需要把插入結點的插入過程的下行路線上的每一個結點都依次記錄下來,這個可以藉助於棧來實現,在查詢插入位置的過程,把每一個結點指標放入棧中.

現在來說一下具體的過程:

從根結點開始,首先查詢要插入的位置

如果結點值相等則返回錯誤,如果小於則向左走,如果大於則向右走,把這個過程中的每一個結點都放入一個棧中,這樣直到到達葉子結點,即找到了插入的位置.然後new出來一個結點進行插入(如果這個位置的父親結點(stack中的top)是NULL,則是空樹,讓root指標指向該結點,插入完成,如果父親結點不是NULL,則根據父親結點和本結點的值的大小確定是左邊插入還是右邊插入).

插入完成以後進行平衡調整

取出棧中的元素進行檢查:插入的結點對於取出的結點如果是左邊插入,則平衡因子減1,如果右邊插入則平衡因子加1.

如果加減1以後平衡因子是0,即意味著插入節點之前平衡因子只能是正負1,插入該節點以後,該子樹的左右子樹高度相等,因此並不改變該子樹的高度,也就並不影響整棵樹的高度,所以樹是平衡的,不需要調整,調整結束,break ;

如果平衡因子是+1或者-1,則意味著該節點所在的子樹的高度發生變化,(因為在此之前該節點的平衡因子只能是0),所以以該節點為root 的子樹的高度一定是增加了,所以要向上繼續檢查是否有哪個節點的平衡因子因為插入了一個節點平衡因子變為正負2,所以繼續取出stack中的下一個節點進行上述同樣的檢查;

如果平衡因子是正負2,則平衡打破,需要進行調整,下面詳述調整過程:

根據平衡子是+2還是-2分為兩種情況:

1.平衡因子是-2:

如果該節點的孩子節點平衡因子是負值:則對該節點進行一次左旋轉即調整完成;

如該該節點的孩子節點的平衡因子是正值:則需要進行先左後右旋轉.

2.平衡因子是+2:

如果該孩子節點bf 是正值:則對該節點進行一次右旋轉即可;

如果孩子節點bf是負值:則對該節點進行先右後左旋轉即可.

調整平衡完成以後需要將該子樹的新根節點掛到之前的根節點下面.以上即整個插入過程.

AVL樹的刪除操作:

首先查詢要刪除的節點,找到以後,要刪除的節點分為兩種情況:

1.要刪除的節點左右兩個孩子都存在,直接刪除不方便,則在右子樹中查詢最小的節點,將其值替換為要刪除的節點的值,因為右子樹的最小節點必然沒有左孩子,即只有一個孩子.然後問題轉化為刪除這個右子樹中最小的節點.(或者也可以將問題轉化為刪除左子樹裡最大的節點)

2.要刪除的孩子節點只有一個孩子節點.

以上均為要刪除的節點只有一個孩子節點,則直接將僅有的一個孩子節點提上來即可.

刪除以後將進行從刪除節點向上進行平衡性的檢查:(在查詢要刪除的節點的過程中,將經過的路徑上的節點全部存放到一個stack)

->取出棧頂元素pr並彈出棧頂元素,如果刪除的節點x比該節點pr的值小,則必定是左樹刪除,則pr-bf++否則pr->bf--.

1.如果pr->bf的絕對值是1:則在刪除節點之前,pr的bf是0,即左右平衡,刪除了以後左樹或者右樹少了一個節點,但pr這個子樹的高度並沒發生變化.對與pr的上面的所有節點而言樹高並沒有發生變化,所以調整完成.

2.如果平衡因子變為0:則在刪除之前平衡因子是+1或者-1,現在刪除節點以後變為0,則pr子樹的高度減1,則要向上繼續檢查,情況重新回到->上面去檢查..

3.如果平衡因子的絕對值是2:則平衡打破,進行平衡調整:

下面詳細描述調整過程:(pr的孩子節點是p)

(1)q->bf == 0,如果pr->bf>0 :則左旋轉,否則右旋轉,旋轉完成以後調整平衡因子大小.

(2)q->bf > 0, 如果 pr->bf>0:則左旋轉,否則先左後右旋轉.

(3)q->bf<0, 如果pr->bf>0:則先右後左旋轉,否則右旋轉.

AVLTree的具體程式碼詳解後面的程式碼片.

還有關於左旋轉,右旋轉,先左後右旋轉,先右後左旋轉,還有旋轉過程的平衡因子如何改變具體詳見後面文章.