Linux内核链表复用实现队列

有了前面Linux内核复用实现栈的基础,使用相同的思想实现队列,也是非常简单的。普通单链表复用实现队列,总会在出队或入队的时候有一个O(n)复杂度的操作,大多数采用增加两个变量,一个head,一个tail来将O(n)降成O(1)。但是在内核链表中,天然的双向循环链表,复用实现队列,无论出队还是入队,都是O(1)时间复杂度。

/* main.c   */

#include <stdio.h>
#include <stdlib.h>

#include "queue.h"

struct person
{
    int age;
    struct list_head list;
};

int main(int argc,char **argv)
{
    int i;
    int num =5;
    struct person *p;
    struct person head;
    struct person *pos,*n;

    queue_creat(&head.list);

    p = (struct person *)malloc(sizeof(struct person )*num);

    for (i = 0;i < num;i++) {
        p->age = i*10;
        in_queue(&p->list,&head.list);
        p++;
    }
    printf("original==========>\n");
    list_for_each_entry_safe(pos,n,&head.list,list) {
        printf("age = %d\n",pos->age);
    }
    printf("size = %d\n",get_queue_size(&head.list));
    struct person test;
    test.age = 100;
    printf("out_queue %d\n",get_queue_head(pos,&head.list,list)->age);
    out_queue(&head.list);
    printf("out_queue %d\n",get_queue_head(pos,&head.list,list)->age);
    out_queue(&head.list);
    printf("in_queue %d\n",test.age);
    in_queue(&test.list,&head.list);

    printf("current==========>\n");
    list_for_each_entry_safe(pos,n,&head.list,list) {
        printf("age = %d\n",pos->age);
    }
    printf("size = %d\n",get_queue_size(&head.list));
    printf("all member out_queue\n");
    list_for_each_entry_safe(pos,n,&head.list,list) {
        out_queue(&head.list);
    }
    printf("size = %d\n",get_queue_size(&head.list));
    if (is_empt_queue(&head.list)) {
        printf("is_empt_queue\n");
    }

    return 0;
}
/*   queue.c  */

#include "queue.h"

void queue_creat(struct list_head *list)
{
    INIT_LIST_HEAD(list);
}

void in_queue(struct list_head *new, struct list_head *head)
{
    list_add_tail(new,head);
}

void out_queue(struct list_head *head)
{
    struct list_head *list = head->next; /* 保存链表的最后节点 */

    list_del(head->next);/* 头删法 */

    INIT_LIST_HEAD(list); /* 重新初始化删除的最后节点,使其指向自身 */

}

int get_queue_size(struct list_head *head)
{
    struct list_head *pos;
    int size = 0;

    if (head == NULL) {
        return -1;
    }

    list_for_each(pos,head) {
        size++;
    }

    return size;

}

bool is_empt_queue(struct list_head *head)
{
    return list_empty(head);
}
/*  queue.h  */

#ifndef _QUEUE_H_
#define _QUEUE_H_

#include <stdbool.h>
#include "list.h"

#define get_queue_head(pos, head, member)        \
        list_entry((head)->next, typeof(*pos), member)

void queue_creat(struct list_head *list);
void in_queue(struct list_head *new, struct list_head *head);
void out_queue(struct list_head *entry);
int get_queue_size(struct list_head *head);
bool is_empt_queue(struct list_head *head);

#endif /* _QUEUE_H_ */

运行结果:

复用Linux内核链表实现队列,时间复杂可以很简单的实现O(1),当然,其中的遍历队列长度是O(n),不过这个在之前的随笔中也说到了,根据具体的应用场景,可以在入队的时候在头结点中size+1,出队的时候在头结点中size-1,获取队列大小的函数就可以直接返回size了,是可以很轻易做到O(1)的时间复杂度的。掌握了Linux内核链表,链表,栈和队列这样的数据结构,就可以很容易的实现复用,并且可以应用在实际项目中。

原文地址:https://www.cnblogs.com/yangguang-it/p/11832136.html

时间: 2024-07-30 06:22:48

Linux内核链表复用实现队列的相关文章

链表的艺术——Linux内核链表分析

引言: 链表是数据结构中的重要成员之中的一个.因为其结构简单且动态插入.删除节点用时少的长处,链表在开发中的应用场景许多.仅次于数组(越简单应用越广). 可是.正如其长处一样,链表的缺点也是显而易见的.这里当然不是指随机存取那些东西,而是因为链表的构造方法(在一个结构体中套入其同类型指针)使得链表本身的逻辑操作(如添加结点,删除结点,查询结点等),往往与其应用场景中的业务数据相互混杂.这导致我们每次使用链表都要进行手工打造,做过链表的人肯定对此深有了解. 是否能将链表从变换莫測的业务数据中抽象出

Linux 内核 链表 的简单模拟

第零章:扯扯淡 出一个有意思的题目:用一个宏定义FIND求一个结构体struct里某个变量相对struc的编移量,如 struct student { int a; //FIND(struct student,a) 等于0 char b; //FIND(struct student,b)等于4 double c; }; 参考答案:#define FIND(type,member) ((size_t)&((type*)0)->member) 我这样理解(可能不太正确): (type*)0,0在

Linux 内核链表

一 . Linux内核链表 1 . 内核链表函数 1.INIT_LIST_HEAD:创建链表 2.list_add:在链表头插入节点 3.list_add_tail:在链表尾插入节点 4.list_del:删除节点 5.list_entry:取出节点 6.list_for_each:遍历链表 2.程序代码

例说Linux内核链表(二)

链表使用 我认为熟悉内核链表功能最好的方法就是看一些简单的实例,实例是一个非常好的素材去更好的理解链表. 下面是一个例子,包含创建,添加,删除和遍历链表. <span style="font-size:14px;"><span style="color:#330099;">#include <stdio.h> #include <stdlib.h> #include "list.h" struct

Linux 内核 链表 的简单模拟(2)

接上一篇Linux 内核 链表 的简单模拟(1) 第五章:Linux内核链表的遍历 /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) for (pos = (head)->next; pos != (head);

例说Linux内核链表(一)

介绍 众所周知,Linux内核大部分是使用GNU C语言写的.C不同于其他的语言,它不具备一个好的数据结构对象或者标准对象库的支持.所以可以借用Linux内核源码树的循环双链表是一件很值得让人高兴的事. 在include/linux/list.h文件中用C实现了一个好用的循环链表.它是有效而且易于操作的,否则它也不会被内核使用(译者注:在kernel中大量的使用了循环双链表结构,比如在在进程描述符实体中我们就可以看到很多struct list_head的身影).不管何时,依靠这种结构,在内核中都

例说Linux内核链表(三)

经常使用的linux内核双向链表API介绍 linux link list结构图例如以下: 内核双向链表的在linux内核中的位置:/include/linux/list.h 使用双向链表的过程,主要过程包括创建包括struct link_head结构的结构体(item),建立链表头.向链表中加入item(自己定义数据结构.双向链表数据单元).删除链表节点.遍历链表,判空等. 1.建立自己定义链表数据结构 struct kool_list{ int to; struct list_head li

linux内核链表的使用

linux内核链表:链表通常包括两个域:数据域和指针域.struct list_head{struct list_head *next,*prev;};include/linux/list.h中实现了一套精彩的链表数据结构.传统的链表指针指向下一个节点的头部.linux链表指针指向下一个指针list_head结构(*next),双向循环.不会随着外部数据的变化而变化,使它具有通用性.? -------------------------------------------------------

linux内核链表的移植与使用

一.  Linux内核链表为双向循环链表,和数据结构中所学链表类似,具体不再细讲.由于在内核中所实现的函数十分经典,所以移植出来方便后期应用程序中的使用. /*********************************** 文件名:kernel link list of linux.h 作者:Bumble Bee 日期:2015-1-31 功能:移植linux内核链表 ************************************/ /*链表结点数据结构*/ struct lis