斐波那契堆之Go实现

一个比二叉堆更高效的数据结构,但是实现起来非常复杂。本科的时候看《算法导论》的时候曾经研究过,不是很明白。今天终于对它有了一个比较清晰的了解。 enter description here

package fibonacciHeap

const MinInt = -int(^uint(0)>>1) - 1

type Vertex struct {
    value  int
    parent *Vertex
    child  *Vertex
    left   *Vertex
    right  *Vertex
    mark   bool
    degree int
}

type FibonacciHeap struct {
    min  *Vertex
    size int
}

// Insert inserts a node into heap with value v
func (F *FibonacciHeap) Insert(value int) *Vertex {
    v := &Vertex{value: value}
    if F.min == nil {
        F.min = v
    } else {
        F.insertToList(F.min, v)
        if F.min.value > v.value {
            F.min = v
        }
    }
    F.size++
    return v
}

func (F *FibonacciHeap) Empty() bool {
    return F.min == nil
}

func (F *FibonacciHeap) Minmum() *Vertex {
    return F.min
}

func (F *FibonacciHeap) ExtractMin() *Vertex {
    z := F.min
    if z == nil {
        return nil
    }
    for z.child != nil {
        v := F.extractVertex(z.child)
        F.insertToList(F.min, v)
    }
    if z == z.right { //the heap only contains one node
        F.min = nil
    } else {
        F.min = z.right
        z = F.extractVertex(z)
        F.consolidate()
    }
    F.size--
    return z
}
func (F *FibonacciHeap) Merge(Other *FibonacciHeap) {
    if F.min == nil { // if current heap is empty
        F.min = Other.min
    } else if Other.min != nil {
        // cut two circle and rearrange them
        F.min.right.left = Other.min.left
        Other.min.left.right = F.min.right //reverse
        F.min.right = Other.min
        Other.min.left = F.min //reverse
        if F.min.value > Other.min.value {
            F.min = Other.min
        }
    }
    Other.min = nil
}
func (F *FibonacciHeap) DecreaseKey(v *Vertex, value int) bool {
    if v.value < value {
        return false // do not increase
    }
    if v.value == value {
        return true
    }
    v.value = value
    parent := v.parent
    if parent != nil && v.value < parent.value {
        v = F.extractVertex(v)
        F.insertToList(F.min, v)
        F.cascadingCut(parent)
    }
    if v.value < F.min.value {
        F.min = v
    }
    return true
}

func (F *FibonacciHeap) IncreaseKey(v *Vertex, value int) bool {
    if v.value > value {
        return false
    }
    if v.value == value {
        return true
    }
    for v.child != nil {
        F.insertToList(F.min, F.extractVertex(v.child))
    }

    v.value = value
    parent := v.parent
    if parent != nil {
        F.insertToList(F.min, F.extractVertex(v))
        F.cascadingCut(parent)
    } else if F.min == v {
        for cur := v.right; cur != v; cur = cur.right {
            if v.value > cur.value {
                F.min = cur
            }
        }
    }
    return true
}

func (F *FibonacciHeap) Modify(v *Vertex, value int) {
    switch {
    case v.value < value:
        F.IncreaseKey(v, value)
    case v.value > value:
        F.DecreaseKey(v, value)
    }
}

func (F *FibonacciHeap) DeleteVertex(v *Vertex) {
    F.DecreaseKey(v, MinInt)
    F.extractVertex(v)
}

// insertToList inserts v after pos
func (F *FibonacciHeap) insertToList(pos *Vertex, v *Vertex) {
    if pos == nil {
        return
    }
    pos.right.left = v
    v.right = pos.right
    pos.right = v
    v.left = pos
    v.parent = pos.parent
    if pos.parent != nil {
        pos.parent.degree++
    }
}

func (F *FibonacciHeap) extractVertex(v *Vertex) *Vertex {
    if v == nil {
        return nil
    }
    if v.parent != nil {
        if v.right != v {
            v.parent.child = v.right
        } else {
            v.parent.child = nil
        }
        v.parent.degree--
        v.parent = nil
    }
    if v.left != v {
        v.left.right = v.right
        v.right.left = v.left
        v.left = v
        v.right = v
    }
    v.mark = false
    return v
}

func (F *FibonacciHeap) cascadingCut(v *Vertex) {
    parent := v.parent
    if parent == nil {
        return
    }
    if v.mark == false {
        v.mark = true
    } else {
        // when the parent have lost a child
        F.extractVertex(v)
        F.insertToList(F.min, v)
        F.cascadingCut(parent)
    }
}

func (F *FibonacciHeap) consolidate() {
    if F.min == nil {
        return
    }
    v := F.min
    degree := v.degree
    // a record table to help merging vertices with the same degree
    table := make([]*Vertex, degree+1)
    for {
        if len(table) <= degree {
            // extend table size
            table = append(table, make([]*Vertex, degree-len(table)+1)...)
        }
        if table[degree] == v {
            break
        }
        if table[degree] == nil {
            //currently ,there is no vertices having the same degree of v
            table[degree] = v
            v = v.right
        } else {
            // make sure v is the minimal vertex
            if table[degree].value < v.value {
                table[degree], v = v, table[degree]
            }
            // merge table[degree] to v as his child
            // make v become root
            table[degree] = F.extractVertex(table[degree])
            if v.child == nil {
                v.child = table[degree]
                table[degree].parent = v
                v.degree++
            } else {
                //v.degree has been increased in this function
                F.insertToList(v.child, table[degree])
            }
            table[degree] = nil
        }
        degree = v.degree
    }
    // find the min
    F.min = nil
    for _, v := range table {
        if v == nil {
            continue
        }
        if F.min == nil {
            F.min = v
        } else if v.value < F.min.value {
            F.min = v
        }
    }
}

参考 - https://www.roading.org/algorithm/introductiontoalgorithm/斐波那契堆fibonacci-heaps.html - http://www.cnblogs.com/skywang12345/p/3659060.html

Comments