Redisでの両端リンクリストの実装

リリース: 2020-04-03 09:40:23
転載
2164 人が閲覧しました

Redisでの両端リンクリストの実装

adlist は、Redis の両端リンク リストとして、スローログのストレージ、マスター/スレーブ レプリケーションのエラー報告クライアントなど、Redis の多くの場所で広く使用されています。リストデータ構造の実装などに関係するものが多く、非常に重要なデータ構造でもあります。

1) Redis の両端リンク リストのデータ構造

(推奨: redis ビデオ チュートリアル)

両端リンク リスト (次のコードは src/adlist.h で定義されます):

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;
ログイン後にコピー

両端リンク リストのノード (次のコードは src/adlist.h で定義されます):

typedef struct listNode {
    struct listNode *prev;   //当前节点的上一个节点
    struct listNode *next;   //当前节点的下一个节点
    void *value;     //当前节点存储的值,可以任意类型
} listNode;
ログイン後にコピー

Redisでの両端リンクリストの実装

list through head 2 つのポインタとテールはそれぞれ、リンク リストの先頭と末尾を指すため、リンク リストは正の順序と負の順序の両方でトラバースできます。データであり、dup、free、match を通じてカスタマイズできます。 listNode の値を処理する方法。

2. 両端リンク リストの簡単な操作

リンク リストを作成します (次のコードは src/adlist.c に定義されています):

list *listCreate(void)
{
    struct list *list;    //初始化链表
    
    //为链表分配内存
    if ((list = zmalloc(sizeof(*list))) == NULL)
        return NULL;
    //为空链表设置初始值
    list->head = list->tail = NULL;
    list->len = 0;
    list->dup = NULL;
    list->free = NULL;
    list->match = NULL;
    return list;
}
ログイン後にコピー

リンク リストの末尾に追加します (以下のコードは src/adlist.c で定義されています):

list *listAddNodeTail(list *list, void *value)
{
    listNode *node;    //初始化node节点

    //为新的node节点分配内存
    if ((node = zmalloc(sizeof(*node))) == NULL)
        return NULL;
    //为node节点设置值
    node->value = value;
    
    if (list->len == 0) {
        //如果空链表则 将头尾指向 新节点 并后继前驱节点设置为NULL
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {
        //否则将节点的前驱节点设置为原来的尾部节点
        node->prev = list->tail;
        //由于追加到尾部,后继节点为NULL
        node->next = NULL;
        //之前的尾部节点的后继节点设置为新增的节点
        list->tail->next = node;
        //将列表的尾部节点指针指向新增的节点
        list->tail = node;
    }
    //增加链表长度
    list->len++;
    return list;
}
ログイン後にコピー

リンク リストを走査する:

リンク リストを走査するには、一般的に 2 つの方法が使用されます。リストの 1 つは、リンク リストの長さに応じて while ループを介してリンク リストを手動で走査する方法で、もう 1 つは Redis の両端リンク リストによって提供されるイテレータを使用して走査する方法です。

手動トラバーサル (次のコードは、src/adlist.c のメモリ解放関数で定義されています):

void listRelease(list *list)
{
    unsigned long len;
    //current表示当前遍历的游标指针,next表示下次遍历的游标指针(next作为临时变量用于保存下一个节点)
    listNode *current, *next;
    //将current指向头部节点
    current = list->head;
    //计算长度(其实就是 listLength(list))
    len = list->len;
    //通过长度递减的方式进行遍历,便利到长度为0的时候,遍历结束
    while(len--) {
        //保存下次循环的节点指针
        next = current->next;
        //释放掉当前节点,如果设置释放节点的回调函数,则执行用户自定义的函数
        if (list->free) list->free(current->value);
        zfree(current);
        //将游标指向下个节点
        current = next;
    }
    zfree(list);
}
ログイン後にコピー

イテレータ モードのトラバーサルについては、以下を参照してください。

3) 両端リンク リストのイテレータ

リンク リストの反復を容易にするために、Redis はリンク リストのイテレータをカプセル化します。イテレータの構造は次のとおりです (以下のコードは src/adlist .h) で定義されています:

typedef struct listIter {
    listNode *next;    //迭代器指向的下一个节点
    //迭代方向,由于双端链表保存了head和tail的值,所以可以进行两个方向的迭代
    //AL_START_HEAD表示从头向后遍历,AL_START_TAIL表示从尾部向前遍历
    int direction;
} listIter;
ログイン後にコピー

イテレーターの使用例:

//l表示list结构,n表示listNode结构,listNode的值保存的是sds字符串
//创建迭代器对象
iter = listGetIterator(l, AL_START_HEAD);
//循环获取下一个需要遍历的节点
while ((n = listNext(iter))) {
    //输出返回的节点n的value值
    printf("Node Value: %s\n", listNodeValue(n));
}
ログイン後にコピー

Redis の詳細については、redis 入門チュートリアル 列に注目してください。

以上がRedisでの両端リンクリストの実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:oschina.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!