数据结构 - 跳表
跳表 练手

介绍

跳表的特性是利用空间复杂度换时间复杂度,其性能与红黑树、AVL树差距不大,且编码原理易懂。原理与编码可参考Leetcode题解

代码

type Node struct {
	value int
	level int
	forwards []*Node
}

// 创建节点
func CreateNode(value int, level int) *Node {
	return &Node{value, level, make([]*Node, level)}
}

const (
	MAX_LEVEL = 32
	P_FACTOR = 0.25
)

type Skiplist struct {
	head *Node
	// 当前跳表的层级
	level int
}

func Constructor() Skiplist {
	return Skiplist{CreateNode(math.MinInt32, MAX_LEVEL), 1}
}

func (s *Skiplist) Add(value int) {
	cur := s.head
	update := make([]*Node, MAX_LEVEL)
	// 由于插入的节点level是随机的,因此update需要初始化加入head对象
	for i := range update {
		update[i] = s.head
	}

	// 从当前层级往下遍历
	for i := s.level - 1; i >= 0; i-- {
		// 遍历直到当前指针的下一跳指向nil或者下一跳数值大于等于传入值
		for cur.forwards[i] != nil && cur.forwards[i].value < value {
			cur = cur.forwards[i]
		}
		// 记录当前层走过的节点,即cur,随后往下一层走
		update[i] = cur
	}

	// 生成随机层数
	level := 1
	for i := 1; i < MAX_LEVEL; i++ {
		if rand.Float64() < P_FACTOR {
			level++
		}
	}
	// 更新当前跳表层级
	if level > s.level {
		s.level = level
	}

	// 创建新节点
	newNode := CreateNode(value, level)

	// 将新节点插入跳表中
	for i := newNode.level - 1; i >= 0; i-- {
		update[i].forwards[i], newNode.forwards[i] = newNode, update[i].forwards[i]
	}
}

func (s *Skiplist) Erase(value int) bool {
	cur := s.head
	update := make([]*Node, MAX_LEVEL)

	// 从当前层级往下遍历
	for i := s.level; i >= 0; i-- {
		// 遍历直到当前指针的下一跳指向nil或者下一跳数值大于等于传入值
		for cur.forwards[i] != nil && cur.forwards[i].value < value {
			cur = cur.forwards[i]
		}

		update[i] = cur
	}

	// 移位到下一跳,因为下一跳必定满足cur.forwards[i] == nil || cur.forwards[i].value >= value
	cur = cur.forwards[0]
	// 若不存在或不匹配,返回false
	if cur == nil || cur.value != value {
		return false
	}

	// 删除节点
	for i := cur.level - 1; i >= 0; i-- {
		update[i].forwards[i] = cur.forwards[i]
	}

	// 更新当前跳表的level
	for s.level > 1 && s.head.forwards[s.level - 1] == nil {
		s.level--
	}
	return true
}

func (s *Skiplist) Search(value int) bool {
	cur := s.head

	// 从当前层级往下遍历
	for i := s.level - 1; i >= 0; i-- {
		// 遍历直到当前指针的下一跳指向nil或者下一跳数值大于等于传入值
		for cur.forwards[i] != nil && cur.forwards[i].value < value {
			cur = cur.forwards[i]
		}
		// 找到了,返回true
		if cur.forwards[i] != nil && cur.forwards[i].value == value {
			return true
		}
	}
	return false
}

相关题目

1206. 设计跳表

难度困难208收藏分享切换为英文接收动态反馈

不使用任何库函数,设计一个 跳表


最后修改于 2022-07-26