用Python深入理解跳躍表原理及實現

2021-09-10 02:20:45 字數 2406 閱讀 4882

最近看 redis 的實現原理,其中講到 redis 中的有序資料結構是通過跳躍表來進行實現的。第一次聽說跳躍表的概念,感到比較新奇,所以查了不少資料。其中,網上有部分文章是按照如下方式描述跳躍表的:

這種描述便於理解,很容易讓人理解到跳躍表是建立了類似索引的東西,從而提高效率的。但是,這樣描述給人的感覺是,資料有多份儲存,每份資料有兩個指標,指向下層資料的指標和指向右面資料的指標。然而實際並不是這樣的,實際的資料結構如下:

即:並非由多份資料,而是每份資料有多層指標。

那麼,什麼是跳躍表,跳躍表有什麼特點呢?

從定義中可以看出,跳躍表是為了解決平衡樹插入或者刪除操作過於複雜而進行設計的。的確,平衡樹在插入或者刪除時,需要維持平衡而進行過多的操作,學過資料結構的同學想到平衡樹、紅黑樹等都不寒而慄吧。而跳躍表則沒有這種問題,採用了隨機的思想簡化了維持平衡的過程,而保持查詢的時間複雜度依舊是o(log n)。

跳躍表有如下特點:

(1) 每個跳躍表由很多層結構組成;

(2) 每一層都是乙個有序鍊錶,且第乙個節點是頭節點;

(3) 最底層的有序鍊錶包含所有節點;

(4) 每個節點可能有多個指標,這與節點所包含的層數有關;

(5) 跳躍表的查詢、插入、刪除的時間複雜度均為o(log n)。

從上面的結構也可以看出,跳躍表的核心思想就是,每乙個節點既包含指向下乙個節點的指標,也可能包含很多個指向後續節點的指標,這樣在查詢、插入、刪除某個節點的過程中,可以避免一些不必要的節點,從而提高效率。

所以,每個節點的資料結構設計如下:

跳躍表的設計如下:

那麼,如何進行查詢呢?

假設查詢5,那麼在查詢的過程中,需要從最高層開始查詢(畢竟,越高層越表示索引嘛,很可能一下子就找到資料了),如果元素小於5,則一直向右查詢。若遇到大於5的,則降低一層,在下一層繼續查詢。查詢的流程如下圖所示:

查詢的**如下:

插入的過程是怎麼樣的呢?

插入的過程包括如下4個步驟:

1、首先,需要找到每一層要插入節點的位置,並儲存(用於後續調整指標);

2、確定該節點包含的層數,初始化要插入的節點;

3、相關的指標的調整;

4、若跳躍表層數增加,需要調整header節點。

如下圖,若要插入key 為4.5的節點,先要找到需要插入的位置,如圖中黃線所示,然後隨機生成乙個層數(範圍是1層到當前跳躍表層數+1,隨機數生成器可以自行設計),初始化該節點,然後進行調整指標。

假設隨機生成的層數為3,那麼插入後為:

是不是比平衡樹簡單多了?當然,如果隨機生成的層數為 當前跳躍表層數+1,那麼跳躍表層數增加一層,header節點需要增加一層。

python實現如下:

刪除操作呢?跟插入操作類似,但是更為簡單,只需要如下3個步驟:

1、首先,需要找到每一層要刪除節點的位置,並儲存(用於後續調整指標);

2、相關的指標的調整;

3、若層數減少,需要調整跳躍表層數和header節點。

如果刪除6這個節點,找到相應的位置,然後調整指標即可:

刪除後的結果為:

python**實現為:

這裡需要注意,如果刪除元素後導致層數發生變化,那麼需要對header節點進行調整的,即降低一層。

跳躍表的原理及實現你是否深入理解了?

深入理解Android EventBus原理

1.定義乙個evnet public static class messageevent2.準備觀察者 宣告和注釋你的訂閱方法,可選地指定執行緒模式 subscribe threadmode threadmode.main 比如這個就指定主線程 關於型別的解釋介紹請查閱 註冊和反註冊在你的使用中,例...

深入理解用mysql fetch

同mysql result 一樣,mysql fetch row 也可以用來獲取查詢結果集,其區別在於函式的返回值不是乙個字串,而是乙個陣列。函式定義如下。複製 如下 array mysql fetch row int result 引數說www.cppcns.com明如下。result 由函式my...

python深入 Python的深入理解

處理檔案和目錄 python 3 帶有乙個模組叫做 os,代表 作業系統 operating system os 模組 包含非常多的函式用於獲取 和修改 本地目錄 檔案程序 環境變數等的資訊。python 盡最大的努力在所有支援的作業系統上提供乙個統一的api,這樣你就可以在保證程式能夠在任何的計算...