package SortedMap
import (
"fmt"
"math/rand"
"testing"
"time"
)
/*
跳表 skip List ,可以实现有序表的所有操作
O(logN) 实现机制和二叉树没关系
跳表好实现,思想先进,跳表实现的有序思路,要比平衡二叉树先进
跳表,是用Node串成的, Node 有多条往外指的指针
一开始的第一个节点,是系统最小值,Node上也得放key 需要支持排序
跳表最左侧的节点认为是弃而不用的,以后增加的所有的key 都要比 最左边的头节点key = nil 标记一个最小的key
一开始,节点只有一条往外指的指针,作为最左侧,node的往外指的指针可以扩展
-------------------
| nil smallest |
| |---> nil
-------------------
left
最左侧节点,拥有全局最小值,他的next指针指向nil
假设加入一个数据 3 : "abc"
-------------------
| key: 3 |
| val:"abc" |---> nil
-------------------
生成[key:3, val:"abc"] 记录,每个节点一开始有几层节点呢
最开始有几层的记录,用随机的方式决定 rand.Float64() ->
<= 0.5 认为是0
> 0.5 认为是1
[key:3, val:"abc"] 一开始有一条往外指的指针
在有一条指针的基础上 随机
如果随机的是0 则加一条指针, 再循环,直到遇见1为止
for 随机数 == 0 {
加一条指针
}
算法上讨论的是N无穷大的情况,所以暂时不限定层数
一旦 确定 随机出多少层,对于自己这个节点的层数,绝对不会再扩展了
扩展的永远的是 全局一开始就有的节点
-------------------
| key: 3 |
| val:"abc" |---> nil
| next |---> nil
| |---> nil
-------------------
假设某个节点随机出了三层指针
-------------------
| nil smallest |
| |---> nil
-------------------
left
最左侧节点向外指针的层数 一定要保持和 所有节点中 指针数最大的 强同步
-------------------
| nil smallest |
| |---> nil
| |---> nil
| |---> nil
-------------------
left
然后开始增加节点
从最上层找到 最早的 > 3 的key 或 找到最晚的 <= 3 的key, 没有,则让该层指针,直接指向 3 节点
往下走, 在第二层上遍历 继续找 最晚的 <= 3 的key, 没有,则让该层指针,直接指向 3 节点
往下走, 在第三层上遍历 继续找 最晚的 <= 3 的key, 没有,则让该层指针,直接指向 3 节点
------------------- -------------------
| nil smallest | | key: 3 |
| |--->| val:"abc" |---> nil
| next |--->| next |---> nil
| |--->| |---> nil
------------------- -------------------
left 3
有高层的节点一定有低层,避免出现断层
5节点加入 假设只随机出了两层指针
从头节点最高层指针遍历, 找到<=5 最晚的节点, 此时来到3了, 3 再往下找就没有了
因为5没有3层,所以 3的指针不指向 5
但是在3的内部,跳转到下层指针
高层往右走,右到不能再右,往下跳
连接5节点
------------------- ------------------- -------------------
| nil smallest | | key: 3 | | key: 5 |
| |--->| val:"abc" |-->nil | val:"def" |
| next |--->| next |------> | next |------> nil
| |--->| |------> | |------> nil
------------------- ------------------- -------------------
left 3 5
假如加入节点2 只 随机出一层节点
从头节点遍历
------------------- ------------------- -------------------
| nil smallest | | key: 3 | | key: 5 |
| |------------------------------>| val:"abc" |-->nil | val:"def" |
| next |------------------------------>| next |------> | next |------> nil
| |--- --------------- ---->| |------> | |------> nil
------------------- | | | | ------------------- -------------------
left | | key:2 | | 3 5
| | val:"hnn" | |
| | next | |
---->| |----
---------------
查找的顺序和 插入的一样
和最高层节点保持一致,随机出更高的层数,左节点的指针层数就扩充
-----
|nil| -----
| 5 |---------------------------------------------------------------->| 7 |----> nil
| | ----- | |
| 4 |---------------------------------->| 4 |------------------------>| |----> nil
| | ----- | | ----- | |
| 3 |-------------->| 2 |-------------->| |---->| 5 |-------------->| |----> nil
| | | | ----- | | | | ----- | |
| 2 |-------------->| |---->| 3 |---->| |---->| |---->| 6 |---->| |----> nil
| | ----- | | | | | | | | | | | |
| 1 |---->| 1 |---->| |---->| |---->| |---->| |---->| |---->| |----> nil
----- ----- ----- ----- ----- ----- ----- -----
左 1 2 3 4 5 6 7
查找6 如何操作?
由高到低,遍历左节点的指针数组,看能否沿着最高层指针向右移动,不能,因为最高层指针指向节点的值为7,7 > 6
来到左节点下一层指针,即从左节点5层节点位置往下跳,来到第4层,第4层指针指向的节点的值为4, 4 < 6 所以能往右跳,来到值为4节点
值为4的节点,指针数组当前层不能往右跳 因为指向值为7的节点, 7 > 6
4节点从当前层往下跳来到第3层 第三层指针指向 节点5 5 < 6
5最高层,不能向右移动,
5降层,来到第2层指针 指向 6 找到了,返回
只要是找,永远从最高层开始
最底层一定有所有数据
假设加N记录,
第1层有N个记录
第2层的期望是N/2
第3层的期望是N/4
第4层的期望是N/8
由高层到低层建立了索引关系
从高层往底层找,越过了很多东西
0------->0
|
0--------->0
右 -> 下 等同于在树上走出了一条路径
高层节点越过了一个,底层节点就越过了一大堆
为什么最终能收敛到O(logN),因为和数据状况无关
思想先进:有点像快排,虽然随机出来的一个数,状况不确定,虽然长期期望难求,但是求完很低
*/
type KEY interface {
CompareTo(v KEY) int
}
type VALUE interface{}
// 跳表的节点定义
type SkipListNode struct {
key KEY // 可比较
value VALUE // 伴随数据
nextNodes []*SkipListNode // 扩充往外指的指针
}
func NewSkipListNode(key KEY, value VALUE) *SkipListNode {
return &SkipListNode{
key: key,
value: value,
nextNodes: make([]*SkipListNode, 0),
}
}
// 遍历的时候,如果是往右遍历到的nil(next == nil), 遍历结束
// 头(nil), 头节点的nil,认为最小
// node -> 头,node(nil, "") node.isKeyLess(!nil) true
// node里面的key是否比otherKey小,true,不是false
func (sk *SkipListNode) isKeyLess(otherKey KEY) bool {
// otherKey == nil -> false // sk.key == nil 认为 otherKey 比 sk.key要小
return otherKey != nil && (sk.key == nil || sk.key.CompareTo(otherKey) < 0)
}
func (sk *SkipListNode) isKeyEqual(otherKey KEY) bool {
return sk.key == nil && otherKey == nil ||
sk.key != nil && otherKey != nil && sk.key.CompareTo(otherKey) == 0
}
type SkipListMap struct {
PROBABILITY float64 //可能性
head *SkipListNode //头
size int //上边有多少不同的key
maxLevel int //最大高度
}
func NewSkipListMap() *SkipListMap {
head := NewSkipListNode(nil, nil)
head.nextNodes = make([]*SkipListNode, 1, 1) // 对于全局最左节点,让他拥有一层节点,规定最底层的节点叫0层节点
return &SkipListMap{
PROBABILITY: 0.5, //可能性: < 0.5 继续做,>= 0.5 停
head: head,
size: 0,
maxLevel: 0,
}
}
// 垂直跳跃
// 从最高层开始,一路找下去
// 最终,找到第0层小于key的最右节点
func (skp *SkipListMap) mostRightLessNodeInTree(key KEY) *SkipListNode {
if key == nil {
return nil
}
cur := skp.head // 最左侧节点一定拥有最大的层数
for level := skp.maxLevel; level >= 0; level-- { //从最高层开始,往下层跳,cur level -> level-1, 每次下降一层,因为不知道降下去那层还能不能再往右了
cur = skp.mostRightLessNodeInLevel(key, cur, level) // 非递归
}
return cur
}
// 水平跳跃
// 在level层里,如何往右移动,同一层
// 现在来到的节点是cur,来到了cur的level层,在level层上,找到小于key最后一个节点并返回
func (skp *SkipListMap) mostRightLessNodeInLevel(key KEY, cur *SkipListNode, level int) *SkipListNode {
next := cur.nextNodes[level]
for next != nil && next.isKeyLess(key) { // 人为控制 isKeyLess() 不传入nil
cur = next
next = cur.nextNodes[level]
}
return cur
}
func (skp *SkipListMap) containsKey(key KEY) bool {
if key == nil {
return false
}
less := skp.mostRightLessNodeInTree(key)
next := less.nextNodes[0]
return next != nil && next.isKeyEqual(key)
}
// 新增或改value
func (skp *SkipListMap) put(key KEY, value VALUE) {
if key == nil {
return
}
// 0层上,最右一个,小于 key的 Node 他的下一个 不等于key 就大于 key
less := skp.mostRightLessNodeInTree(key) // 在树中找到小于key的最右节点 O(logN)
find := less.nextNodes[0]
if find != nil && find.isKeyEqual(key) { // 改Value的操作
find.value = value
} else { // find == nil 8 7 9 // 插入的操作
skp.size++
newNodeLevel := 0
rand.Seed(time.Now().UnixNano())
for rand.Float64() < skp.PROBABILITY { // 随机层数
newNodeLevel++
}
// newNodeLevel
for newNodeLevel > skp.maxLevel { // 如果新随机出的层数 大于 最左节点的最大层数, 填充最左层节点
skp.head.nextNodes = append(skp.head.nextNodes, (*SkipListNode)(nil))
skp.maxLevel++
}
newNode := NewSkipListNode(key, value)
newNode.nextNodes = make([]*SkipListNode, newNodeLevel+1, newNodeLevel+1) // 原本有一条指针,再加上 随机出来的Level,就是newNode的指针条数
pre := skp.head
for level := skp.maxLevel; level >= 0; level-- { // 在树上运动
// 在level 层中,找到最右的 小于 key 的节点
pre = skp.mostRightLessNodeInLevel(key, pre, level)
if level <= newNodeLevel { // 新节点有这一层 就插在 pre 和 next 之间
newNode.nextNodes[level] = pre.nextNodes[level]
pre.nextNodes[level] = newNode
}
} //目的是 让底层的节点通过高层的索引尽快的走到合适的位置
}
}
func (skp *SkipListMap) get(key KEY) VALUE {
if key == nil {
return nil
}
less := skp.mostRightLessNodeInTree(key)
next := less.nextNodes[0] // 最底层节点
if next != nil && next.isKeyEqual(key) {
return next.value
}
return nil
}
func (skp *SkipListMap) remove(key KEY) {
if !skp.containsKey(key) {
return
}
skp.size--
level := skp.maxLevel
pre := skp.head
for level >= 0 {
pre = skp.mostRightLessNodeInLevel(key, pre, level)
next := pre.nextNodes[level]
// 1)在这一层中,pre下一个就是key
// 2)在这一层中,pre的下一个key是>要删除key
if next != nil && next.isKeyEqual(key) {
// free delete node memory -> C++
// level : pre -> next(key) -> ...
pre.nextNodes[level] = next.nextNodes[level] // 我把我的next指向下一层的下一层
}
// 在level层只有一个节点了,就是默认节点head
if level != 0 && pre == skp.head && pre.nextNodes[level] == nil {
//skp.head.nextNodes.remove(level)
skp.head.nextNodes = skp.head.nextNodes[:0]
skp.head.nextNodes = append(skp.head.nextNodes[:level], skp.head.nextNodes[level+1:]...)
skp.maxLevel--
}
level--
}
}
func (skp *SkipListMap) firstKey() KEY {
if skp.head.nextNodes[0] != nil {
return skp.head.nextNodes[0].key
}
return nil
}
func (skp *SkipListMap) lastKey() KEY {
level := skp.maxLevel
cur := skp.head
for level >= 0 {
next := cur.nextNodes[level]
for next != nil {
cur = next
next = cur.nextNodes[level]
}
level--
}
return cur.key
}
func (skp *SkipListMap) ceilingKey(key KEY) KEY {
if key == nil {
return nil
}
less := skp.mostRightLessNodeInTree(key)
next := less.nextNodes[0]
if next != nil {
return next.key
}
return nil
}
func (skp *SkipListMap) floorKey(key KEY) KEY {
if key == nil {
return nil
}
less := skp.mostRightLessNodeInTree(key)
next := less.nextNodes[0]
if next != nil && next.isKeyEqual(key) {
return next.key
}
return less.key
}
func (skp *SkipListMap) Size() int {
return skp.size
}
func (skp *SkipListMap) printAll() {
for i := skp.maxLevel; i >= 0; i-- {
fmt.Print("Level ", i, " : ")
cur := skp.head
for cur.nextNodes[i] != nil {
next := cur.nextNodes[i]
fmt.Print("(", next.key, " , ", next.value, ") ")
cur = next
}
fmt.Println()
}
}
func TestNode(t *testing.T) {
n := NewSkipListNode(nil, nil)
t.Log(len(n.nextNodes))
}
type student struct {
Name string
Age int
}
func (s student)CompareTo(val KEY) int {
if s.Name > val.(student).Name {
return 1
}else if s.Name < val.(student).Name {
return -1
}
return 0
}
func TestSkipListMap(t *testing.T) {
s1 := student{"张1", 0}
s2 := student{"张2", 1}
s3 := student{"张3", 2}
s4 := student{"张4", 3}
s5 := student{"张5", 4}
s6 := student{"张6", 5}
skp := NewSkipListMap()
skp.put(s1, "1")
skp.put(s2, "2")
skp.put(s3, "3")
skp.put(s4, "4")
skp.put(s5, "5")
skp.put(s6, "6")
skp.printAll()
skp.remove(s2)
skp.printAll()
}
06-28
293
12-29
1615