myList.h

#ifndef MYLIST_H_INCLUDED
#define MYLIST_H_INCLUDED/*
仿照linux的链表操作的实现
*/#undef NULL
#ifdef __cplusplus#define NULL 0
#else#define NULL ((void *)0)
#endifstruct list_head
{struct list_head *next;struct list_head *prev;
};#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \struct list_head name = LIST_HEAD_INIT(name)//在(TYPE*)结构体中找到(MEMBER)成员的位置
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
//找到type的开始位置
#define list_entry(ptr, type, member) \(type *)((char *)ptr - offsetof(type,member))//向后遍历链表。pos为当前位置,head为开始位置
#define list_for_each(pos, head) \for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next)//向前遍历链表。pos为当前位置,head为开始位置
#define list_for_each_prev(pos, head) \for (pos = (head)->prev; pos != (head); pos = pos->prev)
#define list_for_each_prev_safe(pos, n, head) \for (pos = (head)->prev, n = pos->prev; pos != (head); pos = n, n = pos->prev)//???
#define list_first_entry(ptr, type, member) \list_entry((ptr)->next, type, member)//初始化链表(链表头)
static inline void INIT_LIST_HEAD(struct list_head *list)
{list->next = list;list->prev = list;
}//添加一个节点到链表中的基本操作
static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next)
{next->prev = new;new->next = next;new->prev = prev;prev->next = new;
}//在链表头之后增加一个新节点。如1->2->3,增加4之后为1->4->2->3
static inline void list_add(struct list_head *new, struct list_head *head)
{__list_add(new, head, head->next);
}//在链表的尾部增加一个新节点,如1->2->3,增加4之后为1->2->3->4
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{__list_add(new, head->prev, head);
}//删除一个链表中的节点,基本操作
static inline void __list_del(struct list_head * prev, struct list_head * next)
{next->prev = prev;prev->next = next;
}//删除一个链表中的节点,*entry为从链表找中摘除的节点,如果有内存申请则需要手动释放
static inline void list_del(struct list_head *entry)
{__list_del(entry->prev, entry->next);entry->next = NULL;entry->prev = NULL;
}//删除一个链表中的节点并把删除的节点初始化,*entry为从链表找中摘除的节点,如果有内存申请则需要手动释放
static inline void list_del_init(struct list_head *entry)
{__list_del(entry->prev, entry->next);INIT_LIST_HEAD(entry);
}//使用new替换链表中的old
static inline void list_replace(struct list_head *old, struct list_head *new)
{new->next = old->next;new->next->prev = new;new->prev = old->prev;new->prev->next = new;
}//使用new替换链表中的old并且把old初始化,如果old是链表头则相当于清空链表
static inline void list_replace_init(struct list_head *old, struct list_head *new)
{list_replace(old, new);INIT_LIST_HEAD(old);
}//将list从链表中取出,然后移动到head的之后的位置。如果head是链表头则是移动到链表的第一个位置
static inline void list_move(struct list_head *list, struct list_head *head)
{__list_del(list->prev, list->next);list_add(list, head);
}//将list从链表中取出,然后移动到head的最后一个位置。如果head是链表头则是移动到链表的尾部
static inline void list_move_tail(struct list_head *list, struct list_head *head)
{__list_del(list->prev, list->next);list_add_tail(list, head);
}//判断链表是否为空
static inline int list_empty(const struct list_head *head)
{return head->next == head;
}//判断链表是否为空。条件更加充足
static inline int list_empty_careful(const struct list_head *head)
{struct list_head *next = head->next;return (next == head) && (next == head->prev);
}/*******************************不常用的操作*********************************///判断list是否为链表最后一个节点
static inline int list_is_last(const struct list_head *list, const struct list_head *head)
{return list->next == head;
}//判断链表中是否只有一个节点
static inline int list_is_singular(const struct list_head *head)
{return !list_empty(head) && (head->next == head->prev);
}//将一个链表拆分为两条链表的基本操作
static inline void __list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry)
{struct list_head *new_first = entry->next;list->next = head->next;list->next->prev = list;list->prev = entry;entry->next = list;head->next = new_first;new_first->prev = head;
}/*
将一个链表拆分成两条
*list为拆分后的新链表的头,*head为被拆分链表的头,*entry为拆分位置
拆分后list->next = entry, head->next = entry->next
既是entry后面的节点被加到list的后面,原链表保留entry之前的节点
head->1->2->3->10->20->30,entry->10.拆分后:head->10->20->30, list->1->2->3
*/
static inline void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry)
{if (list_empty(head))return;if (list_is_singular(head) &&(head->next != entry && head != entry))return;if (entry == head)INIT_LIST_HEAD(list);else__list_cut_position(list, head, entry);
}//合并两条聊表的基本操作
static inline void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next)
{struct list_head *first = list->next;struct list_head *last = list->prev;first->prev = prev;prev->next = first;last->next = next;next->prev = last;
}/*
合并两条链表
将list链表加入到head的后面
list->1->2->3,head->10->20->30。合并后:head->1->2->3->10->20->30
*/
static inline void list_splice(const struct list_head *list, struct list_head *head)
{if (!list_empty(list))__list_splice(list, head, head->next);
}/*
合并两条链表
将list链表加入到head的后面,list为必须为链表头,合并后将其初始化
list->1->2->3,head->10->20->30。合并后:head->1->2->3->10->20->30
*/
static inline void list_splice_init(struct list_head *list, struct list_head *head)
{if (!list_empty(list)){__list_splice(list, head, head->next);INIT_LIST_HEAD(list);}
}/*
合并两条链表
将list链表加入到head的链表尾部
list->1->2->3,head->10->20->30。合并后:head->10->20->30->1->2->3
*/
static inline void list_splice_tail(struct list_head *list, struct list_head *head)
{if (!list_empty(list))__list_splice(list, head->prev, head);
}/*
合并两条链表
将list链表加入到head的链表尾部。list必须是头节点,合并后初始化list
list->1->2->3,head->10->20->30。合并后:head->10->20->30->1->2->3
*/
static inline void list_splice_tail_init(struct list_head *list, struct list_head *head)
{if (!list_empty(list)){__list_splice(list, head->prev, head);INIT_LIST_HEAD(list);}
}
#endif // MYLIST_H_INCLUDED

main.c

#include <stdio.h>
#include <stdlib.h>
#include "myList.h"
#include "memory.h"#define RETURN_OK 0
#define RETURN_ERROR -1//结构体的定义需要放在头文件中,此处做了简便处理
typedef struct tag_myList
{int data;struct list_head stListNode;  //该指针一般放在结构体定义的开头
}myList;struct list_head g_stListHead;    //全局变量,作为链表的头//申请一个节点
myList* newNode()
{myList *pstTemp = NULL;//为节点申请内存pstTemp = (myList*)malloc(sizeof(myList));if (NULL == pstTemp){return NULL;}INIT_LIST_HEAD(&(pstTemp->stListNode));pstTemp->data = 0;return pstTemp;
}int main()
{int i;struct list_head stTempHead;    //作为拆分或者合并的链表的头节点struct list_head *pstEntry = NULL;myList* pstTemp = NULL;struct list_head *pos = NULL;struct list_head *n = NULL;//初始化INIT_LIST_HEAD(&g_stListHead);INIT_LIST_HEAD(&stTempHead);for (i = 0; i < 5; i++){pstTemp = newNode();if (NULL == pstTemp){exit(0);    //内存申请失败则退出,简单的处理}pstTemp->data = i;//将节点加入链表头部list_add(&pstTemp->stListNode, &g_stListHead);}for (i = 5; i < 10; i++){pstTemp = newNode();if (NULL == pstTemp){exit(0);    //内存申请失败则退出,简单的处理}pstTemp->data = i;//将节点加入链表尾部list_add_tail(&pstTemp->stListNode, &g_stListHead);}//遍历链表list_for_each(pos, &g_stListHead){//通过偏移找到结构体开始的位置,list_entry已经将偏移后的指针强制转换为该结构体pstTemp = list_entry(pos, myList, stListNode);printf("%d\t", pstTemp->data);if (0 == pstTemp->data){pstEntry = &pstTemp->stListNode;     //将0所在的位置作为拆分或者合并的节点位置}}printf("\n");list_cut_position(&stTempHead, &g_stListHead, pstEntry);printf("cut node after g_stListHead:");list_for_each(pos, &g_stListHead){//通过偏移找到结构体开始的位置,list_entry已经将偏移后的指针强制转换为该结构体pstTemp = list_entry(pos, myList, stListNode);printf("%d\t", pstTemp->data);}printf("\n");printf("cut node after stTempHead:");list_for_each(pos, &stTempHead){//通过偏移找到结构体开始的位置,list_entry已经将偏移后的指针强制转换为该结构体pstTemp = list_entry(pos, myList, stListNode);printf("%d\t", pstTemp->data);}printf("\n");list_splice_init(&g_stListHead, &stTempHead);   //list_splice在遍历的时候就会有问题printf("splice node after stTempHead:\t");list_for_each(pos, &stTempHead){//通过偏移找到结构体开始的位置,list_entry已经将偏移后的指针强制转换为该结构体pstTemp = list_entry(pos, myList, stListNode);printf("%d\t", pstTemp->data);}printf("\n");printf("splice node after g_stListHead:\t");list_for_each(pos, &g_stListHead){//通过偏移找到结构体开始的位置,list_entry已经将偏移后的指针强制转换为该结构体pstTemp = list_entry(pos, myList, stListNode);printf("%d\t", pstTemp->data);}return 0;
}

转载于:https://blog.51cto.com/5556140/1945609

双向循环链表---仿照linux内核实现相关推荐

  1. Linux 内核调试器 调试指南

    Linux 内核调试器内幕 KDB 入门指南 Hariprasad Nellitheertha (nharipra@in.ibm.com), 软件工程师, IBM 简介: 调试内核问题时,能够跟踪内核 ...

  2. [网易云课堂]Linux内核分析(九)—— 课程总结

    付何山+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000; 导读:本文分为两个部分 ...

  3. 详解Linux内核之双向循环链表 By邪恶八进制

    [转载]详解Linux内核之双向循环链表 详解Linux内核之双向循环链表 信息来源:邪恶八进制信息安全团队(www.eviloctal.com) 摘要:      本文详解了内核中面向对象的list ...

  4. linux内核双向循环队列,读书笔记之linux内核设计与实现(2)进程调度

    调度程序是内核的组成部分,它负责选择下一个要运行的进程.进程调度程序可看作在可运行态进程之间分配有限的处理器时间资源的内核子系统. 多任务操作系统就是能够同时并发的交互执行多个进程的操作系统.多任务系 ...

  5. linux内核开源不能仿照_Linux内核开发,开源生产力工具,使用Google应用程序创建自动日历等

    linux内核开源不能仿照 上周,来自linux.conf.au演讲者系列和Kevin Sonney的开源工具系列的文章在读者中大受欢迎. 您想开始为Opensource.com写作吗? 这很容易. ...

  6. 双向循环链表:鸿蒙轻内核中数据的“驿站”

    本文分享自华为云社区<鸿蒙轻内核M核源码分析系列二 数据结构-双向循环链表>,原文作者:zhushy . 在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用. ...

  7. 《Linux内核设计与实现》读书笔记 第三章 进程管理

    第三章进程管理 进程是Unix操作系统抽象概念中最基本的一种.我们拥有操作系统就是为了运行用户程序,因此,进程管理就是所有操作系统的心脏所在. 3.1进程 概念: 进程:处于执行期的程序.但不仅局限于 ...

  8. linux 内核 fork,《Linux内核分析》之分析fork函数对应的系统调用处理过程

    实验过程 [toggle hide="yes" title="实验过程" color="#f50000"] 1.在实验楼中shell终端依次 ...

  9. linux内核数据结构之链表

    1.前言 最近写代码需用到链表结构,正好公共库有关于链表的.第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域.后来看代码注释发现该代码来自linux内核,在li ...

最新文章

  1. HDU-2089-不要62
  2. 如何在Go中编写防弹代码:不会失败的服务器工作流程
  3. android gridlayout动态添加_Android-TabLayout-动态设置TabItem的背景Shape.有坑.......
  4. 内卷加速 | 本科毕业出国率下降,考研or保研?
  5. LAMP源码安装原理
  6. 11个审查Linux是否被入侵的方法
  7. 河北省对口计算机打字试题,河北省对口升学计算机基础.ppt
  8. 操作抖音取名项目日赚 500 实战案例分析
  9. 微软“玻璃硬盘”问世:2毫米杯垫大小可存储75.8G数据,1000年不坏!
  10. SLAM领域的优秀作者与实验室汇总
  11. 双向可控硅实现 插头防插拔火花
  12. excel双条件筛选
  13. 八数码 || 九宫重排(A*搜索代码)
  14. dpo指标详解买入绝技_DPO指标,DPO指标详解,DPO是什么意思? - 股票入门
  15. python websocket实时消息推送
  16. 无头浏览器和抓取-解决方案
  17. bravado哺乳内衣 这款哺乳胸罩,越早买越好,别等到下垂涨奶才知道后悔!
  18. 老男孩python博客汇总
  19. 首师大附中互测题:99999999海岛帝国后传:算法大会【D001】
  20. 2020年12月8日 阴

热门文章

  1. struts2登录注册示例_Struts2资源包和本地化示例
  2. Akka异步通讯《three》译
  3. 作为一个产品经理,产品文档该怎样写
  4. OA系统中公文流转简单思路
  5. 光纤非线性效应对光OFDM信号的影响研究
  6. MySql按字段分组取最大值记录 [此博文包含图片]
  7. 手把手教你如何把本地文件传到服务器,如何映射
  8. QTableView修改数据后弹出是否保存的提示框。
  9. 查询软件和硬件列表清单[将文章里代码另存为 list.vbs,双击运行就会出现一个html页面]...
  10. B树、B-树、B+树、B*树都是什么