1 前言
在上一篇文章中,概要介紹了Redis的第一種數據結構SDS(Simple Dynamic String)之後,本文將進一步介紹Redis中的另一種數據結構——鏈表。
2 什麼是鏈表
鏈表,作爲數據結構中的基礎結構,理解起來非常簡單。以下是摘自百度百科中,對鏈表的定義。
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱爲結點)組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。
3 Redis鏈表的定義及實現
在C語言中,沒有內置鏈表數據結構,所以,Redis構建了自己的鏈表實現。參考Redis源碼可知,鏈表的數據結構定義分成兩部分。
第一部分:ListNode
從上圖可知,Redis中的鏈表節點,採用雙端鏈表節點的設計方式,即每個節點都有指向自己前置節點和後置節點的指針域,同時包含節點本身的值域。
而採用雙端鏈表,在之後實現對鏈表的讀寫上,能夠極大降低時間複雜度。
第二部分:List
從上圖可知,雙端鏈表的數據結構中,包括以下內容
1 *head :指向鏈表頭結點的指針
2 *tail: 指向鏈表表尾節點的指針
3 *(*dup)(void *ptr):節點值複製函數
4 (*free)(void *ptr):節點值釋放函數
5 *match)(void *ptr, void *key):節點值對比函數
6 len :鏈表包含的節點數量
此外,雙端鏈表的數據結構定義中,還有一種輔助迭代器數據結構,用於迭代鏈表,即——雙端鏈表迭代器
這裏說明一下迭代方向 direction值:adlist.h的頭文件中,預定義了兩個int類型變量,用於指示鏈表的迭代方向。
4 Redis中使用鏈表的優勢
鏈表提供了高效的節點重排能力,以及順序性的節點訪問方式,並且可以通過增刪節點來靈活調整鏈表的長度。
而Redis將鏈表數據結構定義成雙端鏈表,將具有以下性能優勢:
1 雙端:每個鏈表節點都帶有prev和next指針,所以在獲取某個節點的前置節點和後置節點的複雜度都是O(1)
2 帶表頭和表尾指針:通過list結構的head指針和tail指針,程序獲取鏈表表頭和表尾節點的時間複雜度爲O(1)
3 自帶長度計數器:鏈表數據結構中的len屬性,用來對list持有的節點數進行統計,能夠在時間複雜度爲O(1)的前提下獲取鏈表中的節點數量。
4 多態:鏈表的數據結構中,內置了三個函數(dup、free、match),同事鏈表節點使用void*指針來保存節點值,並且可以通過這三個函數設置特定的數據類型,所以,鏈表可以用來保存各種不同類型的值。