douliexing2195 2015-05-21 21:44
浏览 106
已采纳

GoLang堆和堆排序

So I'm trying to implement a max heap for practice so I can get familiar with Go.

type MaxHeap struct {
    slice []int
    heapSize int
}
func BuildMaxHeap(slice []int) MaxHeap{
    h := MaxHeap{slice: slice, heapSize: len(slice)}
    for i := len(slice)/2; i >= 0; i-- {
        h.MaxHeapify(i)
    }
    return h
}

func (h MaxHeap) MaxHeapify(i int) {
    left := 2*i
    right := 2*i + 1
    largest := i
    slice := h.slice

    if left < h.size() {
        if slice[left] > slice[i] {
            largest = left
        } else {
            largest = i
        }
    }
    if right < h.size() {
        if slice[right] > slice[largest] {
            largest = right
        }
    }
    if largest != i {
        prevLargest := slice[i]
        slice[i] = slice[largest]
        slice[largest] = prevLargest
        h.MaxHeapify(largest)
    }
}

On an array of [4,1,3,2,16,9,10,14,8,7] I produce [16 14 9 10 8 1 4 2 3 7]

which is wrong as the 9 is one level too high and should be switched with the 10.

Where am I going wrong?

I also know something is weird, because when I try and heapsort

func heapSort(slice []int) []int {
    h := BuildMaxHeap(slice)
    fmt.Println(slice)
    for i := len(h.slice) - 1; i >=1 ; i-- {
        first := h.slice[0]
        last := h.slice[i]
        h.slice[0] = last
        h.slice[i] = first
        h.heapSize--
        h.MaxHeapify(1)
    }
    return h.slice
}

It does not work.

  • 写回答

2条回答 默认 最新

  • dqgxazo4483 2015-05-21 22:36
    关注

    The issue was that slice indexes start at zero so your:

    left := 2*i
    right := 2*i + 1
    

    gives a left child of 0 for index 0 (i.e., itself). Just add one to each of those.

    Your heapSort had a similar issue calling h.MaxHeapify(1) instead of 0. That effectively left whatever value was at the front there.

    Here is a modified version of your code that works (test file also included that uses testing/quick to verify it against container/heap and sort).

    heap.go:

    package main
    
    import "fmt"
    
    type MaxHeap struct {
        slice    []int
        heapSize int
    }
    
    func BuildMaxHeap(slice []int) MaxHeap {
        h := MaxHeap{slice: slice, heapSize: len(slice)}
        for i := len(slice) / 2; i >= 0; i-- {
            h.MaxHeapify(i)
        }
        return h
    }
    
    func (h MaxHeap) MaxHeapify(i int) {
        l, r := 2*i+1, 2*i+2
        max := i
    
        if l < h.size() && h.slice[l] > h.slice[max] {
            max = l
        }
        if r < h.size() && h.slice[r] > h.slice[max] {
            max = r
        }
        //log.Printf("MaxHeapify(%v): l,r=%v,%v; max=%v\t%v
    ", i, l, r, max, h.slice)
        if max != i {
            h.slice[i], h.slice[max] = h.slice[max], h.slice[i]
            h.MaxHeapify(max)
        }
    }
    
    func (h MaxHeap) size() int { return h.heapSize } // ???
    
    func heapSort(slice []int) []int {
        h := BuildMaxHeap(slice)
        //log.Println(slice)
        for i := len(h.slice) - 1; i >= 1; i-- {
            h.slice[0], h.slice[i] = h.slice[i], h.slice[0]
            h.heapSize--
            h.MaxHeapify(0)
        }
        return h.slice
    }
    
    func main() {
        s := []int{4, 1, 3, 2, 16, 9, 10, 14, 8, 7}
        h := BuildMaxHeap(s)
        fmt.Println(h)
    
        s = heapSort(s)
        fmt.Println(s)
    }
    

    <kbd>Playground</kbd>

    heap_test.go:

    package main
    
    import (
        "container/heap"
        "reflect"
        "sort"
        "testing"
        "testing/quick"
    )
    
    // Compare against container/heap implementation:
    // https://golang.org/pkg/container/heap/#example__intHeap
    
    type IntHeap []int
    
    func (h IntHeap) Len() int            { return len(h) }
    func (h IntHeap) Less(i, j int) bool  { return h[i] > h[j] } // use > for MaxHeap
    func (h IntHeap) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
    func (h *IntHeap) Push(x interface{}) { *h = append(*h, x.(int)) }
    func (h *IntHeap) Pop() interface{} {
        old := *h
        n := len(old)
        x := old[n-1]
        *h = old[:n-1]
        return x
    }
    
    func TestMaxHeap(t *testing.T) {
        f := func(s []int) bool {
            //t.Log("testing heap len", len(s))
            h := BuildMaxHeap(s)
            h2 := make(IntHeap, len(h.slice))
            copy(h2, h.slice)
            for i := range h2 {
                heap.Fix(&h2, i)
            }
            eq := reflect.DeepEqual(h.slice, []int(h2))
            if !eq {
                t.Logf("MaxHeap: %v
    \t IntHeap: %v", h.slice, h2)
            }
            return eq
        }
        if err := quick.Check(f, nil); err != nil {
            t.Error(err)
        }
    }
    
    func TestHeapSort(t *testing.T) {
        f := func(s []int) bool {
            s = heapSort(s)
            return sort.IntsAreSorted(s)
        }
        if err := quick.Check(f, nil); err != nil {
            t.Error(err)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3