123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- package skiplist
- import (
- "fmt"
- "math"
- "math/rand"
- "testing"
- "time"
- //"github.com/pkg/profile"
- )
- const (
- maxN = 1000000
- )
- type Element int
- func (e Element) ExtractKey() int64 {
- return int64(e)
- }
- func (e Element) String() string {
- return fmt.Sprintf("%03d", e)
- }
- type FloatElement float64
- func (e FloatElement) ExtractKey() int64 {
- return int64(e)
- }
- func (e FloatElement) String() string {
- return fmt.Sprintf("%.3f", e)
- }
- type ComplexElement struct {
- E int
- S string
- }
- func (e ComplexElement) ExtractKey() int64 {
- return int64(e.E)
- }
- func (e ComplexElement) String() string {
- return fmt.Sprintf("%03d", e.E)
- }
- // timeTrack will print out the number of nanoseconds since the start time divided by n
- // Useful for printing out how long each iteration took in a benchmark
- func timeTrack(start time.Time, n int, name string) {
- loopNS := time.Since(start).Nanoseconds() / int64(n)
- fmt.Printf("%s: %d\n", name, loopNS)
- }
- func TestInsertAndFind(t *testing.T) {
- t.Run("nil list", func(t *testing.T) {
- var listPointer *SkipList
- listPointer.Insert(Element(0))
- if _, ok := listPointer.Find(Element(0)); ok {
- t.Error("should not find element in nil list")
- }
- })
- t.Run("empty list", func(t *testing.T) {
- list := New()
- if _, ok := list.Find(Element(0)); ok {
- t.Error("should not find element in empty list")
- }
- if !list.IsEmpty() {
- t.Error("list should be empty")
- }
- })
- t.Run("sequential insert at beginning", func(t *testing.T) {
- list := New()
- for i := 0; i < maxN; i++ {
- list.Insert(Element(maxN - i))
- }
- for i := 0; i < maxN; i++ {
- if _, ok := list.Find(Element(maxN - i)); !ok {
- t.Errorf("failed to find element %d", maxN-i)
- }
- }
- })
- t.Run("sequential insert at end", func(t *testing.T) {
- list := New()
- for i := 0; i < maxN; i++ {
- list.Insert(Element(i))
- }
- for i := 0; i < maxN; i++ {
- if _, ok := list.Find(Element(i)); !ok {
- t.Errorf("failed to find element %d", i)
- }
- }
- })
- t.Run("random insert", func(t *testing.T) {
- list := New()
- rList := rand.Perm(maxN)
- for _, e := range rList {
- list.Insert(Element(e))
- }
- for _, e := range rList {
- if _, ok := list.Find(Element(e)); !ok {
- t.Errorf("failed to find element %d", e)
- }
- }
- })
- t.Run("boundary values", func(t *testing.T) {
- list := New()
- // Test with min/max int values
- list.Insert(Element(math.MinInt64))
- list.Insert(Element(math.MaxInt64))
-
- if _, ok := list.Find(Element(math.MinInt64)); !ok {
- t.Error("failed to find MinInt64")
- }
- if _, ok := list.Find(Element(math.MaxInt64)); !ok {
- t.Error("failed to find MaxInt64")
- }
- })
- t.Run("duplicate values", func(t *testing.T) {
- list := New()
- // Insert same value multiple times
- for i := 0; i < 10; i++ {
- list.Insert(Element(42))
- }
-
- // Should be able to find the value
- if _, ok := list.Find(Element(42)); !ok {
- t.Error("failed to find duplicate value")
- }
-
- // Count should reflect all insertions
- count := 0
- node, _ := list.Find(Element(42))
- for node != nil && node.GetKey() == 42 {
- count++
- node = list.Next(node)
- }
- if count != 10 {
- t.Errorf("expected 10 duplicate values, got %d", count)
- }
- })
- }
- func TestDelete(t *testing.T) {
- var list SkipList
- // Delete on empty list
- list.Delete(Element(0))
- list = New()
- list.Delete(Element(0))
- if !list.IsEmpty() {
- t.Fail()
- }
- // Delete elements at the beginning of the list.
- for i := 0; i < maxN; i++ {
- list.Insert(Element(i))
- }
- for i := 0; i < maxN; i++ {
- list.Delete(Element(i))
- }
- if !list.IsEmpty() {
- t.Fail()
- }
- list = New()
- // Delete elements at the end of the list.
- for i := 0; i < maxN; i++ {
- list.Insert(Element(i))
- }
- for i := 0; i < maxN; i++ {
- list.Delete(Element(maxN - i - 1))
- }
- if !list.IsEmpty() {
- t.Fail()
- }
- list = New()
- // Delete elements at random positions in the list.
- rList := rand.Perm(maxN)
- for _, e := range rList {
- list.Insert(Element(e))
- }
- for _, e := range rList {
- list.Delete(Element(e))
- }
- if !list.IsEmpty() {
- t.Fail()
- }
- }
- func TestFindGreaterOrEqual(t *testing.T) {
- eps := 0.00000001
- maxNumber := 1000.0
- var list SkipList
- var listPointer *SkipList
- // Test on empty list.
- if _, ok := listPointer.FindGreaterOrEqual(FloatElement(0)); ok {
- t.Fail()
- }
- list = NewEps(eps)
- for i := 0; i < maxN; i++ {
- list.Insert(FloatElement(rand.Float64() * maxNumber))
- }
- first := float64(list.GetSmallestNode().GetValue().(FloatElement))
- // Find the very first element. This is a special case in the implementation that needs testing!
- if v, ok := list.FindGreaterOrEqual(FloatElement(first - 2.0*eps)); ok {
- // We found an element different to the first one!
- if math.Abs(float64(v.GetValue().(FloatElement))-first) > eps {
- t.Fail()
- }
- } else {
- // No element found.
- t.Fail()
- }
- for i := 0; i < maxN; i++ {
- f := rand.Float64() * maxNumber
- if v, ok := list.FindGreaterOrEqual(FloatElement(f)); ok {
- // if f is v should be bigger than the element before
- lastV := float64(list.Prev(v).GetValue().(FloatElement))
- thisV := float64(v.GetValue().(FloatElement))
- isFirst := math.Abs(first-thisV) <= eps
- if !isFirst && lastV >= f {
- fmt.Printf("PrevV: %.8f\n f: %.8f\n\n", lastV, f)
- t.Fail()
- }
- // v should be bigger or equal to f
- // If we compare directly, we get an equal key with a difference on the 10th decimal point, which fails.
- if f-thisV > eps {
- fmt.Printf("f: %.8f\nv: %.8f\n\n", f, thisV)
- t.Fail()
- }
- } else {
- lastV := float64(list.GetLargestNode().GetValue().(FloatElement))
- // It is OK, to fail, as long as f is bigger than the last element.
- if f <= lastV {
- fmt.Printf("lastV: %.8f\n f: %.8f\n\n", lastV, f)
- t.Fail()
- }
- }
- }
- }
- func TestPrev(t *testing.T) {
- list := New()
- for i := 0; i < maxN; i++ {
- list.Insert(Element(i))
- }
- smallest := list.GetSmallestNode()
- largest := list.GetLargestNode()
- lastNode := largest
- node := lastNode
- for node != smallest {
- node = list.Prev(node)
- // Must always be incrementing here!
- if node.value.(Element) >= lastNode.value.(Element) {
- t.Fail()
- }
- // Next.Prev must always point to itself!
- if list.Prev(list.Next(node)) != node {
- t.Fail()
- }
- lastNode = node
- }
- if list.Prev(smallest) != largest {
- t.Fail()
- }
- }
- func TestNext(t *testing.T) {
- list := New()
- for i := 0; i < maxN; i++ {
- list.Insert(Element(i))
- }
- smallest := list.GetSmallestNode()
- largest := list.GetLargestNode()
- lastNode := smallest
- node := lastNode
- for node != largest {
- node = list.Next(node)
- // Must always be incrementing here!
- if node.value.(Element) <= lastNode.value.(Element) {
- t.Fail()
- }
- // Next.Prev must always point to itself!
- if list.Next(list.Prev(node)) != node {
- t.Fail()
- }
- lastNode = node
- }
- if list.Next(largest) != smallest {
- t.Fail()
- }
- }
- func TestChangeValue(t *testing.T) {
- list := New()
- for i := 0; i < maxN; i++ {
- list.Insert(ComplexElement{i, "value"})
- }
- for i := 0; i < maxN; i++ {
- // The key only looks at the int so the string doesn't matter here!
- f1, ok := list.Find(ComplexElement{i, ""})
- if !ok {
- t.Fail()
- }
- ok = list.ChangeValue(f1, ComplexElement{i, "different value"})
- if !ok {
- t.Fail()
- }
- f2, ok := list.Find(ComplexElement{i, ""})
- if !ok {
- t.Fail()
- }
- if f2.GetValue().(ComplexElement).S != "different value" {
- t.Fail()
- }
- if ok = list.ChangeValue(f2, ComplexElement{i + 5, "different key"}); ok {
- t.Fail()
- }
- }
- }
- func TestGetNodeCount(t *testing.T) {
- list := New()
- for i := 0; i < maxN; i++ {
- list.Insert(Element(i))
- }
- if list.GetNodeCount() != maxN {
- t.Fail()
- }
- }
- func TestString(t *testing.T) {
- list := NewSeed(1531889620180049576)
- for i := 0; i < 20; i++ {
- list.Insert(Element(i))
- }
- testString := ` --> [000] -> [002] -> [009] -> [010]
- 000: [---|001]
- 001: [000|002]
- 002: [001|003] -> [004]
- 003: [002|004]
- 004: [003|005] -> [005]
- 005: [004|006] -> [009]
- 006: [005|007]
- 007: [006|008]
- 008: [007|009]
- 009: [008|010] -> [010] -> [010]
- 010: [009|011] -> [012] -> [---] -> [---]
- 011: [010|012]
- 012: [011|013] -> [013]
- 013: [012|014] -> [---]
- 014: [013|015]
- 015: [014|016]
- 016: [015|017]
- 017: [016|018]
- 018: [017|019]
- 019: [018|---]
- --> [019] -> [013] -> [010] -> [010]
- `
- if list.String() != testString {
- t.Fail()
- }
- }
- func TestInfiniteLoop(t *testing.T) {
- list := New()
- list.Insert(Element(1))
- if _, ok := list.Find(Element(2)); ok {
- t.Fail()
- }
- if _, ok := list.FindGreaterOrEqual(Element(2)); ok {
- t.Fail()
- }
- }
- for i := 0; i < maxN; i++ {
- // The key only looks at the int so the string doesn't matter here!
- f1, ok := list.Find(ComplexElement{i, ""})
- if !ok {
- t.Fail()
- }
- ok = list.ChangeValue(f1, ComplexElement{i, "different value"})
- if !ok {
- t.Fail()
- }
- f2, ok := list.Find(ComplexElement{i, ""})
- if !ok {
- t.Fail()
- }
- if f2.GetValue().(ComplexElement).S != "different value" {
- t.Fail()
- }
- if ok = list.ChangeValue(f2, ComplexElement{i + 5, "different key"}); ok {
- t.Fail()
- }
- }
- }
- func TestGetNodeCount(t *testing.T) {
- list := New()
- for i := 0; i < maxN; i++ {
- list.Insert(Element(i))
- }
- if list.GetNodeCount() != maxN {
- t.Fail()
- }
- }
- func TestString(t *testing.T) {
- list := NewSeed(1531889620180049576)
- for i := 0; i < 20; i++ {
- list.Insert(Element(i))
- }
- testString := ` --> [000] -> [002] -> [009] -> [010]
- 000: [---|001]
- 001: [000|002]
- 002: [001|003] -> [004]
- 003: [002|004]
- 004: [003|005] -> [005]
- 005: [004|006] -> [009]
- 006: [005|007]
- 007: [006|008]
- 008: [007|009]
- 009: [008|010] -> [010] -> [010]
- 010: [009|011] -> [012] -> [---] -> [---]
- 011: [010|012]
- 012: [011|013] -> [013]
- 013: [012|014] -> [---]
- 014: [013|015]
- 015: [014|016]
- 016: [015|017]
- 017: [016|018]
- 018: [017|019]
- 019: [018|---]
- --> [019] -> [013] -> [010] -> [010]
- `
- if list.String() != testString {
- t.Fail()
- }
- }
- func TestInfiniteLoop(t *testing.T) {
- list := New()
- list.Insert(Element(1))
- if _, ok := list.Find(Element(2)); ok {
- t.Fail()
- }
- if _, ok := list.FindGreaterOrEqual(Element(2)); ok {
- t.Fail()
- }
- }
|