// Expected check whether given item is equals to expected value type Expected func(a interface{})bool
// Consumer traverses list. // It receives index and value as params, returns true to continue traversal, while returns false to break type Consumer func(i int, v interface{})bool
type List interface { Add(val interface{}) Get(index int) (val interface{}) Set(index int, val interface{}) Insert(index int, val interface{}) Remove(index int) (val interface{}) RemoveLast() (val interface{}) RemoveAllByVal(expected Expected) int RemoveByVal(expected Expected, count int) int ReverseRemoveByVal(expected Expected, count int) int Len() int ForEach(consumer Consumer) Contains(expected Expected) bool Range(start int, stop int) []interface{} }
// QuickList is a linked list of page (which type is []interface{}) // QuickList has better performance than LinkedList of Add, Range and memory usage type QuickList struct { data *list.List // list of []interface{} size int }
// find returns page and in-page-offset of given index func(ql *QuickList)find(index int) *iterator
其流程为:
首先查看 index 在快速链表的前半部分还是后半部分。若在前半部分,则从前向后查找。
从前向后查找,找到 index 所在的 page,pageBeg 表示这个 index 所在 page 之前的元素个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/ 首先查看 index 在快速链表的前半部分还是后半部分。 if index < ql.size/2 { // 若在前半部分,则从前向后查找 node = ql.data.Front() pageBeg = 0 for { page := node.Value.([]interface{}) if pageBeg+len(page) > index { break }
pageBeg += len(page) node = node.Next() } }
若 index 在快速链表的后半部分,则从后向前查找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
else { // 后半部分,从后向前查找 node = ql.data.Back() pageBeg = ql.size for { page := node.Value.([]interface{}) if pageBeg-len(page) <= index { pageBeg -= len(page) break }
func(skiplist *skiplist)getByRank(rank int64) *node { var i int64 = 0 n := skiplist.header // scan from top level for level := skiplist.level - 1; level >= 0; level-- { for n.level[level].forward != nil && (i+n.level[level].span) <= rank { i += n.level[level].span n = n.level[level].forward } if i == rank { return n } } returnnil }
getFirstInScoreRange
skiplist.getFirstInScoreRange 方法用于查找分数范围内的第一个节点。
1
func(skiplist *skiplist)getFirstInScoreRange(min *ScoreBorder, max *ScoreBorder) *node
n := skiplist.header // scan from top level for level := skiplist.level - 1; level >= 0; level-- { // if forward is not in range than move forward for n.level[level].forward != nil && !min.less(n.level[level].forward.Score) { n = n.level[level].forward } }
查找结束,此时 n.level[0].forward 节点一定是范围内的第一个节点。
1 2 3 4 5
n = n.level[0].forward if !max.greater(n.Score) { returnnil } return n
// find position to insert node := skiplist.header for i := skiplist.level - 1; i >= 0; i-- { if i == skiplist.level-1 { rank[i] = 0 } else { rank[i] = rank[i+1] // store rank that is crossed to reach the insert position } if node.level[i] != nil { // traverse the skip list for node.level[i].forward != nil && (node.level[i].forward.Score < score || (node.level[i].forward.Score == score && node.level[i].forward.Member < member)) { // same score, different key rank[i] += node.level[i].span node = node.level[i].forward } } update[i] = node }
随机决定新节点的层数,若新的节点层数大于当前跳表的最高层数,则创建新的层。
1 2 3 4 5 6 7 8 9 10
level := randomLevel() // extend skiplist level if level > skiplist.level { for i := skiplist.level; i < level; i++ { rank[i] = 0 update[i] = skiplist.header update[i].level[i].span = skiplist.length } skiplist.level = level }
// make node and link into skiplist node = makeNode(level, score, member) for i := int16(0); i < level; i++ { node.level[i].forward = update[i].level[i].forward update[i].level[i].forward = node
// update span covered by update[i] as node is inserted here node.level[i].span = update[i].level[i].span - (rank[0] - rank[i]) update[i].level[i].span = (rank[0] - rank[i]) + 1 }
// RemoveByRank removes member ranking within [start, stop) // sort by ascending order and rank starts from 0 func(sortedSet *SortedSet)RemoveByRank(start int64, stop int64)int64 { removed := sortedSet.skiplist.RemoveRangeByRank(start+1, stop+1) for _, element := range removed { delete(sortedSet.dict, element.Member) } returnint64(len(removed)) }