博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核链表题目
阅读量:5987 次
发布时间:2019-06-20

本文共 11415 字,大约阅读时间需要 38 分钟。

==============================================

      先来个知识背景:

  我们都知道数组是存储数据的一种方式,但是数组对里面数据的操作比较麻烦(插入、删除等)

所以,我们有了单链表,单链表对于数据的插入删除都比数组方便很多,但是还是不那么方便,为什么?

因为,我们只能从头节点(一般的链表都有头节点,当然了循环队列除外)查找数据,不能往上查找,只能往下查找。

所以,我们又有了双向链表,它集成了单向链表的优点,解决了单链表的不足,使数据的操作变得方便很多,但是这也不是很方便.......

看到这里也就引出了主角---内核链表....(掌声~~~~)

  `

        什么是内核链表? 它解决了双链表什么问题?

################################################################################# 

   先说第一个:

内核链表是双向链表的变种,它将逻辑与数据分开,这里有两个结构体

// 自己定义的结构体typedef struct node{    datatype data;    struct list_head list;}listnode, *linklist;// 内核代码提供struct list_head {    struct list_head *next, *prev;};

可以看到 listnode 这个结构体包含了 struct list_head 这种类型的结构体.

listnode是我们说的数据(大结构体),struct list_head是我们说的逻辑(小结构体)------小结构体嵌到大结构体里面

 

###########################################################################

  那第二个呢? 内核链表有什么特殊的,它能解决传统的双向链表什么缺点。

   内核链表的诀窍在于数据和逻辑分来!

   如果是传统的双向链表,它是不能灵活处理因链表变化的需求,因为它和数据捆绑在一块,

链表里面的数据变了那整个链表都变了,处理它的函数都需要改(尽管实现的逻辑代码一样)。

   内核链表数据和逻辑是分开的,所以大结构体的变化是不影响小结构体的逻辑代码的!

所以....................内核代码就是很厉害了 0``0..

 

      那么我们先来欣赏下用内核代码实现的一道小题目吧

                代码如下

/*   XXX.c文件   */#include 
#include
#include
#include
#include
#include
#include "kernel_list.h"#ifndef DATATYPE #define DATATYPE int#endiftypedef DATATYPE datatype;// 在一个特殊的节点中,包含通用的标准链表实现typedef struct node{ datatype data; struct list_head list;}listnode, *linklist;linklist init_list(void){ // 申请一个头节点 linklist head = calloc(1, sizeof(listnode)); if(head != NULL) { //head->list.next = head->list.prev = &head->list; INIT_LIST_HEAD(&head->list);  (在内核头文件) } return head;}linklist new_node(int i){ linklist new = calloc(1, sizeof(struct node)); if(new == NULL) { printf("creat new failed\n"); exit(0); } new->data = i; new->list.next = new->list.prev = NULL; return new;}void show(linklist head){ struct list_head *pos; linklist tmp; list_for_each(pos, &head->list)  (在内核头文件) { // 将小结构体转换成大结构体 tmp = list_entry(pos, listnode, list);  (在内核头文件) printf("%d", tmp->data); } printf("\n");}void rearrange(linklist head){ struct list_head *tmp; struct list_head *pos; linklist p; bool first = true; // 遍历所有小节点 list_for_each_prev(pos, &head->list)  (在内核头文件) { // 将小结构体转换成大结构体 p = list_entry(pos, listnode, list); (在内核头文件) // 这是一个偶数!并且不是第一个偶数!将他移动到链表的末尾 if(p->data % 2 == 0 && first != true) { // 将这个节点移到链表最后 list_move_tail(pos, &head->list);  (在内核头文件) pos = tmp; } else // 遇到奇数,就记下这个位置 { tmp = pos; } first = false; } }int main(void){ // 搞一个空双向循环链表 linklist head = init_list(); if(head == NULL) { printf("init failed"); exit(0); } // 依次插入若干个节点 int n; scanf("%d", &n); int i; for(i=1; i<=n; i++) { linklist new = new_node(i); // 传入 小结构体节点的地址、小结构体头节点的地址 (在内核头文件) list_add_tail(&new->list, &head->list); } // 显示链表里面的所有节点看看是否正确 show(head); // 按照题目需要,奇偶数重新排列 rearrange(head); // 再次显示链表里面的所有节点看看是否正确 show(head); return 0;}
1 /*内核头文件 */  2 #ifndef __DLIST_H  3 #define __DLIST_H  4   5 /* This file is from Linux Kernel (include/linux/list.h)  6 * and modified by simply removing hardware prefetching of list items.  7 * Here by copyright, credits attributed to wherever they belong.  8 * Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu)  9 */ 10  11 /* 12 * Simple doubly linked list implementation. 13 * 14 * Some of the internal functions (“__xxx”) are useful when 15 * manipulating whole lists rather than single entries, as 16 * sometimes we already know the next/prev entries and we can 17 * generate better code by using them directly rather than 18 * using the generic single-entry routines. 19 */ 20 /** 21  * container_of - cast a member of a structure out to the containing structure 22  * 23  * @ptr:    the pointer to the member. 24  * @type:    the type of the container struct this is embedded in. 25  * @member:    the name of the member within the struct. 26  * 27  */ 28 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 29  30 #define container_of(ptr, type, member) ({            \ 31         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \ 32         (type *)( (char *)__mptr - offsetof(type,member) );}) 33 /* 34  * These are non-NULL pointers that will result in page faults 35  * under normal circumstances, used to verify that nobody uses 36  * non-initialized list entries. 37  */ 38 #define LIST_POISON1  ((void *) 0x00100100) 39 #define LIST_POISON2  ((void *) 0x00200) 40  41 struct list_head { 42     struct list_head *next, *prev; 43 }; 44  45 #define LIST_HEAD_INIT(name) { &(name), &(name) } 46  47 #define LIST_HEAD(name) \ 48 struct list_head name = LIST_HEAD_INIT(name) 49  50 #define INIT_LIST_HEAD(ptr) do { \ 51     (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 52 } while (0) 53  54 /* 55 * Insert a new entry between two known consecutive entries. 56 * 57 * This is only for internal list manipulation where we know 58 * the prev/next entries already! 59 */ 60 static inline void __list_add(struct list_head *new, 61                 struct list_head *prev, 62                 struct list_head *next) 63 { 64     next->prev = new; 65     new->next = next; 66     new->prev = prev; 67     prev->next = new; 68 } 69  70 /** 71 * list_add – add a new entry 72 * @new: new entry to be added 73 * @head: list head to add it after 74 * 75 * Insert a new entry after the specified head. 76 * This is good for implementing stacks. 77 */ 78 static inline void list_add(struct list_head *new, struct list_head *head) 79 { 80     __list_add(new, head, head->next); 81 } 82  83 /** 84 * list_add_tail – add a new entry 85 * @new: new entry to be added 86 * @head: list head to add it before 87 * 88 * Insert a new entry before the specified head. 89 * This is useful for implementing queues. 90 */ 91 static inline void list_add_tail(struct list_head *new, struct list_head *head) 92 { 93     __list_add(new, head->prev, head); 94 } 95  96 /* 97 * Delete a list entry by making the prev/next entries 98 * point to each other. 99 *100 * This is only for internal list manipulation where we know101 * the prev/next entries already!102 */103 static inline void __list_del(struct list_head *prev, struct list_head *next)104 {105     next->prev = prev;106     prev->next = next;107 }108 109 /**110 * list_del – deletes entry from list.111 * @entry: the element to delete from the list.112 * Note: list_empty on entry does not return true after this, the entry is in an undefined state.113 */114 static inline void list_del(struct list_head *entry)115 {116     __list_del(entry->prev, entry->next);117     entry->next = (void *) 0;118     entry->prev = (void *) 0;119 }120 121 /**122 * list_del_init – deletes entry from list and reinitialize it.123 * @entry: the element to delete from the list.124 */125 static inline void list_del_init(struct list_head *entry)126 {127     __list_del(entry->prev, entry->next);128     INIT_LIST_HEAD(entry);129 }130 131 /**132 * list_move – delete from one list and add as another’s head133 * @list: the entry to move134 * @head: the head that will precede our entry135 */136 static inline void list_move(struct list_head *list,137                 struct list_head *head)138 {139     __list_del(list->prev, list->next);140     list_add(list, head);141 }142 143 /**144 * list_move_tail – delete from one list and add as another’s tail145 * @list: the entry to move146 * @head: the head that will follow our entry147 */148 static inline void list_move_tail(struct list_head *list,149                     struct list_head *head)150 {151     __list_del(list->prev, list->next);152     list_add_tail(list, head);153 }154 155 /**156 * list_empty – tests whether a list is empty157 * @head: the list to test.158 */159 static inline int list_empty(struct list_head *head)160 {161     return head->next == head;162 }163 164 static inline void __list_splice(struct list_head *list,165                     struct list_head *head)166 {167     struct list_head *first = list->next;168     struct list_head *last = list->prev;169     struct list_head *at = head->next;170 171     first->prev = head;172     head->next = first;173 174     last->next = at;175     at->prev = last;176 }177 178 /**179 * list_splice – join two lists180 * @list: the new list to add.181 * @head: the place to add it in the first list.182 */183 static inline void list_splice(struct list_head *list, struct list_head *head)184 {185 if (!list_empty(list))186 __list_splice(list, head);187 }188 189 /**190 * list_splice_init – join two lists and reinitialise the emptied list.191 * @list: the new list to add.192 * @head: the place to add it in the first list.193 *194 * The list at @list is reinitialised195 */196 static inline void list_splice_init(struct list_head *list,197 struct list_head *head)198 {199 if (!list_empty(list)) {200 __list_splice(list, head);201 INIT_LIST_HEAD(list);202 }203 }204 205 /**206 * list_entry – get the struct for this entry207 * @ptr:    the &struct list_head pointer.208 * @type:    the type of the struct this is embedded in.209 * @member:    the name of the list_struct within the struct.210 */211 #define list_entry(ptr, type, member) \212 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))213 214 /**215 * list_for_each    -    iterate over a list216 * @pos:    the &struct list_head to use as a loop counter.217 * @head:    the head for your list.218 */219 #define list_for_each(pos, head) \220 for (pos = (head)->next; pos != (head); \221 pos = pos->next)222 /**223 * list_for_each_prev    -    iterate over a list backwards224 * @pos:    the &struct list_head to use as a loop counter.225 * @head:    the head for your list.226 */227 #define list_for_each_prev(pos, head) \228 for (pos = (head)->prev; pos != (head); \229 pos = pos->prev)230 231 /**232 * list_for_each_safe    -    iterate over a list safe against removal of list entry233 * @pos:    the &struct list_head to use as a loop counter.234 * @n:        another &struct list_head to use as temporary storage235 * @head:    the head for your list.236 */237 #define list_for_each_safe(pos, n, head) \238 for (pos = (head)->next, n = pos->next; pos != (head); \239 pos = n, n = pos->next)240 241 /**242 * list_for_each_entry    -    iterate over list of given type243 * @pos:    the type * to use as a loop counter.244 * @head:    the head for your list.245 * @member:    the name of the list_struct within the struct.246 */247 #define list_for_each_entry(pos, head, member)                \248 for (pos = list_entry((head)->next, typeof(*pos), member);    \249 &pos->member != (head);                     \250 pos = list_entry(pos->member.next, typeof(*pos), member))251 252 /**253 * list_for_each_entry_safe – iterate over list of given type safe against removal of list entry254 * @pos:    the type * to use as a loop counter.255 * @n:        another type * to use as temporary storage256 * @head:    the head for your list.257 * @member:    the name of the list_struct within the struct.258 */259 #define list_for_each_entry_safe(pos, n, head, member)            \260 for (pos = list_entry((head)->next, typeof(*pos), member),    \261 n = list_entry(pos->member.next, typeof(*pos), member);    \262 &pos->member != (head);                     \263 pos = n, n = list_entry(n->member.next, typeof(*n), member))264 265 #endif

   好吧,看的懂并且能从原理上理解这份代码、加上我那篇《写程序关于c语言语法的一些心得--内存和指针的正确认识》都理解了后

C语言语法就没问题了 0^0~...

 

转载于:https://www.cnblogs.com/huang321/p/6486140.html

你可能感兴趣的文章
C++的函数重载和main函数之外的工作
查看>>
js中的hasOwnProperty和isPrototypeOf方法
查看>>
杂七杂八的面试概念
查看>>
递归算法浅谈
查看>>
赵雅智_ListView_BaseAdapter
查看>>
20款优秀的国外 Mobile App 界面设计案例
查看>>
github简单使用教程
查看>>
使用instantclient_11_2 和PL/SQL Developer工具包连接oracle 11g远程数据库(转)
查看>>
娓娓道来c指针 (0)c语言的梦魇:c指针
查看>>
samsungGalaxyS4USB驱动
查看>>
myqltransactionRollbackexception deadlock found when trying to get lock
查看>>
Linux 在线模拟器
查看>>
NavigationBar 背景颜色,字体颜色
查看>>
右键菜单 GenericMenu
查看>>
〖Linux〗Kubuntu14.04 平滑字体的设置
查看>>
Windows SVN局域网设置连接
查看>>
jquery.elevateZoom实现仿淘宝看图片,一张小的,一张大用于鼠标经过时候显示
查看>>
Android WebRTC 音视频开发总结(一)
查看>>
快速生成漂亮的移动端视差滚动效果
查看>>
快速幂取模算法
查看>>