面试题答案
一键面试Redis链表数据结构定义
在Redis源码中,链表相关数据结构定义在adlist.h
文件中。
- 链表节点:
typedef struct listNode {
struct listNode *prev;
struct listNode *next;
void *value;
} listNode;
prev
指针指向前一个节点,next
指针指向后一个节点,value
指针指向节点存储的值,可以是任意类型。
- 链表:
typedef struct list {
listNode *head;
listNode *tail;
unsigned long len;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
} list;
head
和tail
分别指向链表头和链表尾节点。len
记录链表节点数量。dup
、free
和match
是函数指针,用于复制值、释放值以及比较值。
插入节点操作大致实现思路
- 头插法:
- 创建新节点,并分配内存空间。
- 将新节点的
next
指针指向当前链表的head
节点。 - 如果链表不为空,将当前
head
节点的prev
指针指向新节点。 - 更新链表的
head
指针为新节点。 - 如果链表为空,同时更新
tail
指针为新节点。 - 更新链表长度
len
。
- 尾插法:
- 创建新节点,并分配内存空间。
- 将新节点的
prev
指针指向当前链表的tail
节点。 - 如果链表不为空,将当前
tail
节点的next
指针指向新节点。 - 更新链表的
tail
指针为新节点。 - 如果链表为空,同时更新
head
指针为新节点。 - 更新链表长度
len
。
删除节点操作大致实现思路
- 查找要删除的节点:通过遍历链表,根据
match
函数指针(如果设置了)找到要删除的节点。 - 调整指针:
- 如果要删除的节点是
head
节点,将head
指针指向当前节点的next
节点。如果next
节点存在,将其prev
指针设为NULL
。 - 如果要删除的节点是
tail
节点,将tail
指针指向当前节点的prev
节点。如果prev
节点存在,将其next
指针设为NULL
。 - 如果要删除的节点在链表中间,将当前节点的
prev
节点的next
指针指向当前节点的next
节点,当前节点的next
节点的prev
指针指向当前节点的prev
节点。
- 如果要删除的节点是
- 释放资源:
- 使用
free
函数指针(如果设置了)释放节点中value
指向的值的内存。 - 释放节点本身的内存。
- 使用
- 更新链表长度:链表长度
len
减1。