参照了Redis里面的双链表结构,可以说是完全复制粘贴,redis的双链表还是写的很通俗易懂的,没有什么花里胡哨的东西,但是redis还有个iter迭代器的结构来遍历链表。我这里就没有实现了,只是实现了双链表的基本操作

redis双链表结构有如下特点

  1. 多态:可以储存多种数据类型
  2. 双端
  3. 无环:也就是说head->pre==NULL tail->next=NULL
  4. 带有长度计数器
  5. 有头指针和尾指针

实现

注意,这里的链表有一个迭代器结构,方便遍历链表

#include<iostream>
#include<stdlib.h>
using namespace std; #define START_HEAD 0
#define START_TAIL 1 struct listNode{
listNode* prev;
listNode* next;
int value; //可以是void void*类型 实现多态链表
}; struct list{
listNode* head;
listNode* tail;
int len;
}; //迭代器模式
typedef struct listIter {
listNode *next;
int direction; //遍历方向
}; //创建迭代器
listIter *listGetIterator(list *myList, int direction)
{
listIter *iter = (listIter*)malloc(sizeof(listIter)); if (direction == START_HEAD)
iter->next = myList->head;
else
iter->next = myList->tail;
iter->direction = direction;
return iter;
}
/* Release the iterator memory */
void listReleaseIterator(listIter *iter) {
free(iter);
} //将迭代器指向开头节点
void listRewind(list *myList, listIter *li) {
li->next = myList->head;
li->direction = START_HEAD;
}
//迭代器指向尾部节点
void listRewindTail(list *myList, listIter *li) {
li->next = myList->tail;
li->direction = START_TAIL;
} //用迭代器遍历下一个节点
listNode *listNext(listIter *iter)
{
listNode *current = iter->next; if (current != NULL) {
if (iter->direction == START_HEAD)
iter->next = current->next;
else
iter->next = current->prev;
}
return current;
} //初始化链表
list* listCreate(){
list* myList;
myList = (list*)malloc(sizeof(list));
myList->head = myList->tail=NULL;
myList->len=0;
return myList;
} //移除链表元素
void listEmpty(list* list){
int len = 0;
listNode* current,*next;
current = list->head;
while(len--){
next = current->next;
free(current);
current = next;
}
list->head=list->tail=NULL;
list->len=0;
} void listRelease(list* list){
listEmpty(list);
free(list);
list = NULL;
} //头插
list* listAddNodeHead(list* list,int val){
listNode* node = (listNode*)malloc(sizeof(listNode));
node->value = val;
if(list->len==0){
list->head = list->tail=node;
node->prev=node->next=NULL;
}else{
node->prev = NULL; node->next = list->head;
list->head->prev = node; list->head = node;
}
list->len++;
return list;
}
//尾插
list* listAddNodeTail(list* myList,int val){
listNode* node = (listNode*)malloc(sizeof(listNode));
node->value = val;
if(myList->len==0){
myList->head = myList->tail = node;
node->prev=node->next=NULL;
}else{
node->prev = myList->tail;
myList->tail->next = node; node->next=NULL; myList->tail = node;
}
myList->len++;
return myList;
} //插入到指定节点前面或后面
list* listInsertNode(list* list,listNode* old_node,int val,bool after){
listNode* node = (listNode*)malloc(sizeof(listNode));
node->value = val;
if(after){ node->prev = old_node;
node->next = old_node->next;
if(list->tail==old_node){
list->tail = node;
}
}else{ node->next = old_node;
node->prev = old_node->prev;
if(list->head==old_node){
list->head = node;
}
} if(node->prev!=NULL){
node->prev->next = node;
}
if(node->next!=NULL){
node->next->prev = node;
}
list->len++;
return list;
} //删除指定节点
void listDelNode(list* list,listNode* node){
if(node->prev)
node->prev->next = node->next;
else //是头节点
list->head = node->next; if(node->next) //如果不是尾节点
node->next->prev = node->prev;
else
list->tail = node->prev;
free(node);
node = NULL;
list->len--;
} //链表的复制
list* listCopy(list* old_list){ list* new_list = listCreate(); listNode* node;
listIter iter;
listRewind(old_list,&iter); //指向开头节点
while((node=listNext(&iter))!=NULL){
listAddNodeTail(new_list,node->value);
}
//listRelease(old_list);
return new_list;
} //根据值查找节点
listNode* listSearchKey(list* myList,int val){
listNode* node;
listIter iter;
listRewind(myList,&iter); while((node=listNext(&iter))!=NULL && node->value!=val)
; if(node)
return node;
else
return NULL;
} //根据索引查找节点 支持倒排序索引
listNode* listIndex(list* list,int index){
listNode* node; if(index<0){
index = (-index)-1;
node = list->tail;
while(index-- && node) node =node->prev;
}
else{
node = list->head;
while(index-- && node) node = node->next;
}
return node;
} //second连接到first
list* listJoin(list* first,list* second){
if(second->head)
second->head->prev = first->tail; if(first->tail)
first->tail->next = second->head;
else //first链表是空的
first->head = second->head; if(second->tail)
first->tail = second->tail; first->len +=second->len; second->head = second->tail = NULL;
second->len = 0; return first;
} #define dlist_for_each(pos, head) \
for (pos = (head)->next; pos != NULL; pos = pos->next) #define dlist_reverse_for_each(pos, head) \
for (pos = (head)->next; pos!=NULL; pos = pos->next) void Show_Int_List(list* myList){
listNode* node;
dlist_for_each(node,myList->head){
cout<<node->value<<endl;
} } int main(){ list* myList1 = listCreate();
for(int i=1;i<=5;i++)
listAddNodeTail(myList1,i);
Show_Int_List(myList1);
cout<<endl; list* myList2 = listCreate();
for(int i=6;i<=10;i++)
listAddNodeTail(myList2,i);
Show_Int_List(myList2);
cout<<endl; listJoin(myList1,myList2);
Show_Int_List(myList1);
cout<<endl; cout<<listIndex(myList1,-2)->value<<endl;
cout<<endl; list* myList3=NULL;
myList3 = listCopy(myList1);
listAddNodeHead(myList3,99);
listDelNode(myList3,listSearchKey(myList3,10));
Show_Int_List(myList3);
cout<<endl;
cout<<"len:"<<myList3->len<<endl; return 0;
}

双链表【参照redis链表结构】的更多相关文章

  1. Redis数据结构—链表与字典的结构

    目录 Redis数据结构-链表与字典的结构 链表 Redis链表节点的结构 Redis链表的表示 Redis链表用在哪 字典 Redis字典结构总览 Redis字典结构分解 Redis字典的使用 Re ...

  2. redis 链表

    redis 链表 前言 借鉴了 黄健宏 的 <<Redis 设计与实现>> 一书, 对 redis 源码进行学习 欢迎大家给予意见, 互相沟通学习 概述 redis 的链表结构 ...

  3. Redis链表实现

    链表在 Redis 中的应用非常广泛, 比如列表键的底层实现之一就是链表: 当一个列表键包含了数量比较多的元素, 又或者列表中包含的元素都是比较长的字符串时, Redis 就会使用链表作为列表键的底层 ...

  4. PHP+Redis链表解决高并发下商品超卖问题

    目录 实现原理 实现步骤 上一篇文章聊了一下使用Redis事务来解决高并发商品超卖问题,今天我们来聊一下使用Redis链表来解决高并发商品超卖问题. 实现原理 使用redis链表来做,因为pop操作是 ...

  5. Redis底层结构全了解

    第一篇文章,思来想去,写一写Redis吧,最近在深入研究它. 一丶Redis底层结构 1. redis 存储结构 redis的存储结构从外层往内层依次是redisDb.dict.dictht.dict ...

  6. 《闲扯Redis七》Redis字典结构的底层实现

    一.前言 上节<闲扯Redis六>Redis五种数据类型之Hash型 中说到 Hash(哈希对象)的底层实现有: 1.ziplist 编码的哈希对象使用压缩列表作为底层实现 2.hasht ...

  7. Redis的结构和运作机制

    目录 1.数据库的结构 1.1 字典的底层实现 2.过期键的检查和清除 2.1 定时删除 2.2 惰性删除 2.3 定期删除 2.4 对RDB.AOF和复制的影响 3.持久化机制 3.1 RDB方式 ...

  8. 使用C语言描述静态链表和动态链表

    静态链表和动态链表是线性表链式存储结构的两种不同的表示方式. 静态链表的初始长度一般是固定的,在做插入和删除操作时不需要移动元素,仅需修改指针,故仍具有链式存储结构的主要优点. 动态链表是相对于静态链 ...

  9. C语言 Linux内核链表(企业级链表)

    //Linux内核链表(企业级链表) #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> ...

随机推荐

  1. python学习之由

    2019python之年: 2019是个挫折之年,但又是幸运之年,这一年创业遭遇滑铁卢,几与破产,充满着迷茫,路在何方?? 开始接触python是在微信朋友圈,结缘于广告,觉得很有意思,但一直没有深入 ...

  2. 细数Java项目中用过的配置文件(ini 篇)

    Java 菜鸟,会把可变的配置信息写死在代码里:Java 老鸟,会把可变的配置信息提取到配置文件中.坊间流传这么一句非科学的衡量标准,来评判程序员的级别. 那么,项目中的配置信息,你平时都是怎样来实现 ...

  3. Coding 是门技术

    今天的分享来源于工作中的点点滴滴…… 01. 习惯性自嘲 代码写久了,伴随肩疼头痛眼近视,于是乎也就成了名副其实的 code farmer(码农),作为如牛吃草挤奶般的码农,吃草(撸)挤奶(码)便是日 ...

  4. Python中判断输入字符串是否为数字的方法

    在写物理实验图像处理的脚本时,遇到了一个判断输入的字符串是否为数字的方法 最开始我的思路是这个 test = input() while test.isdigit(): # do something ...

  5. MTK Android 预置APK

    [FAQ03038] 如何预置APK [DESCRIPTION]1, 如何将带源码的 APK 预置进系统?2, 如何将无源码的APK预置进系统?3, 如何预制APK使得用户可以卸载?4, 如何使得用户 ...

  6. VSCode设置大小写转换的快捷键

    本文已同步到专业技术网站 www.sufaith.com, 该网站专注于前后端开发技术与经验分享, 包含Web开发.Nodejs.Python.Linux.IT资讯等板块. VSCode在默认情况下没 ...

  7. intelij idea 和 eclipse 使用上的区别

    一.项目创建区别 使用基于IntelliJ的IDE,都会对project和module的关系比较糊涂.用简单的一句话来概括是: IntelliJ系中的Project相当于Eclipse系中的works ...

  8. 最长回文子窜O(N)

    字符窜同构的性质:同构字符窜拥有最小和最大的表示方法: 最长回文子窜: 1.首先暴力法:(n三方) 枚举每个起点和终点,然后单向扫描判断是不是回文子窜: 2.中心扩散法,(N方) 枚举每个中点,向外扩 ...

  9. AJ学IOS 之二维码学习,快速打开相机读取二维码

    AJ分享,必须精品 上一篇文章写了怎么生成二维码,这儿就说说怎么读取吧,反正也很简单,iOS封装的太强大了 步骤呢就是这样: 读取二维码需要导入AVFoundation框架#import <AV ...

  10. 今日写一篇散文 Textview settext 方法不能放入 int 参数 不然报错!

    Textview settext 方法不能放入 int 参数 不然报错!