printf("num = %d, math = %d\n", temp->num, temp->math); } printf("\n"); return 0; } 运行效果: 内核双链表效果图...其实关于内核中链表的操作还有很多的函数,目前就分析这几个。其余留给自己尝试。
概要 本文对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法。其中,也会涉及到Linux内核中非常常用的两个经典宏定义offsetof和container_of。...内容包括: 1.Linux中的两个经典宏定义 2.Linux中双向链表的经典实现 Linux中的两个经典宏定义 倘若你查看过Linux Kernel的源码,那么你对 offsetof 和 container_of...这两个宏最初是极客写出的,后来在Linux内核中被推广使用。...Linux中双向链表的经典实现 1.Linux中双向链表介绍 Linux双向链表的定义主要涉及到两个文件: include/linux/types.h include/linux/list.h Linux...3.Linux中双向链表的使用示例 双向链表代码(list.h): 1 #ifndef _LIST_HEAD_H 2 #define _LIST_HEAD_H 3 // 双向链表节点 4 struct
一.双向循环链表 #include #include // 双向循环链表数据节点 typedef struct node { int data; // 数据域...failled\n"); return NULL; } p->data = 0; p->next = p; p->prev = p; // 2.返回 return p; } 二.内核链表...1.kernel_list.h #ifndef __DLIST_H #define __DLIST_H /* This file is from Linux Kernel (include/linux...head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif 2.内核链表...内核链表_奇升偶降重排 #include #include #include "kernel_list.h" // 内核链表节点结构体(大结构体) typedef
/******************** * 内核中链表的应用 ********************/ (1)介绍 在Linux内核中使用了大量的链表结构来组织数据,包括设备列表以及各种功能模块中的数据组织...这些链表大多采用在include/linux/list.h实现的一个相当精彩的链表数据结构。...和next,内核的数据结构通常组织成双循环链表。...和以前介绍的双链表结构模型不同,这里的list_head没有数据域。在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点。...内核提供了一组函数来操作链表。
linux kernel中的list估计已经被各位前辈们写烂了,但是我还是想在这里记录一下; linux kernel里的很多数据结构都很经典, list链表就是其中之一 本篇要介绍的内容: list...的定义 list提供的操作方法 注意事项 使用实例 ---- List 所在文件: List的所有操作可以在 include/linux/list.h找到; List head的定义可以在 include.../linux/types.h找到; 定义 实际上这就是一个双向循环链表, 且有一个头指针 list head的定义: struct list_head { struct list_head *next...new, struct list_head *head) { __list_add(new, head, head->next); } 在尾部插入,在最后一个元素间和头指针间插入, 因为是循环链表嘛...head); } list_entry宏 按之前说的, 这个list_head都有要嵌入到用户定义的struct中,这个宏就是由这个list_head ptr来获取当前所处的struct对象的指针, 用了linux
双向链表应用实例 2.1 双向链表的操作分析和实现 使用带 head 头的双向链表实现 –水浒英雄排行榜 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。...由于之前已经做过单链表的基础操作,理论上来上手双向链表的比较简单的,可以直接看代码就理解,这里不多废话。...双向链表无非多了一个pre(前一个数) 分析 (1) 遍历 和 单链表一样,只是可以向前,也可以向后查找。...(2) 添加 (默认添加到双向链表的最后) 先找到双向链表的最后这个节点 temp.next = newHeroNode newHeroNode.pre = temp (3) 修改 思路和 原来的单向链表一样...temp; //然后换掉temp.net temp.next = heroNode; } } // 修改一个节点的内容, 双向链表的节点内容修改和单向链表一样
双向链表 在线性链式存储结构的结点中只有一个指示直接后继的指针域,由此,从某个结点出发只能顺指针往后寻查其他结点。若要寻查结点的直接前趋,则需从表头指针出 发。...双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。...//线性表的双向链表存储结构 typedef struct DulNode { ElemType data; struct DulNode *prior; //直接前驱指针 struct...DulNode *next; //直接后继指针 }DulNode , *DuLinkList; 双向链表既然是比单链表多了如可以反向遍历查找等数据结构,那么也就需要付出一些小的代价:在插入和删除时...数据结构声明 19 /******************************************************************************/ 20 /* 线性表的双向链表存储结构
双向链表除头节点外,每个节点除data都有next和pre,next指向下一个节点的内存地址,pre指向上一个节点都内存地址,头节点,没有data,pre指向null,尾节点next记录的是null;...new HeroNode2(0,"",""); public HeroNode2 getHead(){ return head; } /** * 遍历双向链表...*/ public void list(){ if(head.next == null){ System.out.println("链表为空"...void update(HeroNode2 newHeroNode){ if(head.next == null){ System.out.println("链表空...} public void del(int no){ if(head.next == null){ System.out.println("链表空
分析 双向链表的遍历,添加、修改、删除的操作思路 遍历方合单链表一样,只是可以向前、向后查找 添加(默认添加到双向链表的最后) (1)先找到双向链表的最后这个节点 (2)temp.next = new...DataNode(); (3)newDataNode.Pre = temp; 修改思路和原理跟单向链表一样 删除 (1)因为是双向链表,因此,我们可以实现自我删除某个节点 (2)直接找到要删除的这个节点...string ToString() { return $"DataNode[no={Id}],name={Name}"; } } /// /// 双向链表...returns> public DataNode GetHead() { return head; } /// /// 遍历双向链表...//形成一个双向链表 temp.NextNode = node; node.PreNode = temp; } /// <summary
(6); Print(); Insertattail(9); Insertattail(25); Print(); ReversePrintf(); } 和单向链表差不多
双向链表 概念 双向链表是普通链表的扩展,它的特点是具有两个节点。...如果pos <= 0,相当于是pos=0,看做是在头部插入add方法 if pos <= 0: self.add(item) # 如果pos比链表最后一个元素的位置还大...__head = cur.next if cur.next: # 判断链表是否只有一个节点
接着我们的第一篇文章,继续实现双向链表的方法。...这是我们定义好的双向链表的数据结构不要忘了: function TwoWayLinkList() { // 属性 this.head = null...this.prev = null this.next = null } } append() 思路 双向链表与单向链表的区别是在头部和尾部都能找到我们的元素
输入共有三行,第一行为该单向循环链表的长度 n(1≤n≤60);第二行为该单向循环链表的各个元素 ,它们各不相同且都为数字;第三行为一个数字 m,表示链表中的一个元素值,要求输出时以该元素为起点反向输出整个双向链表...输出格式 输出为一行,即完成双向链表后以反向顺序输出该链表,每两个整数之间一个空格,最后一个整数后面没有空格 #include #include typedef
TwoWayLinkList.prototype.isEmpty = function () { return this.length === 0; }; size 返回的是链表的长度...TwoWayLinkList.prototype.getTail = function () { return this.tail.data; }; 完整实现 // 封装双向链表...this.tail = newNode; } this.length += 1; }; /** * 2.链表转换为字符串...) return false; // 根据data创建新的节点 var newNode = new Node(data); // 判断原来的链表是否为空
removeAt(position) 用途: 移除指定位置的元素 越界判断 首先,对于position做一下负数和大于链表长度的越界判断。
思路: 定义current不断向下查找,用index记录索引值。对比current的data和我们传入的参数data,如果相等,把index返回。
带头链表⾥的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这⾥“放哨的”。哨兵位存在的意义:避免链表出现死循环。...双向链表的结构:数据+指向下一个节点的指针+指向前一个节点的指针 typedef int LTDataType; typedef struct ListNode { LTDataType data...; struct Listnode* prev; struct Listnode* next; }LTNode; 双向链表为空,只有一个头结点。 ...首先我们进行初始化: void LTInit(LTNode**pphead);//双向链表的初始化 LTNode* LTBuyNode(LTDataType x) { LTNode*node=(LTNode...,链表必须初始化到只有一个头节点的情况 { //给链表创建一个哨兵位 *pphead=LTBuyNode(-1); } 插入数据 首先我们要申请一个新的节点,再改变指针的指向。
双向链表 有关链表的知识可以点击我上篇文章这里就不再赘述 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。...所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。...双向循环链表的可以点击我这篇文章这里就不再赘述DoubleLoopLinkList 添加 头添加 void addFirst(const T &e) { //新建一个节点让它前驱指向头,后继指向头的后继然后再让头的后继指向新建的节点
双向链表的结构 注意: 这⾥的“带头”跟前面我们说的“头节点”是两个概念,带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨的”。...双向链表的实现 定义双向链表中节点的结构 //定义双向链表中节点的结构 typedef int LTDataType; typedef struct ListNode { LTDataType data...; struct ListNode* prev; struct ListNode* next; }LTNode; 初始化 注意,双向链表是带有哨兵位的,插入数据之前链表中必须要先初始化一个哨兵位 void...推荐传一级指针**(保持接口一致性)** 完整代码: //List.h #include #include #include //定义双向链表中节点的结构...顺序表和双向链表的优缺点分析
领取专属 10元无门槛券
手把手带您无忧上云