跳表

顺序数组可以使用二分法快速搜索到元素,但是顺序链表需要遍历才能找到相应元素。插入、删除同理,跳表可以对链表进行优化,使得插入、查找、删除的时间复杂度都为nlogn,其原理在于使用多级索引

参考:数据结构之跳表

golang 实现:

package main

import (
	"fmt"
	"math/rand"
	"time"
)

type List interface {
	Insert(data int)
	Delete(data int) bool
	Search(data int)
}

type SkipList struct {
	maxLevel int   // 最大层数
	head     *Node // 开始结点
	level    int   // 当前层数
}

type Node struct {
	Data int     // 值
	Next []*Node // 下一个结点 Next[1] 第一层的下一结点 Next[2] 第二层的下一节点
}

func NewSkipList(maxLevel int) *SkipList {
	headNode := new(Node)
	headNode.Next = make([]*Node, maxLevel)
	return &SkipList{
		maxLevel: maxLevel,
		head:     headNode,
		level:    1, // 初始化为1层
	}
}

func NewNode(level int, data int) *Node {
	return &Node{
		Data: data,
		Next: make([]*Node, level),
	}
}

func init() {
	rand.Seed(time.Now().UnixNano())
}

// 获取随机层数
func (sl *SkipList) randomLevel() int {
	level := 1
	if rand.Float32() < 0.5 && level < sl.maxLevel {
		level++
	}

	return level
}

func (sl *SkipList) Insert(data int) {
	update := make([]*Node, sl.maxLevel) // 每层插入结点的前一个结点
	// 找到插入的位置
	node := sl.head
	for level := sl.maxLevel; level > 0; level-- {
		for node.Next != nil && node.Next[level-1] != nil && node.Next[level-1].Data < data {
			node = node.Next[level-1]
		}
		update[level-1] = node
	}

	newLevel := sl.randomLevel() // 新插入的结点的层数
	if newLevel > sl.level {
		sl.level = newLevel
	}

	newNode := NewNode(newLevel, data)
	for level := newLevel; level > 0; level-- {
		// 新结点的当前层级的下一个值
		newNode.Next[level-1] = update[level-1].Next[level-1]
		update[level-1].Next[level-1] = newNode
	}
}

func (sl *SkipList) Delete(data int) (success bool) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}

		success = false
		return
	}()

	node := sl.head
	for level := sl.level; level > 0; level-- {
		for node.Next != nil && node.Next[level-1].Data < data {
			node = node.Next[level-1]
		}
		// 下一个是删除结点,则把指针指向下下个
		if node.Next != nil && node.Next[level-1].Data == data {
			node.Next[level-1] = node.Next[level-1].Next[level-1]
		}
	}

	return true
}

// 搜索打印搜索轨迹
func (sl *SkipList) Search(data int) {
	node := sl.head
	for level := sl.level; level > 0; level-- {

		for node.Next != nil && node.Next[level-1] != nil && node.Next[level-1].Data <= data {
			fmt.Print(node.Data, "--->")
			node = node.Next[level-1]
		}
		if node.Data == data {
			fmt.Print(node.Data)
			return
		}
	}
}

// 打印跳表
func (sl *SkipList) print() {
	for level := sl.level; level > 0; level-- {
		node := sl.head
		for node.Next != nil && node.Next[level-1] != nil {
			fmt.Print(node.Data, "----")
			node = node.Next[level-1]
		}
		fmt.Print("nil")
		fmt.Println()
	}
}

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	sl := NewSkipList(4)

	sl.Insert(1)
	sl.Insert(3)
	sl.Insert(5)
	sl.Insert(7)

	sl.Search(5)
	fmt.Println()
	sl.print()

	fmt.Println("after delete")

	sl.Delete(3)
	sl.Search(5)
	fmt.Println()
	sl.print()
}

result:

0--->1--->3--->5
0----1----3----nil
0----1----3----5----nil
after delete
0--->1--->5
0----1----nil
0----1----5----nil
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值