diff --git a/list/arraylist/arraylist.go b/list/arraylist/arraylist.go index f82fb7c..3461837 100644 --- a/list/arraylist/arraylist.go +++ b/list/arraylist/arraylist.go @@ -33,12 +33,14 @@ func (l *ArrayList) Size() uint { func (l *ArrayList) grow() { newsize := uint(len(l.data)) << 1 - l.reserveHead = al.reserveHead << 1 + if l.reserveHead < l.reserveLimit { + l.reserveHead = l.reserveHead << 1 + } - l.headIndex = al.reserveHead - l.nextIndex = al.headIndex + l.headIndex = l.reserveHead + l.nextIndex = l.headIndex - l.data = make([]interface{}, 8, 8) + l.data = make([]interface{}, newsize, newsize) } // Add add value to the tail of list @@ -50,7 +52,6 @@ func (l *ArrayList) Add(v interface{}) { l.size++ l.data[l.nextIndex] = v - // grow } diff --git a/list/linkedlist/linkedlist.go b/list/linkedlist/linkedlist.go new file mode 100644 index 0000000..b88587c --- /dev/null +++ b/list/linkedlist/linkedlist.go @@ -0,0 +1,108 @@ +package linkedlist + +type Node struct { + next *Node + value interface{} +} + +func (node *Node) Value() interface{} { + return node.value +} + +type LinkedList struct { + head *Node + size uint +} + +func New() *LinkedList { + return &LinkedList{} +} + +func (l *LinkedList) Size() uint { + return l.size +} + +func (l *LinkedList) Push(v interface{}) { + l.size++ + if l.head == nil { + l.head = &Node{value: v} + return + } + l.head = &Node{value: v, next: l.head} +} + +func (l *LinkedList) PushNode(n *Node) { + l.size++ + if l.head == nil { + l.head = n + return + } + + n.next = l.head + l.head = n +} + +func (l *LinkedList) Pop() (result interface{}, found bool) { + if n, ok := l.PopNode(); ok { + return n.value, ok + } + return nil, false +} + +func (l *LinkedList) PopNode() (result *Node, found bool) { + if l.head == nil { + return nil, false + } + + result = l.head + found = true + l.head = result.next + result.next = nil + l.size-- + return +} + +func (l *LinkedList) Remove(idx uint) (result *Node, found bool) { + if l.size == 0 { + return nil, false + } + + if idx == 0 { + result = l.head + found = true + l.head = result.next + result.next = nil + l.size-- + return + } + + for cur := l.head; cur.next != nil; cur = cur.next { + if idx == 1 { + l.size-- + result = cur.next + found = true + cur.next = result.next + result.next = nil + return + } + idx-- + } + + return nil, false +} + +func (l *LinkedList) Values() (result []interface{}) { + l.Traversal(func(cur *Node) bool { + result = append(result, cur.value) + return true + }) + return +} + +func (l *LinkedList) Traversal(every func(*Node) bool) { + for cur := l.head; cur != nil; cur = cur.next { + if !every(cur) { + break + } + } +} diff --git a/list/linkedlist/linkedlist_test.go b/list/linkedlist/linkedlist_test.go new file mode 100644 index 0000000..9d89c7e --- /dev/null +++ b/list/linkedlist/linkedlist_test.go @@ -0,0 +1,87 @@ +package linkedlist + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" +) + +func TestPush(t *testing.T) { + l := New() + for i := 0; i < 5; i++ { + l.Push(i) + } + var result string + result = spew.Sprint(l.Values()) + if result != "[4 3 2 1 0]" { + t.Error(result) + } + + l.Push(0) + result = spew.Sprint(l.Values()) + if result != "[0 4 3 2 1 0]" { + t.Error(result) + } +} + +func TestPop(t *testing.T) { + l := New() + for i := 0; i < 5; i++ { + l.Push(i) + } + + if v, ok := l.Pop(); ok { + if v != 4 { + t.Error(v) + } + } else { + t.Error("Pop should ok, but is not ok") + } + + var result string + result = spew.Sprint(l.Values()) + if result != "[3 2 1 0]" { + t.Error(result) + } + + for i := 3; l.Size() != 0; i-- { + if v, ok := l.Pop(); ok { + if v != i { + t.Error(i, v, "is not equals") + } + } else { + t.Error("Pop should ok, but is not ok", i) + } + } + + l.Push(0) + result = spew.Sprint(l.Values()) + if result != "[0]" { + t.Error(result) + } + + if l.Size() != 1 { + t.Error("l.Size() == 1, but is error, size = ", l.Size()) + } +} + +func TestRemove(t *testing.T) { + l := New() + for i := 0; i < 5; i++ { + l.Push(i) + } + + for i := 0; i < 5; i++ { + if n, ok := l.Remove(0); ok { + if n.Value() != 4-i { + t.Error(n) + } + } else { + t.Error("Pop should ok, but is not ok", i) + } + } + + if l.Size() != 0 { + t.Error("l.Size() == 0, but is error, size = ", l.Size()) + } +} diff --git a/list/priority_list/iterator.go b/list/priority_list/iterator.go new file mode 100644 index 0000000..cc1738d --- /dev/null +++ b/list/priority_list/iterator.go @@ -0,0 +1,87 @@ +package plist + +type Iterator struct { + pl *PriorityList + cur *Node +} + +func (iter *Iterator) Value() interface{} { + return iter.cur.value +} + +func (iter *Iterator) Prev() bool { + if iter.cur == iter.pl.head { + return false + } + iter.cur = iter.cur.prev + return iter.cur != iter.pl.head +} + +func (iter *Iterator) Next() bool { + if iter.cur == iter.pl.tail { + return false + } + iter.cur = iter.cur.next + return iter.cur != iter.pl.tail +} + +func (iter *Iterator) MoveToHead() { + iter.cur = iter.pl.head +} + +func (iter *Iterator) MoveToTail() { + iter.cur = iter.pl.tail +} + +type CircularIterator struct { + pl *PriorityList + cur *Node +} + +func (iter *CircularIterator) Value() interface{} { + return iter.cur.value +} + +func (iter *CircularIterator) Prev() bool { + if iter.pl.size == 0 { + return false + } + + if iter.cur == iter.pl.head { + iter.cur = iter.pl.tail.prev + return true + } + + iter.cur = iter.cur.prev + if iter.cur == iter.pl.head { + iter.cur = iter.pl.tail.prev + } + + return true +} + +func (iter *CircularIterator) Next() bool { + if iter.pl.size == 0 { + return false + } + + if iter.cur == iter.pl.tail { + iter.cur = iter.pl.head.next + return true + } + + iter.cur = iter.cur.next + if iter.cur == iter.pl.tail { + iter.cur = iter.pl.head.next + } + + return true +} + +func (iter *CircularIterator) MoveToHead() { + iter.cur = iter.pl.head +} + +func (iter *CircularIterator) MoveToTail() { + iter.cur = iter.pl.tail +} diff --git a/list/priority_list/priority_list.go b/list/priority_list/priority_list.go new file mode 100644 index 0000000..bb5897b --- /dev/null +++ b/list/priority_list/priority_list.go @@ -0,0 +1,165 @@ +package plist + +import ( + "strings" + + "github.com/474420502/focus/compare" + "github.com/davecgh/go-spew/spew" +) + +type Node struct { + prev, next *Node + value interface{} +} + +type PriorityList struct { + head, tail *Node + size int + Compare compare.Compare +} + +func New(Compare compare.Compare) *PriorityList { + pl := &PriorityList{head: &Node{}, tail: &Node{}, size: 0, Compare: Compare} + pl.head.next = pl.tail + pl.tail.prev = pl.head + return pl +} + +func (pl *PriorityList) String() string { + content := "" + + cur := pl.head.next + + for ; cur != pl.tail; cur = cur.next { + content += spew.Sprint(cur.value) + " " + } + content = strings.TrimRight(content, " ") + return content +} + +func (pl *PriorityList) RString() string { + content := "" + + cur := pl.tail.prev + + for ; cur != pl.head; cur = cur.prev { + content += spew.Sprint(cur.value) + " " + } + content = strings.TrimRight(content, " ") + return content +} + +func (pl *PriorityList) Iterator() *Iterator { + return &Iterator{pl: pl, cur: pl.head} +} + +func (pl *PriorityList) CircularIterator() *CircularIterator { + return &CircularIterator{pl: pl, cur: pl.head} +} + +func (pl *PriorityList) Size() int { + return pl.size +} + +func (pl *PriorityList) Push(value interface{}) { + pl.size++ + pnode := &Node{value: value} + if pl.size == 1 { + pl.head.next = pnode + pl.tail.prev = pnode + pnode.prev = pl.head + pnode.next = pl.tail + return + } + + cur := pl.head + for ; cur.next != pl.tail; cur = cur.next { + if pl.Compare(value, cur.next.value) > 0 { + cnext := cur.next + + cur.next = pnode + cnext.prev = pnode + pnode.prev = cur + pnode.next = cnext + + return + } + } + + cur.next = pnode + pnode.prev = cur + pnode.next = pl.tail + pl.tail.prev = pnode +} + +func (pl *PriorityList) Top() (result interface{}, ok bool) { + if pl.size > 0 { + return pl.head.next.value, true + } + return nil, false +} + +func (pl *PriorityList) Pop() (result interface{}, ok bool) { + if pl.size > 0 { + pl.size-- + temp := pl.head.next + temp.next.prev = pl.head + pl.head.next = temp.next + return temp.value, true + } + return nil, false +} + +func (pl *PriorityList) Get(idx int) (interface{}, bool) { + if n, ok := pl.GetNode(idx); ok { + return n.value, true + } + return nil, false +} + +func (pl *PriorityList) GetNode(idx int) (*Node, bool) { + if idx >= 0 { + cur := pl.head.next + for i := 0; cur != pl.tail; i++ { + if i == idx { + return cur, true + } + cur = cur.next + } + } else { + cur := pl.tail.prev + for i := -1; cur != pl.head; i-- { + if i == idx { + return cur, true + } + cur = cur.prev + } + } + return nil, false +} + +func (pl *PriorityList) RemoveWithIndex(idx int) { + if n, ok := pl.GetNode(idx); ok { + pl.Remove(n) + } +} + +func (pl *PriorityList) Remove(node *Node) { + + prev := node.prev + next := node.next + prev.next = next + next.prev = prev + + node.prev = nil + node.next = nil + + pl.size-- +} +func (pl *PriorityList) Values() []interface{} { + values := make([]interface{}, pl.size, pl.size) + for i, cur := 0, pl.head.next; cur != pl.tail; i, cur = i+1, cur.next { + values[i] = cur.value + } + return values +} diff --git a/list/priority_list/priority_list_test.go b/list/priority_list/priority_list_test.go new file mode 100644 index 0000000..2ea0129 --- /dev/null +++ b/list/priority_list/priority_list_test.go @@ -0,0 +1,260 @@ +package plist + +import ( + "bytes" + "encoding/gob" + "io/ioutil" + "log" + "testing" + + "github.com/474420502/focus/compare" +) + +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 +} + +func TestInsert(t *testing.T) { + pl := New(compare.Int) + for i := 0; i < 10; i++ { + pl.Push(i) + } + + if pl.size != 10 { + t.Error(pl.size) + } + + if pl.String() != "9 8 7 6 5 4 3 2 1 0" { + t.Error(pl.String()) + } + + if pl.RString() != "0 1 2 3 4 5 6 7 8 9" { + t.Error(pl.RString()) + } + + for i := 0; i < 10; i++ { + pl.Push(i) + } + + if pl.String() != "9 9 8 8 7 7 6 6 5 5 4 4 3 3 2 2 1 1 0 0" { + t.Error(pl.String()) + } + + if pl.RString() != "0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9" { + t.Error(pl.RString()) + } +} + +func TestIterator(t *testing.T) { + pl := New(compare.Int) + for i := 0; i < 10; i++ { + pl.Push(i) + } + + iter := pl.Iterator() + + for i := 0; iter.Next(); i++ { + if iter.Value() != 9-i { + t.Error("iter.Next() ", iter.Value(), "is not equal ", 9-i) + } + } + + if iter.cur != iter.pl.tail { + t.Error("current point is not equal tail ", iter.pl.tail) + } + + for i := 0; iter.Prev(); i++ { + if iter.Value() != i { + t.Error("iter.Prev() ", iter.Value(), "is not equal ", i) + } + } +} + +func TestCircularIterator(t *testing.T) { + pl := New(compare.Int) + for i := 0; i < 10; i++ { + pl.Push(i) + } + + iter := pl.CircularIterator() + + for i := 0; i != 10; i++ { + iter.Next() + if iter.Value() != 9-i { + t.Error("iter.Next() ", iter.Value(), "is not equal ", 9-i) + } + } + + if iter.cur != iter.pl.tail.prev { + t.Error("current point is not equal tail ", iter.pl.tail.prev) + } + + if iter.Next() { + if iter.Value() != 9 { + t.Error("iter.Value() != ", iter.Value()) + } + } + + iter.MoveToTail() + for i := 0; i != 10; i++ { + iter.Prev() + if iter.Value() != i { + t.Error("iter.Prev() ", iter.Value(), "is not equal ", i) + } + } + + if iter.cur != iter.pl.head.next { + t.Error("current point is not equal tail ", iter.pl.tail.prev) + } + + if iter.Prev() { + if iter.Value() != 0 { + t.Error("iter.Value() != ", iter.Value()) + } + } +} + +func TestGet(t *testing.T) { + pl := New(compare.Int) + for i := 0; i < 10; i++ { + pl.Push(i) + } + + for _, v := range []int{0, 9, 5, 7} { + if g, ok := pl.Get(v); ok { + if g != (9 - v) { + t.Error(v, "Get == ", g) + } + } + } + + if n, ok := pl.Get(10); ok { + t.Error("index 10 is over size", n) + } +} + +func TestTop(t *testing.T) { + pl := New(compare.Int) + for i := 0; i < 10; i++ { + pl.Push(i) + } + + i := 0 + for n, ok := pl.Pop(); ok; n, ok = pl.Pop() { + if (9 - i) != n { + t.Error("value is not equal ", i) + } + if top, tok := pl.Top(); tok { + if (9 - i - 1) != top { + t.Error("top is error cur i = ", i, "top is ", top) + } + } + + i++ + } + + if pl.Size() != 0 { + t.Error("list size is not zero") + } +} + +func TestPop(t *testing.T) { + pl := New(compare.Int) + for i := 0; i < 10; i++ { + pl.Push(i) + } + + i := 0 + for n, ok := pl.Pop(); ok; n, ok = pl.Pop() { + if (9 - i) != n { + t.Error("value is not equal ", i) + } + i++ + } + + if pl.Size() != 0 { + t.Error("list size is not zero") + } + + for i := 9; i >= 0; i-- { + pl.Push(i) + } + + i = 0 + for n, ok := pl.Pop(); ok; n, ok = pl.Pop() { + if (9 - i) != n { + t.Error("value is not equal ", i) + } + i++ + } + + if pl.Size() != 0 { + t.Error("list size is not zero") + } +} + +func TestRemove(t *testing.T) { + pl := New(compare.Int) + for i := 0; i < 10; i++ { + pl.Push(i) + } + + pl.RemoveWithIndex(0) + if g, ok := pl.Get(0); ok { + if g != 8 { + t.Error(g) + } + } + + pl.RemoveWithIndex(-1) + if g, ok := pl.Get(-1); ok { + if g != 1 { + t.Error(g) + } + } + +} + +// func BenchmarkGet(b *testing.B) { +// pl := New(compare.Int) + +// l := loadTestData() + +// for _, v := range l { +// pl.Push(v) +// } + +// b.ResetTimer() +// b.StartTimer() +// b.N = len(l) + +// for i := 0; i < b.N; i++ { +// if i%2 == 0 { +// pl.Get(i) +// } +// } + +// } +// func BenchmarkInsert(b *testing.B) { + +// l := loadTestData() + +// b.ResetTimer() +// b.StartTimer() + +// execCount := 1 +// b.N = len(l) * execCount +// for i := 0; i < execCount; i++ { +// pl := New(compare.Int) +// for _, v := range l { +// pl.Push(v) +// } +// } +// } diff --git a/map/treemap/treemap.go b/map/treemap/treemap.go new file mode 100644 index 0000000..5595ed0 --- /dev/null +++ b/map/treemap/treemap.go @@ -0,0 +1,77 @@ +package treemap + +import ( + "strings" + + "github.com/davecgh/go-spew/spew" + + "github.com/474420502/focus/compare" + "github.com/474420502/focus/tree/avlkeydup" +) + +type TreeMap struct { + avl *avlkeydup.Tree +} + +// New instantiates a hash map. +func New(Compare compare.Compare) *TreeMap { + return &TreeMap{avl: avlkeydup.New(Compare)} +} + +// Put inserts element into the map. +func (tmap *TreeMap) Put(key interface{}, value interface{}) { + tmap.avl.Put(key, value) +} + +func (tmap *TreeMap) Get(key interface{}) (value interface{}, isfound bool) { + value, isfound = tmap.avl.Get(key) + return +} + +func (tmap *TreeMap) Remove(key interface{}) { + tmap.Remove(key) +} + +func (tmap *TreeMap) Empty() bool { + return tmap.avl.Size() == 0 +} + +func (tmap *TreeMap) Size() int { + return tmap.avl.Size() +} + +func (tmap *TreeMap) Keys() []interface{} { + keys := make([]interface{}, tmap.avl.Size()) + count := 0 + tmap.avl.Traversal(func(key, value interface{}) bool { + keys[count] = key + count++ + return true + }) + return keys +} + +func (tmap *TreeMap) Values() []interface{} { + values := make([]interface{}, tmap.avl.Size()) + count := 0 + tmap.avl.Traversal(func(key, value interface{}) bool { + values[count] = value + count++ + return true + }) + return values +} + +func (tmap *TreeMap) Clear() { + tmap.avl.Clear() +} + +func (tmap *TreeMap) String() string { + content := "{" + tmap.avl.Traversal(func(key, value interface{}) bool { + content += spew.Sprint(key) + ":" + spew.Sprint(value) + "," + return true + }) + content = strings.TrimRight(content, ",") + "}" + return content +} diff --git a/map/treemap/treemap_test.go b/map/treemap/treemap_test.go new file mode 100644 index 0000000..d3e3bb3 --- /dev/null +++ b/map/treemap/treemap_test.go @@ -0,0 +1 @@ +package treemap