From 42cd6ef9faf974a0858d13a0e280aa03c782df2e Mon Sep 17 00:00:00 2001 From: eson <474420502@qq.com> Date: Mon, 15 Apr 2019 22:57:44 +0800 Subject: [PATCH] change heap array --- heap/array3.go | 237 ++++++++++++++++++++++++++++++++++ heap/heap.go | 131 ++++++++++++++++++- heap/heap_test.go | 187 +++++++++++++++++++++++++++ sparse_array/array3/array3.go | 13 +- 4 files changed, 559 insertions(+), 9 deletions(-) create mode 100644 heap/array3.go create mode 100644 heap/heap_test.go diff --git a/heap/array3.go b/heap/array3.go new file mode 100644 index 0000000..039f9c3 --- /dev/null +++ b/heap/array3.go @@ -0,0 +1,237 @@ +package heap + +type arrayN struct { + ysizes []int + xsizes [][]int + xyproduct int + zsize int + ysize int + xsize int + data [][][]interface{} + + cap int +} + +func newArray() *arrayN { + return newWithCap(8, 8, 8) +} + +func newWithCap(zsize, ysize, xsize int) *arrayN { + arr := &arrayN{zsize: zsize, ysize: ysize, xsize: xsize} + + arr.ysizes = make([]int, arr.zsize, arr.zsize) + + arr.xsizes = make([][]int, arr.zsize, arr.zsize) + for i := 0; i < arr.zsize; i++ { + arr.xsizes[i] = make([]int, arr.ysize, arr.ysize) + } + + arr.xyproduct = arr.ysize * arr.xsize + arr.data = make([][][]interface{}, arr.zsize, arr.zsize) + + arr.cap = arr.zsize * arr.xyproduct + return arr +} + +func (arr *arrayN) debugValues() []interface{} { + var result []interface{} + for _, z := range arr.data { + if z != nil { + for _, y := range z { + if y == nil { + for i := 0; i < arr.xsize; i++ { + result = append(result, nil) + } + } else { + for _, x := range y { + if x == nil { + result = append(result, struct{}{}) + } else { + result = append(result, x) + } + } + } + } + } else { + for i := 0; i < arr.ysize*arr.xsize; i++ { + result = append(result, nil) + } + } + } + return result +} + +func (arr *arrayN) Values() []interface{} { + var result []interface{} + for _, z := range arr.data { + if z != nil { + + for _, y := range z { + if y == nil { + for i := 0; i < arr.xsize; i++ { + result = append(result, nil) + } + } else { + for _, x := range y { + if x == nil { + result = append(result, nil) + } else { + result = append(result, x) + } + } + } + } + } else { + for i := 0; i < arr.ysize*arr.xsize; i++ { + result = append(result, nil) + } + } + } + + return result +} + +func (arr *arrayN) Cap() int { + return arr.cap +} + +func (arr *arrayN) Grow(size int) { + zsize := arr.zsize + size + temp := make([][][]interface{}, zsize, zsize) + copy(temp, arr.data) + arr.data = temp + + tempysizes := make([]int, zsize, zsize) + copy(tempysizes, arr.ysizes) + arr.ysizes = tempysizes + + tempxsizes := make([][]int, zsize, zsize) + copy(tempxsizes, arr.xsizes) + arr.xsizes = tempxsizes + + for i := arr.zsize; i < zsize; i++ { + arr.xsizes[i] = make([]int, arr.ysize, arr.ysize) + } + + arr.zsize += size + arr.cap = arr.zsize * arr.xyproduct +} + +func (arr *arrayN) Set(idx int, value interface{}) { + zindex := idx / arr.xyproduct + nidx := (idx % arr.xyproduct) + yindex := nidx / arr.xsize + xindex := nidx % arr.xsize + + ydata := arr.data[zindex] + if ydata == nil { + ydata = make([][]interface{}, arr.ysize, arr.ysize) + arr.data[zindex] = ydata + } + + xdata := ydata[yindex] + if xdata == nil { + xdata = make([]interface{}, arr.xsize, arr.xsize) + ydata[yindex] = xdata + arr.ysizes[zindex]++ + } + + v := xdata[xindex] + if v == nil { + arr.xsizes[zindex][yindex]++ + } + xdata[xindex] = value +} + +func (arr *arrayN) getOfSet(idx int, value interface{}) ([]interface{}, int) { + zindex := idx / arr.xyproduct + nidx := (idx % arr.xyproduct) + yindex := nidx / arr.xsize + xindex := nidx % arr.xsize + + ydata := arr.data[zindex] + if ydata == nil { + ydata = make([][]interface{}, arr.ysize, arr.ysize) + arr.data[zindex] = ydata + } + + xdata := ydata[yindex] + if xdata == nil { + xdata = make([]interface{}, arr.xsize, arr.xsize) + ydata[yindex] = xdata + arr.ysizes[zindex]++ + } + + v := xdata[xindex] + if v == nil { + arr.xsizes[zindex][yindex]++ + } + xdata[xindex] = value + return xdata, xindex +} + +func (arr *arrayN) Get(idx int) (interface{}, bool) { + zindex := idx / arr.xyproduct + nextsize := (idx % arr.xyproduct) + yindex := nextsize / arr.xsize + xindex := nextsize % arr.xsize + + ydata := arr.data[zindex] + if ydata == nil { + return nil, false + } + + xdata := ydata[yindex] + if xdata == nil { + return nil, false + } + + v := xdata[xindex] + return v, v != nil +} + +func (arr *arrayN) get(idx int) ([]interface{}, int) { + zindex := idx / arr.xyproduct + nextsize := (idx % arr.xyproduct) + yindex := nextsize / arr.xsize + xindex := nextsize % arr.xsize + + xdata := arr.data[zindex][yindex] + return xdata, xindex +} + +func (arr *arrayN) Del(idx int) (interface{}, bool) { + zindex := idx / arr.xyproduct + nextsize := (idx % arr.xyproduct) + yindex := nextsize / arr.xsize + xindex := nextsize % arr.xsize + + ydata := arr.data[zindex] + if ydata == nil { + return nil, false + } + + xdata := ydata[yindex] + if xdata == nil { + return nil, false + } + + v := xdata[xindex] + xdata[xindex] = nil + + isnotnil := v != nil + + if isnotnil { + arr.xsizes[zindex][yindex]-- + if arr.xsizes[zindex][yindex] == 0 { + arr.data[zindex][yindex] = nil + + arr.ysizes[zindex]-- + if arr.ysizes[zindex] == 0 { + arr.data[zindex] = nil + } + } + } + + return v, isnotnil +} diff --git a/heap/heap.go b/heap/heap.go index feab4c6..6342f76 100644 --- a/heap/heap.go +++ b/heap/heap.go @@ -2,18 +2,139 @@ package heap import ( "474420502.top/eson/structure/compare" - "474420502.top/eson/structure/sparse_array/array3" ) type Heap struct { size int - cap int - elements *array3.Array3 + elements *arrayN Compare compare.Compare } func New(Compare compare.Compare) *Heap { - h := &Heap{Compare: Compare, cap: 8} - h.elements = array3.NewWithCap(4, 4, 4) + h := &Heap{Compare: Compare} + h.elements = newWithCap(8, 8, 8) return h } + +func (h *Heap) Values() []interface{} { + return h.elements.Values()[0:h.size] +} + +func (h *Heap) Push(v interface{}) { + + if h.size >= h.elements.Cap() { + h.elements.Grow(h.elements.zsize * 2) + } + + curidx := h.size + curarray, curarrayidx := h.elements.getOfSet(curidx, v) + + h.size++ + + // up + for curidx != 0 { + pidx := (curidx - 1) / 2 + parray, parrayidx := h.elements.get(pidx) + pvalue := parray[parrayidx] + if h.Compare(v, pvalue) > 0 { + curarray[curarrayidx], parray[parrayidx] = parray[parrayidx], curarray[curarrayidx] + curidx = pidx + curarray = parray + curarrayidx = parrayidx + } else { + break + } + } +} + +func (h *Heap) Pop() (interface{}, bool) { + + if h.size == 0 { + return nil, false + } + + h.size-- + + curidx := 0 + curarray, curarrayidx := h.elements.get(curidx) + curvalue := curarray[curarrayidx] + if h.size == 0 { + return curvalue, true + } + + result := curvalue + + lastarray, lastarrayidx := h.elements.get(h.size) + curarray[curarrayidx] = lastarray[lastarrayidx] + curvalue = curarray[curarrayidx] + + var childidx, childarrayidx int + var childarray []interface{} + var childvalue interface{} + // down + for curidx < h.size { + + var childidx1, childidx2, childarrayidx1, childarrayidx2 int + var childarray1, childarray2 []interface{} + var childvalue1, childvalue2 interface{} + + movidx := curidx << 1 + childidx2 = movidx + 2 + if childidx2 < h.size { + childarray2, childarrayidx2 = h.elements.get(childidx2) + childvalue2 = childarray2[childarrayidx2] + + childidx1 = curidx<<1 + 1 + childarray1, childarrayidx1 = h.elements.get(childidx1) + childvalue1 = childarray1[childarrayidx1] + + if h.Compare(childvalue1, childvalue2) >= 0 { + childvalue = childvalue1 + childidx = childidx1 + childarray = childarray1 + childarrayidx = childarrayidx1 + } else { + childvalue = childvalue2 + childidx = childidx2 + childarray = childarray2 + childarrayidx = childarrayidx2 + } + + } else { + + childidx1 = movidx + 1 + if childidx1 < h.size { + childarray1, childarrayidx1 = h.elements.get(childidx1) + childvalue1 = childarray1[childarrayidx1] + + childvalue = childvalue1 + childidx = childidx1 + childarray = childarray1 + childarrayidx = childarrayidx1 + } else { + break + } + } + + if h.Compare(curvalue, childvalue) < 0 { + curarray[curarrayidx] = childvalue + childarray[childarrayidx] = curvalue + curidx = childidx + curarray = childarray + curarrayidx = childarrayidx + } else { + break + } + } + + return result, true + +} + +func (h *Heap) shiftdown(v interface{}) { + +} + +func (h *Heap) shiftup(v interface{}) { + +} diff --git a/heap/heap_test.go b/heap/heap_test.go new file mode 100644 index 0000000..00064d1 --- /dev/null +++ b/heap/heap_test.go @@ -0,0 +1,187 @@ +package heap + +import ( + "bytes" + "encoding/gob" + "io/ioutil" + "log" + "testing" + + "github.com/Pallinder/go-randomdata" + + "github.com/davecgh/go-spew/spew" + + "github.com/emirpasic/gods/trees/binaryheap" +) + +func Int(k1, k2 interface{}) int { + c1 := k1.(int) + c2 := k2.(int) + switch { + case c1 > c2: + return -1 + case c1 < c2: + return 1 + default: + return 0 + } +} + +func TestPush(t *testing.T) { + + for i := 0; i < 1000000; i++ { + h := New(Int) + + gods := binaryheap.NewWithIntComparator() + for c := 0; c < 20; c++ { + v := randomdata.Number(0, 100) + h.Push(v) + gods.Push(v) + } + + r1 := spew.Sprint(h.Values()) + r2 := spew.Sprint(gods.Values()) + if r1 != r2 { + t.Error(r1) + t.Error(r2) + break + } + } + +} + +func TestPop(t *testing.T) { + + for i := 0; i < 500000; i++ { + h := New(Int) + + // m := make(map[int]int) + gods := binaryheap.NewWithIntComparator() + for c := 0; c < 20; c++ { + v := randomdata.Number(0, 100) + // if _, ok := m[v]; !ok { + h.Push(v) + gods.Push(v) + // m[v] = v + // } + + } + + // t.Error(h.Values()) + // t.Error(gods.Values()) + for c := 0; c < randomdata.Number(5, 10); c++ { + v1, _ := h.Pop() + v2, _ := gods.Pop() + + if v1 != v2 { + t.Error(h.Values(), v1) + t.Error(gods.Values(), v2) + return + } + } + + r1 := spew.Sprint(h.Values()) + r2 := spew.Sprint(gods.Values()) + if r1 != r2 { + t.Error(r1) + t.Error(r2) + break + } + } +} + +func BenchmarkPush(b *testing.B) { + + var i int + b.N = 500000000 + + b.StopTimer() + var l []int + for i := 0; i < b.N/10; i++ { + l = append(l, randomdata.Number(0, 65535)) + } + b.StartTimer() + for c := 0; c < 10; c++ { + h := New(Int) + for i = 0; i < b.N/10; i++ { + // arr.Set(l[i], i) + h.Push(l[i]) + } + } +} + +func BenchmarkPop(b *testing.B) { + + h := New(Int) + + l := loadTestData() + + b.ResetTimer() + execCount := 10 + b.N = len(l) * execCount + + for c := 0; c < execCount; c++ { + b.StopTimer() + for _, v := range l { + h.Push(v) + } + b.StartTimer() + for h.size != 0 { + h.Pop() + } + } + +} + +func BenchmarkGodsPop(b *testing.B) { + + h := binaryheap.NewWithIntComparator() + + l := loadTestData() + + b.ResetTimer() + execCount := 10 + b.N = len(l) * execCount + + for c := 0; c < execCount; c++ { + b.StopTimer() + for _, v := range l { + h.Push(v) + } + b.StartTimer() + for h.Size() != 0 { + h.Pop() + } + } + +} + +func BenchmarkGods(b *testing.B) { + var i int + + b.N = 500000000 + b.StopTimer() + var l []int + for i := 0; i < b.N/10; i++ { + l = append(l, randomdata.Number(0, 65535)) + } + b.StartTimer() + for c := 0; c < 10; c++ { + h := binaryheap.NewWithIntComparator() + for i = 0; i < b.N/10; i++ { + // arr.Set(l[i], i) + h.Push(l[i]) + } + } +} + +func loadTestData() []int { + data, err := ioutil.ReadFile("../l.log") + if err != nil { + log.Println(err) + } + var l []int + decoder := gob.NewDecoder(bytes.NewReader(data)) + decoder.Decode(&l) + return l +} diff --git a/sparse_array/array3/array3.go b/sparse_array/array3/array3.go index d232c55..bde429a 100644 --- a/sparse_array/array3/array3.go +++ b/sparse_array/array3/array3.go @@ -96,19 +96,24 @@ func (arr *Array3) Cap() int { } func (arr *Array3) Grow(size int) { - arr.zsize += size - temp := make([][][]interface{}, arr.zsize, arr.zsize) + zsize := arr.zsize + size + temp := make([][][]interface{}, zsize, zsize) copy(temp, arr.data) arr.data = temp - tempysizes := make([]int, arr.zsize, arr.zsize) + tempysizes := make([]int, zsize, zsize) copy(tempysizes, arr.ysizes) arr.ysizes = tempysizes - tempxsizes := make([][]int, arr.ysize, arr.ysize) + tempxsizes := make([][]int, zsize, zsize) copy(tempxsizes, arr.xsizes) arr.xsizes = tempxsizes + for i := arr.zsize; i < zsize; i++ { + arr.xsizes[i] = make([]int, arr.ysize, arr.ysize) + } + + arr.zsize += size arr.cap = arr.zsize * arr.xyproduct }