github.com/benz9527/toy-box/algo@v0.0.0-20240221120937-66c0c6bd5abd/list/skip_list_intf.go (about) 1 package list 2 3 import ( 4 "math" 5 "math/bits" 6 ) 7 8 // Ref 9 // paper: 10 // https://www.cl.cam.ac.uk/teaching/2005/Algorithms/skiplists.pdf 11 // github: 12 // classic: https://github.com/antirez/disque/blob/master/src/skiplist.h 13 // classic: https://github.com/antirez/disque/blob/master/src/skiplist.c 14 // https://github.com/liyue201/gostl 15 // https://github.com/chen3feng/stl4go 16 // test: 17 // https://github.com/chen3feng/skiplist-survey 18 19 const ( 20 ClassicSkipListMaxLevel = 32 // 2^32 - 1 elements 21 ClassicSkipListProbability = 0.25 // P = 1/4, a skip list node element has 1/4 probability to have a level 22 ) 23 24 type SkipListNodeElement[E comparable] interface { 25 GetObject() E 26 GetVerticalBackward() SkipListNodeElement[E] 27 SetVerticalBackward(backward SkipListNodeElement[E]) 28 GetLevels() []SkipListLevel[E] 29 Free() 30 } 31 32 type SkipListLevel[E comparable] interface { 33 GetSpan() int64 34 SetSpan(span int64) 35 GetHorizontalForward() SkipListNodeElement[E] 36 SetHorizontalForward(forward SkipListNodeElement[E]) 37 } 38 39 type SkipList[E comparable] interface { 40 GetLevel() int 41 Len() int64 42 Insert(v E) SkipListNodeElement[E] 43 Remove(v E) SkipListNodeElement[E] 44 Find(v E) SkipListNodeElement[E] 45 PopHead() E 46 PopTail() E 47 Free() 48 ForEach(fn func(idx int64, v E)) 49 } 50 51 // LessThan is the compare function. 52 type compareTo[E comparable] func(a, b E) int 53 54 // SkipListRandomLevel is the skip list level element. 55 // Dynamic level calculation. 56 func SkipListRandomLevel(random func() uint64, maxLevel int) int { 57 // goland math random (math.Float64()) contains global mutex lock 58 // Ref 59 // https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/math/rand/rand.go 60 // https://cs.opensource.google/go/go/+/refs/tags/go1.21.5:src/math/bits/bits.go 61 // 1. Avoid to use global mutex lock 62 // 2. Avoid to generate random number each time 63 total := uint64(1)<<maxLevel - 1 // maxLevel => n, 2^n -1, there will be 2^n-1 elements in the skip list 64 rest := random() % total 65 // Bits right shift equals to manipulate a high level bit 66 // Calculate the minimum bits of the random number 67 level := maxLevel - bits.Len64(rest) + 1 68 return level 69 } 70 71 func MaxLevels(totalElements int64, P float64) int { 72 // Ref https://www.cl.cam.ac.uk/teaching/2005/Algorithms/skiplists.pdf 73 // MaxLevels = log(1/P) * log(totalElements) 74 // P = 1/4, totalElements = 2^32 - 1 75 return int(math.Ceil(math.Log(1/P) * math.Log(float64(totalElements)))) 76 }