初始化:x指向Head[H],Head[H]是对两个二项堆的根表合并后的数据结构的第一个结点(合并时根表的度数是按照单调递增排列的),并且Head[H]不为NIL,next-x指向x的兄弟结点。x指向的结点左侧(包括结点本身)所构成的数据结构是二项堆,因为此时该堆只有一个以Head[H]为根结点的二项树。
保持:需要分成四种情况讨论。
首先,循环的目的是要把x沿着根表向链表的尾端推进,并且在循环过程中保持x结点左边的数据结构(包括x结点,以及以x结点为根的二项树)是二项堆。
情况1):degree[x] ≠ degree[next-x]
这种情况最简单,因为根表本身是按照度数单调递增排列的,因此degree[next-x]>degree[x],把x的指针向右推进一个兄弟结点,显然可以保证:
x结点左边的数据结构(包括x结点,以及以x结点为根的二项树)是二项堆。
情况2):sibling[next-x] ≠ NIL and degree[sibling[next-x]] = degree[x]
这种情况意味着,x,x的兄弟结点和x的兄弟的兄弟结点的度数相同(最多有3个相邻的结点度数相同,否则合并前就不是二项堆了)
这时,将x的指针向右推进一个兄弟结点,会破坏x结点左边的数据结构(包括x结点,以及以x结点为根的二项树)是二项堆的性质,但因为这种情况下不会退出循环,实际这样做会把问题转换到情况3)或4)。
情况3):当x和x的兄弟的度数相等,但和x的兄弟的兄弟的度数不同,并且key[x] ≤ key[next-x]时
因为度数相同,因此要对这两个二项树进行连接。把x的兄弟结点为根的二项树与x结点为根的二项树进行连接,保证x是连接后的总体二项树的根(用x做根,保证最小堆)。
这时,x结点左边的数据结构(包括x结点,以及以x结点为根的二项树)是二项堆。
情况4):当x和x的兄弟的度数相等,但和x的兄弟的兄弟的度数不同,并且key[x] > key[next-x]时
如果x的上一个结点是NIL,意味着x是指向的head[H],这时需要把head[H]改一下,让它指向x的兄弟结点。如果x的上一个结点不是NIL,那么需要修改prev-x的指针指向x的兄弟结点(因为x结点代表的子树需要被连接)。
然后对x为根和x的兄弟为根的二项树进行连接,这次连接后的根是x的兄弟结点(为保证最小堆性质)。最后,将x指向x的兄弟结点。
此时,x结点左边的数据结构(包括x结点,以及以x结点为根的二项树)是二项堆。
终止:当循环结束时,x的兄弟结点为NIL,x已经指向根表的尾端。意味着x结点左边的数据结构(包括x结点,以及以x结点为根的二项树)已经包括了合并堆的所有结点。并且,该数据结构就是一个二项堆。所以,合并算法是正确的。