Redis 深度解析:跳躍表的原理與應用

一、跳躍表簡介

跳躍表SkipList是一種有序的數據結構,是 Redis 有序集合的底層實現之一。

跳躍表中,數據被存儲在節點中,每個節點包含一個數據元素和一組指向其他節點的指針。這些指針分佈在不同的層級,用於提升跳躍表的訪問性能。

跳躍表支持平均O(log N)、最壞O(N)複雜度的查找性能,並且支持通過順序性操作來批量處理節點。

在大部分情況下,跳躍表的效率可以和平衡樹相媲美,並且因爲眺躍表的實現比平衡樹 要來得更爲簡單,所以有不少程序都使用跳躍表來代替平衡樹。

二、跳躍表的原理

1. 跳躍表的數據結構

跳躍表是一種擴展的有序鏈表,它通過維護一個多級索引結構來實現快速查找。在跳躍表中,每個節點包含一個數據元素和一組指向其他節點的指針。這些指針分佈在不同的層級,每個層級的指針數量都比下一層級少。最底層(第 0 層)包含所有的元素,而最高層則只包含少數幾個元素。這樣,查找操作可以在高層級開始,快速跳過那些不需要的元素。

在簡單的有序列表中,要訪問節點節點 3 需要經過節點 1、2、3 共 3 個節點;要訪問節點 9 需要經過節點 1、2、3…8、9 共 9 個節點

在跳躍表中,要訪問節點節點 3 需要經過節點 1、3 共 2 個節點(通過 L1 索引);要訪問節點 9 需要經過節點 1、7、9 共 3 個節點(通過 L3 索引)。

可以看到查找的複雜度得到極大提升。

2. 跳躍表的查找、插入和刪除操作

3. 跳躍表的時間複雜度分析

由於跳躍表的層級結構,查找、插入和刪除操作的平均時間複雜度和最壞時間複雜度都是 O(log n),其中 n 是跳躍表中元素的數量。這使得跳躍表在處理大量數據時具有很高的效率。同時,跳躍表的空間複雜度是 O(n),因爲每個元素都需要存儲在跳躍表中。

三、Redis 中的跳躍表

1. Redis 中跳躍表的實現

Redis 中的跳躍表實現與基本的跳躍表有一些不同。在 Redis 中,跳躍表的每個節點除了包含一個指向下一個節點的指針數組外,還包含一個反向指針,指向前一個節點。這樣,Redis 的跳躍表可以支持雙向遍歷。此外,Redis 的跳躍表還包含一個header節點和一個tail節點,分別指向跳躍表中的第一個節點和最後一個節點。

/* ZSETs use a specialized version of Skiplists */
typedef struct zskiplistNode {
    sds ele;
    double score;
    struct zskiplistNode *backward;
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned long span;
    } level[];
} zskiplistNode;

2. Redis 中跳躍表的特性

Redis 中的跳躍表具有以下特性:

四、跳躍表與其他數據結構的比較

1. 跳躍表與平衡樹

平衡樹(如 AVL 樹、紅黑樹等)和跳躍表都是可以進行快速查找的數據結構,它們的查找、插入和刪除操作的時間複雜度都是O(log N)。然而,平衡樹的實現通常比跳躍表複雜,需要處理更多的旋轉和平衡操作。相比之下,跳躍表的實現更簡單,更易於理解和操作。

2. 跳躍表與哈希表

哈希表的查找、插入和刪除操作的平均時間複雜度是O(1),優於跳躍表的O(log N)。然而,哈希表不支持有序操作,例如獲取最小值、最大值或者進行範圍查找。而跳躍表由於其有序性,可以很好地支持這些操作。

3. 跳躍表與鏈表

鏈表是一種基礎的數據結構,其查找、插入和刪除操作的時間複雜度是O(N)。而跳躍表是對鏈表的擴展,通過添加多級索引,將查找、插入和刪除操作的時間複雜度降低到O(log N)。同時,跳躍表保留了鏈表的有序性,可以支持一些鏈表無法支持的有序操作。

五、Redis 中跳躍表的應用場景

在 Redis 中,跳躍表主要被用於實現有序集合Sorted Set

有序集合是 Redis 支持的一種數據類型,它不僅可以存儲一組元素,還可以爲每個元素關聯一個分數。通過這個分數,Redis 可以快速地獲取分數最高或最低的元素,或者獲取滿足特定分數範圍的所有元素。這些操作都是通過跳躍表來實現的。

跳躍表在 Redis 集羣節點中用作內部數據結構。

跳躍表在 Redis 中僅用於有序集合和集羣節點內部數據結構兩種場景。

六、跳躍表的優缺點小結

優點:

缺點:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/adJJy-WM2jP9ArmXI3Y4bA