本次學習除了基本內容以外主要思考三個問題:why(爲何)、what(原理是什麼)、which(同類中還有哪些相似的東西,相比有什麼區別)。html
因爲我對 java 比較熟悉,而且 java 中也有字符串和鏈表。因此本篇暫拿 redis 中的字符串和鏈表與 java 進行對比。java
先看幾個問題:node
因爲 C 語言的字符數組有着以上的侷限性,因此 redis 和 java 都從新定義了本身的字符串結構。redis
redis 中的字符串是本身構建了一種叫作簡單動態字符串(SDS)的抽象類型標識的。它的具體結構以下:數組
struct sdshdr { //字符串長度 int len; // buf中未使用的字節數 int free; // 字節數組,用於保存字符串 char buf[]; }
redis 的這個數據結構,很好的解決了 C 語言字符數組的第一、二、三、4點侷限性。並且值得注意的是 sdshdr 中的 buf 數組,也是以「\0」結尾的,因此buf的總長度爲:len + free + 1。那麼爲何要浪費這一個字節呢?主要是想重用 C 語言對於字符串的一些函數,好比鏈接、輸出等等。緩存
這裏有一個點須要注意一下,就是 redis 不會對存儲的字符串進行編碼,存儲和獲取都是直接經過二進制進行傳輸的,因此理論上來講只要客戶端的編碼和解碼方式同樣,是不會出現亂碼的。這也是上面 buf 的註釋裏寫字節數組的緣由。安全
java 的字符串呢?則是直接把字符串搞成了一個常量。以下:數據結構
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 ...... }
java 的字符串也解決了c語言字符數組的第 1/2/3/4 點。函數
如今咱們再回去看一下 redis 中字符串的結構,有一個數組,有數組中存儲數據的長度。想到了什麼?Java中 StringBuilder、StringBuffer、ArrayList 是否是都是這個結構?他們的共同點呢?是否是都是可變的數組( StringBuilder、StringBuffer 能夠當作可變的字符數組)?說到可變,這裏遺留一個問題:redis中的SDS、Java中的 (StringBuilder、StringBuffer、ArrayList ),他們的擴容規則分別是什麼呢?學習
形成這些差別的緣由,主要就是其定位不同。redis 的定位是緩存、要求快。java 的定位是語言,最重要的是跨平臺及擴展性。
也一樣看三個問題:
鏈表的產生主要是由於數組的侷限性。 好比:插入、刪除慢。不能動態增長元素。
redis 的鏈表結構以下:
typedef struct listNode { struct listNode *prev; //前驅節點,若是是list的頭結點,則prev指向NULL struct listNode *next;//後繼節點,若是是list尾部結點,則next指向NULL void *value; //萬能指針,可以存聽任何信息 } listNode; typedef struct list { listNode *head; //鏈表頭結點指針 listNode *tail; //鏈表尾結點指針 //下面的三個函數指針就像類中的成員函數同樣 void *(*dup)(void *ptr); //複製鏈表節點保存的值 void (*free)(void *ptr); //釋放鏈表節點保存的值 int (*match)(void *ptr, void *key); //比較鏈表節點所保存的節點值和另外一個輸入的值是否相等 unsigned long len; //鏈表長度計數器 } list;
java 的鏈表結構以下:
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{ transient int size = 0; /** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */ transient Node<E> first; /** * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */ transient Node<E> last; ....... }
基本一致,都是雙向不循環鏈表。
雙向的優勢就是能夠向前遍歷,也能夠向後遍歷。缺點就是每一個節點都須要浪費一個指針去指向前一個節點。
原文出處:https://www.cnblogs.com/wind-snow/p/11019260.html