• Redis list实现原理


    双向链表

    双向表示每个节点知道自己的直接前驱和直接后继,每个节点需要三个域

    查找方向可以是从左往右也可以是从右往左,但是要实现从右往左还需要终端节点的地址,所以通常会设计成双向的循环链表;

    双向的循环链表

    循环链表指得是终端节点的next指向head节点,head的prior指向终端节点

    若链表为空 则head的next和prior都是head自己

    与普通链表不同之处就在于可以根据要查找的位置来决定遍历方向从而降低遍历次数,当要查找的数据在两端时效率更优

    也可以实现redis中list类型可以从两端插入或取值

    c语言实现:

    #include <stdio.h>
    #include <stdlib.h>
    //定义节点结构
    typedef struct Node {
        struct Node *next, *prior;
        int data, length;
    } Node, *RDLinkList;
    
    //初始化链表
    RDLinkList initialLink() {
        Node *head = malloc(sizeof(Node));
        head->next = head; //next和prior都指向自身
        head->prior = head;
        head->length = 0;
        return head;
    }
    //获取指定位置的节点
    Node *get(RDLinkList list, int position) {
        if (position<1 || position > list->length){
            return NULL;
        }
        Node *current;
        int index,reverse;
        //判断要获取的位置在左边还是右边,从而确定遍历方向,以减少遍历次数
        if (position <= (list->length / 2)){
            //目标位置小于等于中心位置 从左边开始
            index = 1;
            current = list->next;//指向首节点
            reverse = 0;
        }else{
            //目标位置大于中心位置 从右边开始
            index = list->length;
            current = list->prior;//指向终端节点
            reverse = 1;
        }
        //如果下面还有值并且还没有到达指定的位置就继续遍历
        while (current != list && position != index){
            printf("loop
    ");//查看当前循环次数
            if (reverse == 1){
                current = current->prior;
                index -= 1;
            }else{
                current = current->next;
                index += 1;
            }
        }
        if (index == position && current!=list) {
            return current;
        }
        return NULL;
    }
    //插入一个新节点到指定位置
    void insert(RDLinkList list, int data, int position) {
        Node *newNode, *pre;
        if (position == 1) {
            pre = list;
        } else {
            pre = get(list, position - 1);
        }
        //判断其位置是否可插入
        if (pre == NULL) {
            printf("位置非法");
            exit(-1);
        }
        newNode = malloc(sizeof(Node));
        newNode->data = data;
    
        newNode->next = pre->next;
        newNode->prior = pre;
        pre->next = newNode;
        newNode->next->prior = newNode;
        list->length += 1;
    }
    //删除某个位置节点
    void delete(RDLinkList list,int position){
        Node * target = get(list,position);
        if (target != NULL){
            target->prior->next = target->next;
            target->next->prior = target->prior;
            free(target);
        }
        list->length-=1;
    }
    
    //插入到左边
    void lpush(RDLinkList list,int data){
        insert(list,data,1);
    }
    //插入到右边
    void rpush(RDLinkList list,int data){
        insert(list,data,list->length+1);
    }
    Node * pop(RDLinkList list,int left){
        Node *target;
        if (left == 1){
             target = get(list,1);
        } else{
            target = get(list,list->length);
        }
        if (target != NULL){
            target->prior->next = target->next;
            target->next->prior = target->prior;
            free(target);
        }
        return target;
    }
    //弹出最左边一个元素
    Node *lpop(RDLinkList list){
        return pop(list,1);
    }
    //弹出最右边一个元素
    Node *rpop(RDLinkList list){
        return pop(list,0);
    }
    
    int main() {
        printf("Hello, World!
    ");
        RDLinkList  linkList = initialLink();
        insert(linkList,100,1);
        insert(linkList,200,2);
        insert(linkList,300,3);
        insert(linkList,400,4);
        insert(linkList,500,5);
        insert(linkList,600,6);
        insert(linkList,700,7);
        insert(linkList,800,8);
        insert(linkList,900,9);
        insert(linkList,1000,10);
        insert(linkList,1100,11);
        //查找测试 从右边遍历 只需要遍历两个节点就能找到第9个
        Node *res = get(linkList,9);
        if (res != NULL){
            printf("%d
    ",res->data);
        }
    
    //    pop  push测试
        RDLinkList  linkList2 = initialLink();
        lpush(linkList2,100);
        lpush(linkList2,200);
        rpush(linkList2,300);
        rpush(linkList2,400);
        printf("%d
    ",lpop(linkList2)->data);
        printf("%d
    ",lpop(linkList2)->data);
        printf("%d
    ",rpop(linkList2)->data);
        printf("%d
    ",rpop(linkList2)->data);
        return 0;
    }
    

    从同一端推入和弹出 如:lpush和lpop 能实现栈

    从相反方向推入和弹出 如:lpush和rpop能实现队列

  • 相关阅读:
    安卓开发知识点
    安卓开发第一天之环境搭建
    maven中的依赖的范围、传递、冲突,继承
    pom.xml文件
    Maven的目录结构
    tomcat的端口修改不成功
    maven的安装和配置,及在Eclipse里的使用
    servlet的路径跳转及路径问题
    servlet如何获取jsp表单里的数据
    关于“servelt始终驻留在服务器内存”的理解
  • 原文地址:https://www.cnblogs.com/yangyuanhu/p/12390199.html
Copyright © 2020-2023  润新知