🍳前言
继续是算法的有序表的学习笔记,这篇博客来实现一个跳表。😂虽然好像工作也用不上就是了,单纯想看看算法…
简单来说,跳表是一种具有多级随机生成索引的有序链表。跳表由多个有序链表组成,每个链表称为一层。最底层的链表包含所有节点,节点在加入时有概率加入高层的链表中,越高层的链表节点越稀疏,越低层越稠密。搜索时先从高层索引开始,找到右侧大于目标值的时候,再往下一层搜索。通过索引,跳表可以实现 的时间复杂度下进行增删改查操作。同时它实现简单,没有类似平衡树复杂的调整操作。得益于这两点,跳表被广泛应用于各种场景中,例如 Redis、LevelDB。
🍟类型定义
和上次类似,除了实现基本的增删改查外,再实现序号和前驱后继的查询。
节点加入时,会获得一个随机的level
作为节点的最高层数。为了实现多层的索引,跳表的每一个节点的后继指针这里使用一个数组来表示。
每一个跳表节点SkipListNode
包含以下属性:
key
,用于排序的键值;level
,节点索引的层数;count
,插入该节点的数量;- 'next`,每一层指向下一个节点的指针;
span
,每一层指针,跨越最底层节点的数量,左开右闭的区间,用于方便实现序号和前驱后继的查询。
对于跳表,为了做到 的时间复杂度,跳表层数一般为数据量 2 为底(大概,具体看实现)的对数。
rust- #[derive(Debug, Clone)]
- struct SkipListNode {
- key: i32,
- count: i32,
- level: usize,
- span: Vec<i32>,
- next: Vec<OptionSkipListNodeRc>
- }
- type SkipListNodeRc = Rc<RefCell<SkipListNode>>;
- type OptionSkipListNodeRc = Option<
- SkipListNodeRc
- >;
- struct SkipList {
- head: SkipListNodeRc,
- max_level: usize
- }
- impl SkipListNode {
- fn new(key: i32, level: usize) -> Rc<RefCell<Self>> {
- Rc::new(RefCell::new(Self {
- key,
- count: 1,
- level,
- next: vec![None; level + 1],
- span: vec![0; level + 1],
- }))
- }
- }
- impl SkipList {
- fn new(max_level: usize) -> Self {
- SkipList { head: SkipListNode::new(i32::MIN, max_level), max_level }
- }
- }
🌮搜索节点
搜索时先从高层索引开始,找到右侧大于目标值的时候,再往下一层搜索,直到到达最底层,右侧节点大于目标值或者不存在为止。如果节点和目标值相等就找到了。
rust- fn find(mut node: SkipListNodeRc, level: usize, key: i32) -> OptionSkipListNodeRc {
- loop {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- if next.borrow().key < key {
- node = next;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- if level == 0 {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- if next.borrow().key == key {
- return Some(next);
- } else {
- return None;
- }
- } else {
- return None;
- }
- }
- return Self::find(node, level - 1, key)
- }
🍔加入节点
加入节点分为两种情况。当需要加入的节点存在时,只需要给它count
加 1,更新左侧各层节点的跨越的距离span
就好了。
rust- fn insert(&mut self, key: i32) {
- if Self::find(self.head.clone(), self.max_level, key).is_some() {
- Self::add_count(self.head.clone(), self.max_level, key);
- } else {
- // ...
- }
- }
- fn add_count(mut node: SkipListNodeRc, level: usize, key: i32) {
- loop {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- if next.borrow().key < key {
- node = next;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- if level == 0 {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- next.borrow_mut().count += 1;
- }
- } else {
- Self::add_count(node.clone(), level - 1, key);
- }
- node.borrow_mut().span[level] += 1;
- }
当节点不存在时,需要搜索到最底层适合添加节点的地方,插入节点,然后通过搜索时记录的向右移动距离更新左侧节点的span
。
ts- fn get_level(&self) -> usize {
- let mut n = 0;
- while rand::random::<bool>() && n < self.max_level {
- n += 1;
- }
- n
- }
- // ...
- fn insert(&mut self, key: i32) {
- if Self::find(self.head.clone(), self.max_level, key).is_some() {
- Self::add_count(self.head.clone(), self.max_level, key);
- } else {
- let node_level = self.get_level();
- let new_node = SkipListNode::new(key, node_level);
- Self::insert_node(self.head.clone(), self.max_level, new_node);
- }
- }
- fn insert_node(mut node: SkipListNodeRc, level: usize, new_node: SkipListNodeRc) -> i32 {
- let mut left_offset = 0;
- loop {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- if next.borrow().key < new_node.borrow().key {
- left_offset += node.borrow().span[level];
- node = next;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- if level == 0 {
- {
- let mut new_node_borrow = new_node.borrow_mut();
- new_node_borrow.next[level] = node.borrow().next[level].clone();
- new_node_borrow.span[level] = if new_node_borrow.next[level].is_some() { new_node_borrow.next[level].clone().unwrap().borrow().count } else { 0 };
- }
- {
- let mut node_boorow = node.borrow_mut();
- node_boorow.next[level] = Some(new_node.clone());
- node_boorow.span[level] = new_node.borrow().count;
- }
- left_offset
- } else {
- let down_offset = Self::insert_node(node.clone(), level - 1, new_node.clone());
- if level > new_node.borrow().level {
- node.borrow_mut().span[level] += 1;
- } else {
- {
- let mut new_node_borrow = new_node.borrow_mut();
- new_node_borrow.next[level] = node.borrow().next[level].clone();
- new_node_borrow.span[level] = node.borrow().span[level] - down_offset;
- }
- {
- let mut node_borrow = node.borrow_mut();
- node_borrow.next[level] = Some(new_node.clone());
- node_borrow.span[level] = down_offset + new_node.borrow().count;
- }
- }
- left_offset + down_offset
- }
- }
🥗删除节点
和添加节点相似,如果节点count
大于 1,则减少count
,否则移除节点,然后更新左侧的span
。
ts- fn remove(&mut self, key: i32) -> bool {
- assert!(self.head.borrow().key != key || self.head.borrow().count != 1, "Cannot delete the head node!");
- let node = Self::find(self.head.clone(), self.max_level, key);
- match node {
- None => false,
- Some(x) => {
- if x.borrow().count > 1 {
- Self::remove_count(self.head.clone(), self.max_level, key);
- } else {
- Self::remove_node(self.head.clone(), self.max_level, x.clone());
- }
- true
- }
- }
- }
- fn remove_count(mut node: SkipListNodeRc, level: usize, key: i32) {
- loop {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- if next.borrow().key < key {
- node = next;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- if level == 0 {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- next.borrow_mut().count -= 1;
- }
- } else {
- Self::remove_count(node.clone(), level - 1, key);
- }
- node.borrow_mut().span[level] -= 1;
- }
- fn remove_node(mut node: SkipListNodeRc, level: usize, node_deleting: SkipListNodeRc) {
- let node_deleting_key = node_deleting.borrow().key;
- loop {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- if next.borrow().key < node_deleting_key {
- node = next;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- if level > node_deleting.borrow().level {
- node.borrow_mut().span[level] -= 1;
- } else {
- node.borrow_mut().next[level] = node_deleting.borrow().next[level].clone();
- node.borrow_mut().span[level] += node_deleting.borrow().span[level] - 1;
- }
- if level > 0 {
- Self::remove_node(node, level - 1, node_deleting);
- }
- }
🥪排名的查询
rank
函数获取传入的key
在跳表中的排名,index
函数获取传入排名在跳表中对应元素,这都可以通过跳表的span
便捷计算遍历越过的节点数量来完成。
rust- fn rank(&self, key: i32) -> i32 {
- Self::rank_helper(self.head.clone(), self.max_level, key) + 1
- }
- fn rank_helper(mut node: SkipListNodeRc, level: usize, key: i32) -> i32 {
- let mut left_offset = 0;
- loop {
- let next = node.borrow().next[level].clone();
- if let Some(next) = next {
- if next.borrow().key < key {
- left_offset += node.borrow().span[level];
- node = next;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- if level == 0 {
- return left_offset;
- } else {
- return left_offset + Self::rank_helper(node, level - 1, key);
- }
- }
- fn index(&self, idx: i32) -> i32 {
- Self::index_helper(self.head.clone(), self.max_level, idx)
- }
- fn index_helper(mut node: SkipListNodeRc, level: usize, idx: i32) -> i32 {
- if idx < 1 {
- return i32::MIN
- }
- let mut acc = 0;
- while node.clone().borrow().next[level].is_some() && acc < idx - node.borrow().span[level] {
- acc += node.borrow().span[level];
- let next_node = node.borrow().next[level].clone();
- match next_node {
- None => break,
- Some(x) => {
- node = x;
- }
- }
- }
- if level == 0 {
- let next_node = node.borrow().next[level].clone();
- match next_node {
- None => i32::MAX,
- Some(x) => {
- x.borrow().key
- }
- }
- } else {
- Self::index_helper(node, level - 1, idx - acc)
- }
- }
🧇前驱后继查询
前驱后继的查询,就是找出小于目标值的最大节点或者大于目标值的最小节点。这个查询在跳表中非常方便,找到最底层小于目标值的最右节点,就是前驱,它右侧第二个节点就是后继。
rust- fn pre(&self, key: i32) -> i32 {
- Self::pre_helper(self.head.clone(), self.max_level, key)
- }
- fn pre_helper(node: SkipListNodeRc, level: usize, key: i32) -> i32 {
- let mut cur_node = Some(node.clone());
- while cur_node.is_some() {
- match cur_node.clone() {
- None => {
- break;
- },
- Some(x) => {
- if x.borrow().next[level].is_some() && x.borrow().next[level].clone().unwrap().borrow().key < key {
- cur_node = x.borrow().next[level].clone();
- } else {
- break;
- }
- }
- }
- }
- if level == 0 {
- let key = cur_node.clone().unwrap().borrow().key;
- if key == i32::MIN {
- i32::MIN
- } else {
- key
- }
- } else {
- Self::pre_helper(cur_node.clone().unwrap(), level - 1, key)
- }
- }
- fn next(&self, key: i32) -> i32 {
- Self::next_helper(self.head.clone(), self.max_level, key)
- }
- fn next_helper(node: SkipListNodeRc, level: usize, key: i32) -> i32 {
- let mut cur_node = Some(node.clone());
- while cur_node.is_some() {
- match cur_node.clone() {
- None => {
- break;
- },
- Some(x) => {
- if x.borrow().next[level].is_some() && x.borrow().next[level].clone().unwrap().borrow().key < key {
- cur_node = x.borrow().next[level].clone();
- } else {
- break;
- }
- }
- }
- }
- if level == 0 {
- let next = cur_node.clone().unwrap().borrow().next[0].clone();
- match next {
- None => i32::MAX,
- Some(x) => {
- if x.borrow().key > key {
- x.borrow().key
- } else {
- let next_next = x.borrow().next[0].clone();
- match next_next {
- None => i32::MAX,
- Some(x) => {
- x.borrow().key
- }
- }
- }
- }
- }
- } else {
- Self::next_helper(cur_node.clone().unwrap(), level - 1, key)
- }
- }
🥚结语
这里是在复习(学习)算法和数据结构和 rust 的程序员,这个博客使用 rust 构建了一个链表,包含了完整的增加、删除、查找,和排名、前驱后继的查询功能。
这篇博客用 rust 实现了一个 AVL 树,并且实现了对排序、前驱后继节点查询的操作。
参考:
【算法讲解149【扩展】有序表专题2-跳表】 https://www.bilibili.com/video/BV1HZ1jYMEt3/?share_source=copy_web&vd_source=a06db201a5f7fab5fe54f12bff164f84