From 703dff0813c85eb5d1c6392de111bdb58687e474 Mon Sep 17 00:00:00 2001 From: eson <474420502@qq.com> Date: Mon, 15 Apr 2019 00:56:01 +0800 Subject: [PATCH] finish sparse array --- sparse_array/array2/array2.go | 34 +++++- sparse_array/array2/array2_test.go | 53 ++++++-- sparse_array/array3/array3.go | 47 +++++++- sparse_array/array3/array3_test.go | 33 ++--- sparse_array/arrayn/arrayn.go | 138 ++++++++++++++++----- sparse_array/arrayn/arrayn_test.go | 187 +++++++++++++++++++++++++++-- 6 files changed, 424 insertions(+), 68 deletions(-) diff --git a/sparse_array/array2/array2.go b/sparse_array/array2/array2.go index 5150479..273ae4f 100644 --- a/sparse_array/array2/array2.go +++ b/sparse_array/array2/array2.go @@ -18,7 +18,7 @@ func NewWithCap(ysize, xsize int) *Array2 { return arr } -func (arr *Array2) Values() []interface{} { +func (arr *Array2) debugValues() []interface{} { var result []interface{} for _, y := range arr.data { if y != nil { @@ -35,10 +35,40 @@ func (arr *Array2) Values() []interface{} { } } } - return result } +func (arr *Array2) Values() []interface{} { + var result []interface{} + for _, y := range arr.data { + if y != nil { + for _, v := range y { + if v == nil { + result = append(result, nil) + } else { + result = append(result, v) + } + } + } else { + for i := 0; i < arr.xsize; i++ { + result = append(result, nil) + } + } + } + return result +} + +func (arr *Array2) Grow(size int) { + arr.ysize += size + temp := make([][]interface{}, arr.ysize, arr.ysize) + copy(temp, arr.data) + arr.data = temp + + tempsizes := make([]int, arr.ysize, arr.ysize) + copy(tempsizes, arr.sizes) + arr.sizes = tempsizes +} + func (arr *Array2) Set(idx int, value interface{}) { yindex := idx / arr.xsize xindex := idx % arr.xsize diff --git a/sparse_array/array2/array2_test.go b/sparse_array/array2/array2_test.go index ed1df15..ac05cfd 100644 --- a/sparse_array/array2/array2_test.go +++ b/sparse_array/array2/array2_test.go @@ -16,7 +16,7 @@ func testSet1(t *testing.T) { } var result string - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[0 {} {} {} {} 5 6 {} {} {} {} 15]" { t.Error(result) } @@ -31,15 +31,15 @@ func testSet1(t *testing.T) { } func testSet2(t *testing.T) { - arr := NewWithCap(3, 6) - l := []int{0, 6, 5, 15} + arr := NewWithCap(5, 3) + l := []int{0, 6, 5, 14} for _, v := range l { arr.Set(v, v) } var result string - result = spew.Sprint(arr.Values()) - if result != "[0 {} {} {} {} 5 6 {} {} {} {} 15]" { + result = spew.Sprint(arr.debugValues()) + if result != "[0 {} {} {} {} 5 6 {} {} {} {} 14]" { t.Error(result) } @@ -122,27 +122,27 @@ func TestArray2Del(t *testing.T) { var result string arr.Del(0) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[{} {} {} {} {} 5 6 {} {} {} {} {} {} {} {} 15 {} {}]" { t.Error(arr.data) t.Error(result) } arr.Del(5) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[ 6 {} {} {} {} {} {} {} {} 15 {} {}]" { t.Error(arr.data) t.Error(result) } arr.Del(6) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[ {} {} {} 15 {} {}]" { t.Error(result) } arr.Del(15) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[ ]" { t.Error(result) } @@ -156,6 +156,41 @@ func TestArray2Del(t *testing.T) { arr.Del(18) } +func TestArray2Grow(t *testing.T) { + arr := NewWithCap(4, 4) + l := []int{0, 6, 5, 15} + for _, v := range l { + arr.Set(v, v) + } + + arr.Grow(1) + + if v, ok := arr.Get(15); ok { + if v != 15 { + t.Error(v) + } + } else { + t.Error(v) + } + + arr.Set(19, 19) + if v, ok := arr.Get(19); ok { + if v != 19 { + t.Error(v) + } + } else { + t.Error(v) + } + + arr.Grow(-1) + var result string + + result = spew.Sprint(arr.debugValues()) + if result != "[0 {} {} {} {} 5 6 {} {} {} {} 15]" { + t.Error(result) + } +} + func BenchmarkArray2Set(b *testing.B) { arr := NewWithCap(1000, 100) diff --git a/sparse_array/array3/array3.go b/sparse_array/array3/array3.go index 66873b4..b87a50a 100644 --- a/sparse_array/array3/array3.go +++ b/sparse_array/array3/array3.go @@ -29,11 +29,10 @@ func NewWithCap(zsize, ysize, xsize int) *Array3 { return arr } -func (arr *Array3) Values() []interface{} { +func (arr *Array3) 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++ { @@ -55,10 +54,54 @@ func (arr *Array3) Values() []interface{} { } } } + return result +} + +func (arr *Array3) 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 *Array3) Grow(size int) { + arr.ysize += size + temp := make([][][]interface{}, arr.zsize, arr.zsize) + copy(temp, arr.data) + arr.data = temp + + tempysizes := make([]int, arr.zsize, arr.zsize) + copy(tempysizes, arr.ysizes) + arr.ysizes = tempysizes + + tempxsizes := make([][]int, arr.ysize, arr.ysize) + copy(tempxsizes, arr.xsizes) + arr.xsizes = tempxsizes +} + func (arr *Array3) Set(idx int, value interface{}) { zindex := idx / arr.xyproduct nidx := (idx % arr.xyproduct) diff --git a/sparse_array/array3/array3_test.go b/sparse_array/array3/array3_test.go index e378d0e..8105cc3 100644 --- a/sparse_array/array3/array3_test.go +++ b/sparse_array/array3/array3_test.go @@ -16,7 +16,7 @@ func testSet1(t *testing.T) { } var result string - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[0 1 {} 7]" { t.Error(result) } @@ -38,7 +38,7 @@ func testSet2(t *testing.T) { } var result string - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[0 {} {} {} {} 5 6 {} {} {} {} 11]" { t.Error(arr.data) t.Error(result) @@ -74,22 +74,26 @@ func testArray2Get1(t *testing.T) { } } + if v, ok := arr.Get(8*8*8 - 1); ok { + t.Error(v) + } + defer func() { if err := recover(); err == nil { t.Error("err == nil, but array the get is out of range") } }() - arr.Get(64) + arr.Get(8 * 8 * 8) } func testArray2Get2(t *testing.T) { arr := NewWithCap(4, 3, 3) - for i := 0; i < 64; i++ { + for i := 0; i < 36; i++ { arr.Set(i, i) } - for i := 0; i < 64; i++ { + for i := 0; i < 36; i++ { if v, ok := arr.Get(i); ok { if v != i { t.Error("v is equal i, but", v, i) @@ -105,7 +109,7 @@ func testArray2Get2(t *testing.T) { } }() - arr.Get(72) + arr.Get(36) } func TestArray2Get(t *testing.T) { @@ -123,27 +127,27 @@ func TestArray2Del(t *testing.T) { var result string arr.Del(0) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[ {} {} 5 6 {} {} {} {} 11]" { t.Error(arr.data) t.Error(result) } arr.Del(5) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[ 6 {} {} {} {} 11]" { t.Error(arr.data) t.Error(result) } arr.Del(6) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[ {} {} 11]" { t.Error(result) } arr.Del(11) - result = spew.Sprint(arr.Values()) + result = spew.Sprint(arr.debugValues()) if result != "[ ]" { t.Error(result) } @@ -157,7 +161,7 @@ func TestArray2Del(t *testing.T) { arr.Del(18) } -func BenchmarkArray2Set(b *testing.B) { +func BenchmarkArray3Set(b *testing.B) { arr := NewWithCap(100, 100, 10) b.N = 500000000 @@ -173,10 +177,9 @@ func BenchmarkArray2Set(b *testing.B) { arr.Set(l[i], i) } } - } -func BenchmarkArray2Get(b *testing.B) { +func BenchmarkArray3Get(b *testing.B) { arr := NewWithCap(100, 100, 10) b.N = 500000000 @@ -192,10 +195,9 @@ func BenchmarkArray2Get(b *testing.B) { for i := 0; i < b.N; i++ { arr.Get(i % 65535) } - } -func BenchmarkArray2Del(b *testing.B) { +func BenchmarkArray3Del(b *testing.B) { arr := NewWithCap(100, 100, 10) b.N = 500000000 @@ -210,5 +212,4 @@ func BenchmarkArray2Del(b *testing.B) { for i := 0; i < b.N; i++ { arr.Del(i % 65535) } - } diff --git a/sparse_array/arrayn/arrayn.go b/sparse_array/arrayn/arrayn.go index d74804a..54252d3 100644 --- a/sparse_array/arrayn/arrayn.go +++ b/sparse_array/arrayn/arrayn.go @@ -21,7 +21,7 @@ type ArrayN struct { dims []int product []int - dim int + dimN int data *Node // []*Node } @@ -30,7 +30,7 @@ func New() *ArrayN { } func NewWithCap(dims ...int) *ArrayN { - arr := &ArrayN{dim: len(dims), dims: dims} + arr := &ArrayN{dimN: len(dims), dims: dims} arr.product = make([]int, len(dims)-1, len(dims)-1) for i := 0; i < len(dims)-1; i++ { pvalue := 1 @@ -43,60 +43,110 @@ func NewWithCap(dims ...int) *ArrayN { return arr } -func (arr *ArrayN) Values() []interface{} { - return nil +func (arr *ArrayN) collectValues(curDim int, cur *Node, result *[]interface{}) { + if cur == nil { + return + } + + if curDim == 1 { + for _, v := range cur.data.([]interface{}) { + if v != nil { + *result = append(*result, v) + } else { + *result = append(*result, nil) + } + } + return + } + + for _, n := range cur.data.([]*Node) { + if n != nil { + arr.collectValues(curDim-1, n, result) + } else { + total := 1 + for i := len(arr.dims) - curDim + 1; i < len(arr.dims); i++ { + total *= arr.dims[i] + } + + for i := 0; i < total; i++ { + *result = append(*result, nil) + } + } + } } -func (arr *ArrayN) set(curDim int, curidx int, data **Node, parent *Node) (*Node, int) { +func (arr *ArrayN) Values() (result []interface{}) { + arr.collectValues(arr.dimN, arr.data, &result) + return +} - sidx := arr.dim - curDim +func (arr *ArrayN) set(curDim int, curidx int, pdata **Node, parent *Node) (*Node, int) { - if *data == nil { + sidx := arr.dimN - curDim + + if *pdata == nil { if parent != nil { parent.size++ } if curDim > 1 { - *data = &Node{data: make([]*Node, arr.dims[sidx], arr.dims[sidx])} + *pdata = &Node{data: make([]*Node, arr.dims[sidx], arr.dims[sidx])} } else { - *data = &Node{data: make([]interface{}, arr.dims[sidx], arr.dims[sidx])} - return *data, curidx + *pdata = &Node{data: make([]interface{}, arr.dims[sidx], arr.dims[sidx])} + return *pdata, curidx } } + cur := *pdata if curDim == 1 { - return *data, curidx + return cur, curidx } nidx := curidx % arr.product[sidx] dimindex := curidx / arr.product[sidx] - cur := *data + return arr.set(curDim-1, nidx, &cur.data.([]*Node)[dimindex], cur) } -func (arr *ArrayN) get(curDim int, curidx int, data **Node) (*Node, int) { - sidx := arr.dim - curDim +func (arr *ArrayN) Grow(size int) { + arr.dims[0] += size - if *data == nil { + pvalue := 1 + for n := 1; n < len(arr.dims); n++ { + pvalue *= arr.dims[n] + } + arr.product[0] = pvalue + + tempdata := arr.data.data.([]*Node) + + newData := make([]*Node, arr.dims[0], arr.dims[0]) + copy(newData, tempdata) + arr.data.data = newData +} + +func (arr *ArrayN) Set(idx int, value interface{}) { + n, nidx := arr.set(arr.dimN, idx, &arr.data, nil) + n.data.([]interface{})[nidx] = value +} + +func (arr *ArrayN) get(curDim int, curidx int, pdata **Node) (*Node, int) { + sidx := arr.dimN - curDim + + if *pdata == nil { return nil, 0 } + cur := *pdata if curDim == 1 { - return *data, curidx + return cur, curidx } nidx := curidx % arr.product[sidx] dimindex := curidx / arr.product[sidx] - cur := *data return arr.get(curDim-1, nidx, &cur.data.([]*Node)[dimindex]) } -func (arr *ArrayN) Set(idx int, value interface{}) { - n, nidx := arr.set(arr.dim, idx, &arr.data, nil) - n.data.([]interface{})[nidx] = value -} - func (arr *ArrayN) Get(idx int) (interface{}, bool) { - n, nidx := arr.get(arr.dim, idx, &arr.data) + n, nidx := arr.get(arr.dimN, idx, &arr.data) if n != nil { v := n.data.([]interface{})[nidx] return v, v != nil @@ -104,23 +154,49 @@ func (arr *ArrayN) Get(idx int) (interface{}, bool) { return nil, false } -func (arr *ArrayN) del(curDim int, curidx int, data **Node) (*Node, int) { - sidx := arr.dim - curDim +func (arr *ArrayN) del(curDim int, curidx int, pdata **Node) (interface{}, bool) { - if *data == nil { - return nil, 0 + cur := *pdata + if cur == nil { + return nil, false } if curDim == 1 { - return *data, curidx + values := cur.data.([]interface{}) + + v := values[curidx] + if v != nil { + cur.size-- + values[curidx] = nil + if cur.size == 0 { + return v, true + } + } + return v, false } + sidx := arr.dimN - curDim + nidx := curidx % arr.product[sidx] dimindex := curidx / arr.product[sidx] - cur := *data - return arr.del(curDim-1, nidx, &cur.data.([]*Node)[dimindex]) + curdata := cur.data.([]*Node) + + v, ok := arr.del(curDim-1, nidx, &curdata[dimindex]) + if ok { + cur.size-- + curdata[dimindex] = nil + if cur.size == 0 { + return v, true + } + } + + return v, false } func (arr *ArrayN) Del(idx int) (interface{}, bool) { - return nil, true + v, _ := arr.del(arr.dimN, idx, &arr.data) + if v != nil { + return v, true + } + return nil, false } diff --git a/sparse_array/arrayn/arrayn_test.go b/sparse_array/arrayn/arrayn_test.go index cee2fd2..4da1a5d 100644 --- a/sparse_array/arrayn/arrayn_test.go +++ b/sparse_array/arrayn/arrayn_test.go @@ -4,17 +4,171 @@ import ( "testing" "github.com/Pallinder/go-randomdata" + "github.com/davecgh/go-spew/spew" ) -func TestCase1(t *testing.T) { - arr := NewWithCap(3, 3, 3, 3) - for i := 0; i < 52; i++ { +func testSet1(t *testing.T) { + arr := NewWithCap(2, 2, 2) + l := []int{0, 1, 7} + for _, v := range l { + arr.Set(v, v) + } + + var result string + result = spew.Sprint(arr.Values()) + if result != "[0 1 7]" { + t.Error(result) + } + + defer func() { + if err := recover(); err == nil { + t.Error("err == nil, but array the set is out of range") + } + }() + + arr.Set(8, 8) +} + +func testSet2(t *testing.T) { + arr := NewWithCap(2, 2, 3) + l := []int{0, 6, 5, 11} + for _, v := range l { + arr.Set(v, v) + } + + var result string + result = spew.Sprint(arr.Values()) + if result != "[0 5 6 11]" { + t.Error(arr.data) + t.Error(result) + } + + defer func() { + if err := recover(); err == nil { + t.Error("err == nil, but array the set is out of range") + } + }() + + arr.Set(12, 12) +} + +func TestSet(t *testing.T) { + testSet1(t) + testSet2(t) +} + +func testArray2Get1(t *testing.T) { + arr := New() + for i := 0; i < 64; i++ { arr.Set(i, i) } - t.Error(arr.Get(2)) - t.Error(arr.Get(1)) - t.Error(arr.Get(80)) + for i := 0; i < 64; i++ { + if v, ok := arr.Get(i); ok { + if v != i { + t.Error("v is equal i, but", v, i) + } + } else { + t.Error("not ok is error") + } + } + + if v, ok := arr.Get(8*8*8 - 1); ok { + t.Error(v) + } + + defer func() { + if err := recover(); err == nil { + t.Error("err == nil, but array the get is out of range") + } + }() + + arr.Get(8 * 8 * 8) +} + +func testArray2Get2(t *testing.T) { + arr := NewWithCap(4, 3, 3) + for i := 0; i < 36; i++ { + arr.Set(i, i) + } + + for i := 0; i < 36; i++ { + if v, ok := arr.Get(i); ok { + if v != i { + t.Error("v is equal i, but", v, i) + } + } else { + t.Error("not ok is error") + } + } + + defer func() { + if err := recover(); err == nil { + t.Error("err == nil, but array the get is out of range") + } + }() + + arr.Get(36) +} + +func TestArray2Get(t *testing.T) { + testArray2Get1(t) + testArray2Get2(t) +} + +func TestDel(t *testing.T) { + arr := NewWithCap(2, 2, 2, 3) + for i := 0; i < 12; i++ { + arr.Set(i, i) + } + + arr.Set(23, 23) + + for i := 0; i < 12; i++ { + arr.Del(i) + } + + arr.Del(23) + var result string + + result = spew.Sprint(arr.Values()) + if result != "[ ]" { + t.Error("result should be all is nil") + } +} + +func TestArray2Grow(t *testing.T) { + arr := NewWithCap(4, 4) + l := []int{0, 6, 5, 15} + for _, v := range l { + arr.Set(v, v) + } + + arr.Grow(1) + + if v, ok := arr.Get(15); ok { + if v != 15 { + t.Error(v) + } + } else { + t.Error(v) + } + + arr.Set(19, 19) + if v, ok := arr.Get(19); ok { + if v != 19 { + t.Error(v) + } + } else { + t.Error(v) + } + + arr.Grow(-1) + var result string + result = spew.Sprint(arr.Values()) + if result != "[0 5 6 15]" { + t.Error(result) + } } func BenchmarkGoMap(b *testing.B) { @@ -35,7 +189,7 @@ func BenchmarkGoMap(b *testing.B) { func BenchmarkArrayNSet(b *testing.B) { - arr := NewWithCap(10, 10, 10, 10000) + arr := NewWithCap(1000, 10, 10, 100) b.N = 10000000 b.StopTimer() @@ -49,5 +203,22 @@ func BenchmarkArrayNSet(b *testing.B) { arr.Set(l[i], i) } } - +} + +func BenchmarkArray3Set(b *testing.B) { + + arr := NewWithCap(100, 100, 10) + 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++ { + for i := 0; i < b.N/10; i++ { + arr.Set(l[i], i) + } + } }