golang实现skiplist 跳表

跳表

package main

import (
	"errors"
	"math"
	"math/rand"
)

func main() {
   

	// 双向链表
	//
	/**
	先理解查找过程
	Level 3: 1		 6
	Level 2: 1   3   6
	Level 1: 1 2 3 4 6

	比如 查找2 ; 从高层往下找;
	如果查找的值比当前值小 说明没有可查找的值
	2比1大 往当前层的下个节点查找,3层的后面没有了或者比后面的6小 ,往下层找
	2层 查找值比下个节点3还小 往下层找
	最后一层找到

	比如查找 4
	没有找到 3层往下到2层; 2层里 4比3大继续往前,比6小,往下层找
	从第一层的继续往前找

	比如查找 5
	第一层的3开始往前找到6比查找值5大,说明没有待查找值
	*/

	/**
	插入流程
		找到插入的位置
		确定他当前的层数
		在他的层数连接当前节点

	    如何确定层数?
			来一个概率的算法就行
			这样在数量大的时候能基本能达到2分查找的效果(概率是1/2)

	    更新索引数组?
		我们在查找的时候的路径就可以拿来做插入的数据
	    比如查找4
		找的路径是 3层的 1,2层的3 ;
		如果4是第三层的
		更新3层 1->4>6
		更新2层 1->3->4->6
	*/

	/**
	删除流程 基本同上

	*/

	/**

	 */

}

// MAX_LEVEL 最高层数
const MAX_LEVEL = 16

type T comparable

type skipListHandle[T comparable] interface {
   
	insert(data T, score int32) (err error)
	delete(data T, score int32) int
	findNode(data T, score int32) (error, *skipListNode[T])
}

type skipListNode[T comparable] struct {
   
	data T
	// 排序分数
	score int32
	//层高
	level int
	// 下个节点 同时也是索引
	forwards []*skipListNode[T]
}

type skipList[T comparable] struct {
   
	head, tail *skipListNode[T]
	// 跳表高度
	level int
	// 跳表长度
	length int32
}

func createSkipList[T comparable](data T) *skipList[T] {
   
	return &skipList[T]{
   
		level:  1,
		length: 0,
		head:   createNode[T](data, math.MinInt32, MAX_LEVEL),
	}
}

func createNode[T comparable](data T, score int32, level int) *skipListNode[T] {
   
	return &skipListNode[T]{
   
		data:     data,
		score:    score,
		forwards: make([]*skipListNode[T], MAX_LEVEL, MAX_LEVEL),
		level:    level,
	}
}
func (list *skipList[T]) Insert(data T, score int32) error {
   
	currenNode := list.head
	// 找到插入的位置
	// 记录插入的路径 记录第一个比待查找的值小的位置
	path := [MAX_LEVEL]*skipListNode[T]{
   }
	for i := MAX_LEVEL - 1; i >= 0; i-- {
   
		for currenNode.forwards[i] != nil {
   
			// 如果插入的位置比当前数据小 直接跳出循环并且高度下降
			if currenNode.forwards[i].score > score {
   
				path[i] = currenNode
				break
			}
			// 插入位置比当前的大,在当前层继续往前找
			currenNode = currenNode.forwards[i]
		}
		// 如果currenNode.forwards[i] == nil 说明是最后一个值了 所以直接插入
		if currenNode.forwards[i] == nil {
   
			path[i] = currenNode
		}
	}

	// 随机算法求得最大层数
	level := 1
	for i := 1; i < MAX_LEVEL; i++ {
   
		if rand.Int31()%7 == 1 {
   
			level++
		}
	}

	newNode := createNode(data, score, level)

	// 原有节点连接
	for i := 0; i <= level-1; i++ {
   
		next := path[i].forwards[i]
		// path[i]拿到第一个插入值小的位置 forwards[i] 是指在当前层它指向的下个节点
		newNode.forwards[i] = next
		path[i].forwards[i] = newNode
	}

	// 更新level
	if level > list.level {
   
		list.level = level
	}

	list.length++

	return errors.New("插入失败")
}

func (list *skipList[T]) Delete(data T, score int32) int {
   
	currenNode := list.head
	// 找到插入的位置
	// 记录插入的路径 记录第一个比待查找的值小的位置
	path := [MAX_LEVEL]*skipListNode[T]{
   }
	for i := list.level - 1; i >= 0; i-- {
   
		path[i] = list.head
		for currenNode.forwards[i] != nil {
   
			// 記錄刪除的位置
			if currenNode.forwards[i].score == score && currenNode.forwards[i].data == data {
   
				path[i] = currenNode
				break
			}
			// 插入位置比当前的大,在当前层继续往前找
			currenNode = currenNode.forwards[i]
		}
	}

	currenNode = path[0].forwards[0]
	for i := currenNode.level - 1; i >= 0; i-- {
   
		if path[i] == list.head && currenNode.forwards[i] == nil {
   
			list.level = i
		}

		if nil == path[i].forwards[i] {
   
			path[i].forwards[i] = nil
		} else {
   
			path[i].forwards[i] = path[i].forwards[i].forwards[i]
		}
	}

	list.length--

	return 0
}

func (list skipList[T]) FindNode(v T, score int32) (err error, node *skipListNode[T]) {
   

	cur := list.head
	for i := list.level - 1; i >= 0; i-- {
   
		for nil != cur.forwards[i] {
   
			if cur.forwards[i].score == score && cur.forwards[i].data == v {
   
				return nil, cur.forwards[i]
			} else if cur.forwards[i].score > score {
   
				break
			}
			cur = cur.forwards[i]
		}
	}
	return errors.New("请传入查找的值"), nil
}

测试


package main

import (
	"testing"
)

func Test_createNode(t *testing.T) {
   
	sl := createSkipList[int](0)

	sl.Insert(1, 95)
	t.Log(sl.head.forwards[0])
	t.Log(sl.head.forwards[0].forwards[0])
	t.Log(sl)
	t.Log("-----------------------------")

	sl.Insert(2, 88)
	t.Log(sl.head.forwards[0])
	t.Log(sl.head.forwards[0].forwards[0])
	t.Log(sl.head.forwards[0].forwards[0].forwards[0])
	t.Log(sl)
	t.Log("-----------------------------")

	sl.Insert(3, 100)
	t.Log(sl.head.forwards[0])
	t.Log(sl.head.forwards[0].forwards[0])
	t.Log(sl.head.forwards[0].forwards[0].forwards[0])
	t.Log(sl.head.forwards[0].forwards[0].forwards[0].forwards[0])
	t.Log(sl)
	t.Log("-----------------------------")

	t.Log(sl.FindNode(2, 88))
	t.Log("-----------------------------")

	sl.Delete(1, 95)
	t.Log(sl.head.forwards[0])
	t.Log(sl.head.forwards[0].forwards[0])
	t.Log(sl.head.forwards[0].forwards[0].forwards[0])
	t.Log(sl)
	t.Log("-----------------------------")
}

相关推荐

  1. golang实现skiplist

    2024-01-11 14:42:01       29 阅读
  2. redis底层数据结构之skiplist实现

    2024-01-11 14:42:01       45 阅读
  3. golang 基于数组、切片、链实现队列

    2024-01-11 14:42:01       27 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-11 14:42:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-11 14:42:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-11 14:42:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-11 14:42:01       20 阅读

热门阅读

  1. 【Machine Learning】Optimization

    2024-01-11 14:42:01       30 阅读
  2. 概率生成函数([CTSC2006] 歌唱王国 题解)

    2024-01-11 14:42:01       33 阅读
  3. GO项目自动化-根据库表字段自动生成API

    2024-01-11 14:42:01       30 阅读
  4. 源码编译FFmpeg4.3

    2024-01-11 14:42:01       40 阅读
  5. 【我的Rust库】get_local_info 0.1.7发布

    2024-01-11 14:42:01       27 阅读
  6. Opentsdb官方优化文档 - 翻译

    2024-01-11 14:42:01       29 阅读
  7. Android 车联网——CarOccupantZoneService介绍(十四)

    2024-01-11 14:42:01       35 阅读
  8. resulttype和parametertype的区别

    2024-01-11 14:42:01       37 阅读
  9. Vuex与Vuex-Class的底层原理简单实现

    2024-01-11 14:42:01       32 阅读
  10. leetcode面试经典150题——49 字母异位词分组

    2024-01-11 14:42:01       37 阅读
  11. 【机器学习300问】2、机器学习分为哪几类?

    2024-01-11 14:42:01       31 阅读
  12. 秒杀相关问题及答案(2024)

    2024-01-11 14:42:01       27 阅读
  13. 12.2 队列模拟

    2024-01-11 14:42:01       61 阅读
  14. Linux搭建Kafka详细一步一步指南(linux启动kafka脚本)

    2024-01-11 14:42:01       36 阅读