tiny-redis list实现

基于Redis 设计与实现实现的redis,根据书上的API描述,自己实现C++版本的redis。

list是常见的数据结构,但是redis有更加抽象的实现,就很,妙,但是也会有很多bug,他用了函数指针,指来指去的。

上代码

#pragma once
#include <memory>
#include <functional>

struct listNode
{
    // 前置节点
    std::shared_ptr<listNode> prev=nullptr;

    // 后置节点
    std::shared_ptr<listNode> next=nullptr;

    // 节点的值
    void* value=nullptr;

    listNode(void *value):value(value){};


    // 返回给定节点的前置节点
    std::shared_ptr<listNode> listPrevNode(){
        return this->prev;
    };

    // 返回给定节点的后置节点
    std::shared_ptr<listNode> listNextNode(){
        return this->next;
    };

    // 返回给定节点当前保存的值
    void* listNodeValue(){
        return this->value;
    };
};

class list {
private:
    // 表头节点
    std::shared_ptr<listNode> head=nullptr;

    // 表尾节点
    std::shared_ptr<listNode> tail=nullptr;

    // 链表所包含的节点数量
    unsigned long len=0;
    // 节点值复制函数
    std::function<void *(void *)> dup=nullptr;

    // 节点值释放函数
    std::function<void(void *)> free=nullptr;

    // 节点值对比函数
    std::function<int(void *, void *)> match=nullptr;
public:


    // 设置链表的节点值复制函数
    void listSetDupMethod(std::function<void *(const void *)> dup){
        this->dup=dup;
    };

    // 返回当前链表正在使用的节点值复制函数
    std::function<void *(void *)> listGetDupMethod(){
        return this->dup;
    };

    // 设置链表的节点值释放函数
    void listSetFreeMethod(std::function<void(void *)> free){
        this->free=free;
    };

    // 返回当前链表正在使用的节点值释放函数
    std::function<void(void *)> listGetFree(){
        return this->free;
    };

    // 设置链表的节点值对比函数
    void listSetMatchMethod(std::function<int(const void *, const void *)> match){
        this->match=match;
    };

    // 返回当前链表正在使用的节点值对比函数
    std::function<int(void *, void *)> listGetMatchMethod(){
        return this->match;
    };

    // 返回链表的长度
    unsigned long listLength() const{
        return this->len;
    };

    // 返回链表的表头节点
    std::shared_ptr<listNode> listFirst(){
        return this->head;
    };

    // 返回链表的表尾节点
    std::shared_ptr<listNode> listLast(){
        return this->tail;
    };

    // 创建一个新的空链表
    list(){

    }
    list(void *value){
        listAddNodeHead(value);
    }
    ~list(){
        listRelease();
    }


    // 添加一个新节点到链表的表头
    std::shared_ptr<listNode> listAddNodeHead(void *value){
        std::shared_ptr<listNode> node=std::make_shared<listNode>(this->dup(value));
        node->next=this->head;
        if(this->head){
            this->head->prev=node;
        }
        this->head=node;
        if(!this->tail){
            this->tail=node;
        }
        this->len++;
        return node;
    };

    // 添加一个新节点到链表的表尾
    std::shared_ptr<listNode> listAddNodeTail(void *value){
        std::shared_ptr<listNode> node=std::make_shared<listNode>(this->dup(value));
        node->prev=this->tail;
        if(this->tail){
            this->tail->next=node;
        }
        this->tail=node;
        if(!this->head){
            this->head=node;
        }
        this->len++;
        return node;
    };

    // 将一个新节点插入到指定节点的前面或后面
    std::shared_ptr<listNode> listInsertNode(std::shared_ptr<listNode> old_node, void *value, int after){
        //after:插入位置,如果设为 1,则在旧节点之后插入,如果设为 0,则在旧节点之前插入
        if(this->len == 0){
            return listAddNodeHead(value);
        }
        std::shared_ptr<listNode> node=std::make_shared<listNode>(this->dup(value));
        if(after){
            node->prev=old_node;
            node->next=old_node->next;
            if(old_node->next){
                old_node->next->prev=node;
            }
            old_node->next=node;
            if(old_node == this->tail){
                this->tail=node;
            }
        }else{
            node->next=old_node;
            node->prev=old_node->prev;
            if(old_node->prev){
                old_node->prev->next=node;
            }
            old_node->prev=node;
            if(old_node == this->head){
                this->head=node;
            }
        }


        this->len++;
        return node;
    };

    // 查找并返回链表中包含指定值的节点
    std::shared_ptr<listNode> listSearchKey(void *key){
        std::shared_ptr<listNode> node=this->head;
        while(node){
            if(this->match(node->value, key) == true){
                return node;
            }
            node=node->next;
        }
        return nullptr;
    };

    // 返回链表指定索引上的节点
    std::shared_ptr<listNode> listIndex(long index){
        if(index < 0 || (unsigned long)index >= this->len){
            return nullptr;
        }
        std::shared_ptr<listNode> node=this->head;
        while(index--){
            node=node->next;
        }
        return node;
    };

    // 从链表中删除指定的节点
    void listDelNode(std::shared_ptr<listNode> node){
        std::shared_ptr<listNode> curr=this->head;
        while(curr){
            if(curr==node){
                if(node->prev){
                    node->prev->next=node->next;
                }
                if(node->next){
                    node->next->prev=node->prev;
                }
                this->len--;
                break;
            }
            curr=curr->next;
        }
        //更新head和tail
        if(node == this->head){
            this->head=node->next;
        }
        if(node == this->tail){
            this->tail=node->prev;
        }
        //释放节点
        if(this->free){
            this->free(node->value);
        }
    };

    // 将链表的表尾节点移动到表头
    void listRotate(){
        if(this->len == 0 || this->len == 1){
            return;
        }
        if(head->next){
            head->next->prev=this->tail;
            tail->next=head->next;
        }
        if(tail->prev){
            tail->prev->next=this->head;
            head->prev=tail->prev;
        }
        head->next=nullptr;
        tail->prev=nullptr;
        std::swap(head, tail);
        
    };

    // 复制一个给定链表的副本
    std::shared_ptr<list> listDup(){
        std::shared_ptr<list> newlist=std::make_shared<list>();
        newlist->dup=this->dup;
        newlist->free=this->free;
        newlist->match=this->match;
        newlist->len=this->len;
        std::shared_ptr<listNode> node=std::make_shared<listNode>(this->dup(this->head->value));
        std::shared_ptr<listNode> curr=this->head;
        newlist->head=node;
        while(curr->next){
            node->next=std::make_shared<listNode>(this->dup(curr->next->value));
            node->next->prev=node;
            node=node->next;
            curr=curr->next;
        }
        newlist->tail=node;
        return newlist;
    
    };
    //释放给定链表,以及链表中的所有节点。
    void listRelease(){
        std::shared_ptr<listNode> curr=this->head;
        while(curr){
            std::shared_ptr<listNode> next=curr->next;
            if(this->free){
                this->free(curr->value);
            }
            curr=next;
        }
        this->head=nullptr;
        this->tail=nullptr;
        this->len=0;
    }

};

数据结构

listnode没啥好说的,看list

head , tail 分别存储了头指针和尾指针

len 是链表的长度

dup 函数指针,用于指向节点的复制函数。这里需要提一下,为啥要用这个函数指针?想到函数的浅拷贝,当传入的一个值是指针的时候,浅拷贝只会复制指针,不会新new一个数据,这里也是一样的,当链表的数据是指针的时候,需要自己new一个新地址。

free 函数指针,用于指向节点的释放函数。和dup相对应,有构造,就有释放

match 函数指针,比较两个节点是否相等。

测试代码

不想说啥了,gpt写的,难受

#include <gtest/gtest.h>
#include "list.h"
#include <iostream>

using namespace std;

class ListTest : public ::testing::Test {
protected:
    void SetUp() override {
        // Set up code
        myList.listSetDupMethod([](const void *value) {
            int myvalue=*(int *)value;
            int *newValue = new int;
            *newValue = myvalue;
            cout<<std::hex<<newValue<<" is created \n";
            return newValue;
        });

        myList.listSetFreeMethod([](void *value) {
            if(value!= nullptr){
                cout<<std::hex<<value<<" is delete \n";
                delete static_cast<int *>(value);
                
            }
        });

        myList.listSetMatchMethod([](const void *a, const void *b) {
            return (*(static_cast<const int *>(a)) == *(static_cast<const int *>(b))) ? 1 : 0;
        });
    }

    // Declare the list instance
    list myList;
};

// Test adding nodes to the head of the list
TEST_F(ListTest, AddNodeHead) {
    int value1 = 10;
    std::shared_ptr<listNode> node1 = myList.listAddNodeHead(&value1);

    ASSERT_EQ(myList.listLength(), 1);

    int *headValue = static_cast<int *>(myList.listFirst()->listNodeValue());
    ASSERT_EQ(*headValue, value1);
    //myList.listGetFree()(headValue); 不要调用free,否则会导致内存泄漏,会有析沟函数自动释放
}

// Test adding nodes to the tail of the list
TEST_F(ListTest, AddNodeTail) {
    int value1 = 10;
    int value2 = 20;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);

    ASSERT_EQ(myList.listLength(), 2);

    int *tailValue = static_cast<int *>(myList.listLast()->listNodeValue());
    ASSERT_EQ(*tailValue, value2);
    //myList.listGetFree()(tailValue);
}

// Test inserting nodes into the list
TEST_F(ListTest, InsertNode) {
    int value1 = 10;
    int value2 = 20;
    int value3 = 30;
    std::shared_ptr<listNode> node1 = myList.listAddNodeHead(&value1);
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);
    std::shared_ptr<listNode> node3 = myList.listInsertNode(node2, &value3, 1);

    ASSERT_EQ(myList.listLength(), 3);

    std::shared_ptr<listNode> nextNode = node1->listNextNode();
    ASSERT_EQ(nextNode, node2);
}

// Test node value comparison
TEST_F(ListTest, NodeValueComparison) {
    int value1 = 10;
    std::shared_ptr<listNode> node1 = myList.listAddNodeHead(&value1);

    int value2 = 20;
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);

    ASSERT_EQ(myList.listGetMatchMethod()(node1->value, &value1), 1);
    ASSERT_EQ(myList.listGetMatchMethod()(node2->value, &value2), 1);
}


// Test list search key
TEST_F(ListTest, ListSearchKey) {
    int value1 = 10;
    int value2 = 20;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);

    std::shared_ptr<listNode> result = myList.listSearchKey(&value1);
    ASSERT_EQ(result, node1);

    result = myList.listSearchKey(&value2);
    ASSERT_EQ(result, node2);

    int value3 = 30;
    result = myList.listSearchKey(&value3);
    ASSERT_EQ(result, nullptr);
}

TEST_F(ListTest, ListSearchKeyEmptyList) {
    int value = 10;
    std::shared_ptr<listNode> result = myList.listSearchKey(&value);
    ASSERT_EQ(result, nullptr);
}

// Test list index
TEST_F(ListTest, ListIndex) {
    int value1 = 10;
    int value2 = 20;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);

    std::shared_ptr<listNode> result = myList.listIndex(0);
    ASSERT_EQ(result, node1);

    result = myList.listIndex(1);
    ASSERT_EQ(result, node2);

    result = myList.listIndex(2);
    ASSERT_EQ(result, nullptr);
}

TEST_F(ListTest, ListIndexOutOfRange) {
    int value = 10;
    std::shared_ptr<listNode> result = myList.listIndex(-1);
    ASSERT_EQ(result, nullptr);

    result = myList.listIndex(0);
    ASSERT_EQ(result, nullptr);
}

// Test list delete node
TEST_F(ListTest, ListDelNode) {
    int value1 = 10;
    int value2 = 20;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);

    myList.listDelNode(node1);
    ASSERT_EQ(myList.listFirst(), node2);
    ASSERT_EQ(myList.listLength(), 1);
}

TEST_F(ListTest, ListDelNodeTail) {
    int value1 = 10;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);

    myList.listDelNode(node1);
    ASSERT_EQ(myList.listFirst(), nullptr);
    ASSERT_EQ(myList.listLast(), nullptr);
    ASSERT_EQ(myList.listLength(), 0);
}

// Test list rotate
TEST_F(ListTest, ListRotate) {
    int value1 = 10;
    int value2 = 20;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);

    myList.listRotate();
    ASSERT_EQ(myList.listFirst(), node2);
    ASSERT_EQ(myList.listLast(), node1);
}

TEST_F(ListTest, ListRotateSingleElement) {
    int value1 = 10;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);

    myList.listRotate();
    ASSERT_EQ(myList.listFirst(), node1);
    ASSERT_EQ(myList.listLast(), node1);
}

// Test list duplicate
TEST_F(ListTest, ListDup) {
    int value1 = 10;
    int value2 = 20;
    std::shared_ptr<listNode> node1 = myList.listAddNodeTail(&value1);
    std::shared_ptr<listNode> node2 = myList.listAddNodeTail(&value2);

    std::shared_ptr<list> newList = myList.listDup();
    ASSERT_EQ(newList->listLength(), myList.listLength());

    std::shared_ptr<listNode> newNode1 = newList->listFirst();
    ASSERT_EQ(*(static_cast<int *>(newNode1->value)), value1);
    std::shared_ptr<listNode> newNode2 = newList->listLast();
    ASSERT_EQ(*(static_cast<int *>(newNode2->value)), value2);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值