当前位置:首页 > Rust > 正文

Rust跳表数据结构实现(从零开始构建高性能有序集合)

在现代编程中,Rust跳表实现 是一个既高效又相对容易理解的数据结构选择。跳表(Skip List)是一种概率性的数据结构,它通过多层链表来加速查找、插入和删除操作,平均时间复杂度为 O(log n)。本文将手把手教你用 Rust 语言从零实现一个跳表,适合 Rust 初学者和对Rust数据结构感兴趣的开发者。

什么是跳表?

跳表由 William Pugh 在 1989 年提出,它通过维护多个层级的“快速通道”来跳过大量元素,从而加快搜索速度。最底层包含所有元素,而上层则随机地包含部分元素,形成索引。

Rust跳表数据结构实现(从零开始构建高性能有序集合) Rust跳表实现 Rust数据结构 跳表教程 Rust并发数据结构 第1张

为什么选择跳表?

  • 实现比平衡树(如红黑树)简单
  • 支持高效的范围查询
  • 天然支持并发(在Rust并发数据结构中很有优势)
  • 平均性能接近 O(log n)

Rust 跳表实现步骤

我们将分步构建一个支持插入、查找和删除的跳表。首先定义节点结构:

use std::collections::HashMap;use rand::Rng;// 跳表节点:每一层都有一个 next 指针#[derive(Debug)]struct SkipNode<T> {    value: T,    forward: Vec<Option<*mut SkipNode<T>>>,}impl<T> SkipNode<T> {    fn new(value: T, level: usize) -> Self {        SkipNode {            value,            forward: vec![None; level],        }    }}

注意:我们使用裸指针(*mut)是为了避免所有权问题,但在实际项目中建议使用 Rc<RefCell<...>> 或更安全的智能指针。为了简化,本教程使用不安全代码块处理指针。

定义跳表主结构

const MAX_LEVEL: usize = 16;const P: f64 = 0.5; // 随机提升层级的概率pub struct SkipList<T: Ord + Clone> {    head: *mut SkipNode<T>,    level: usize,    length: usize,}impl<T: Ord + Clone> SkipList<T> {    pub fn new() -> Self {        let head_node = Box::into_raw(Box::new(SkipNode::new(            // 使用默认值占位,实际不会被访问            unsafe { std::mem::zeroed() },            MAX_LEVEL,        )));        SkipList {            head: head_node,            level: 0,            length: 0,        }    }}

生成随机层级

跳表的关键在于随机决定新节点应出现在多少层:

fn random_level() -> usize {    let mut level = 1;    let mut rng = rand::thread_rng();    while level < MAX_LEVEL && rng.gen_bool(P) {        level += 1;    }    level}

插入操作实现

pub fn insert(&mut self, value: T) {    let update: Vec<*mut SkipNode<T>> = vec![self.head; MAX_LEVEL];    let mut current = self.head;    // 从最高层开始向下搜索    for i in (0..=self.level).rev() {        unsafe {            while let Some(next) = (*current).forward[i] {                if (*next).value < value {                    current = next;                } else {                    break;                }            }            update[i] = current;        }    }    // 检查是否已存在    unsafe {        if let Some(next) = (*current).forward[0] {            if (*next).value == value {                return; // 已存在,不重复插入            }        }    }    // 生成新层级    let new_level = random_level();    if new_level > self.level {        for i in (self.level + 1)..=new_level {            update[i] = self.head;        }        self.level = new_level;    }    // 创建新节点    let new_node = Box::into_raw(Box::new(SkipNode::new(value, new_level + 1)));    // 更新 forward 指针    unsafe {        for i in 0..=new_level {            (*new_node).forward[i] = (*update[i]).forward[i];            (*update[i]).forward[i] = Some(new_node);        }    }    self.length += 1;}

查找与删除(简要说明)

查找逻辑与插入前半部分相同;删除则需先找到目标节点,再更新各层指针。完整实现可参考开源项目如 skiplist crate。

安全提示与改进建议

本教程使用了 unsafe 代码以简化指针操作。在生产环境中,建议:

  • 使用 Arc<Mutex<...>> 实现线程安全
  • Rc<RefCell<SkipNode>> 替代裸指针
  • 添加 Drop trait 自动释放内存

总结

通过本篇跳表教程,你已经掌握了如何在 Rust 中实现一个基础跳表。跳表不仅性能优秀,而且逻辑清晰,是学习高级Rust数据结构的理想起点。希望你能在此基础上构建更强大的并发或持久化跳表!

关键词回顾:Rust跳表实现、Rust数据结构、跳表教程、Rust并发数据结构