plist

https://elixir.bootlin.com/linux/v4.9.59/source/include/linux/plist.h#L212

*Descending-priority-sorted double-linked list (*降序优先排序的双向链表)

plist是一个按优先级排序的节点列表; 每个节点的优先级从 INT_MIN(最高)到 INT_MAX(最低)。

插入的时间复杂度为O(k), 删除的时间复杂度为O(1), 变更节点优先级的时间复杂度是O(k)。其中K是系统中RT优先级的数量。(1≤K≤99)

数据结构

//plist 头
struct plist_head {struct list_head node_list;
};//plist 节点
struct plist_node {int          prio;struct list_head   prio_list;struct list_head  node_list;
};

plist是由两个双向循环链表形成的具备优先级的双向链表。其中

  1. 每个节点的plist_node按prio值重小(优先级最高)到大(优先级最小)以node_list排序形成链表,prio值相同的节点按先插入在前的顺序。
  2. 不同prio值的节点又按小到大的顺序以prio_list排序形成链表。其中prio值相同的节点,仅最早插入链表的节点被链接到prio_list中,其余节点prio_list为空。

这种结构使得插入节点时,通过变量prio_list能快速找到插入位置,不需变量相同prio的节点。同时node_list是以prio小到大排序,相同prio的节点,最早插入的节点在前;按优先级出队时只需要取第一个节点,能实现,高优先级优先出对,同优先级实现FIFO功能。

宏/函数

初始化plist头和节点

静态初始化

创建变量并初始化。

/**p* PLIST_HEAD_INIT - 静态初始化plist头结构体。* @head: struct plist_head variable name*/
#define PLIST_HEAD_INIT(head)               \
{                           \.node_list = LIST_HEAD_INIT((head).node_list) \
}/*** PLIST_HEAD - 定义并初始化一个plist头。* @head: name for struct plist_head variable*/
#define PLIST_HEAD(head) \struct plist_head head = PLIST_HEAD_INIT(head)/*** PLIST_NODE_INIT - 静态初始化plistd节点结构体。* @node:  struct plist_node variable name* @__prio:  initial node priority*/
#define PLIST_NODE_INIT(node, __prio)           \
{                           \.prio  = (__prio),                \.prio_list = LIST_HEAD_INIT((node).prio_list),    \.node_list = LIST_HEAD_INIT((node).node_list),    \
}

动态初始化

给已定义变量初始化

/*** plist_head_init - 动态初始化plist头* @head:  &struct plist_head pointer*/
static inline void
plist_head_init(struct plist_head *head)
{INIT_LIST_HEAD(&head->node_list);
}/*** plist_node_init - 动态初始化plist节点* @node:   &struct plist_node pointer* @prio: initial node priority*/
static inline void plist_node_init(struct plist_node *node, int prio)
{node->prio = prio;INIT_LIST_HEAD(&node->prio_list);INIT_LIST_HEAD(&node->node_list);
}

插入删除plist节点

插入节点

/*** plist_add - add @node to @head** @node:  &struct plist_node pointer* @head: &struct plist_head pointer*/
void plist_add(struct plist_node *node, struct plist_head *head)
{struct plist_node *first, *iter, *prev = NULL;struct list_head *node_next = &head->node_list;plist_check_head(head);WARN_ON(!plist_node_empty(node));WARN_ON(!list_empty(&node->prio_list));if (plist_head_empty(head)) //情况1。goto ins_node;first = iter = plist_first(head);//list_entry(head->node_list.next,struct plist_node, node_list);do {if (node->prio < iter->prio) {node_next = &iter->node_list;break; //prio小于链表中某个节点;和上一个节点相同,情形3;和上一个节点不同,情形4;}prev = iter;iter = list_entry(iter->prio_list.next,struct plist_node, prio_list);} while (iter != first); //遍历完,prio最大,情形2;prio和最后一个节点相同,情形3;if (!prev || prev->prio != node->prio) //只有prio和链表中的节点不同,才需要插入到prio_listlist_add_tail(&node->prio_list, &iter->prio_list);  ins_node:list_add_tail(&node->node_list, node_next); //plist_check_head(head);
}

插入节点分为4种情况:

  1. node_list链表为空;新节点node_list直接插入到node_list链表头。
  2. node_list链表非空,新节点prio大于node_list链表中所有的节点;新节点node_list插入到node_list链表的尾,prio_list插入prio_list链表尾。
  3. node_list链表非空,新节点prio等于node_list链表中某个节点;新节点node_list插入node_list链表当前位置的后面,prio_list为空。
  4. node_list链表非空,新节点prio小于node_list链表中某个节点;新节点node_list插入该节点node_list链表的前面, prio_list插入prio_list链表前面。

删除节点

/*** plist_del - Remove a @node from plist.** @node:   &struct plist_node pointer - entry to be removed* @head:   &struct plist_head pointer - list head*/
void plist_del(struct plist_node *node, struct plist_head *head)
{plist_check_head(head);if (!list_empty(&node->prio_list)) {if (node->node_list.next != &head->node_list) {struct plist_node *next;next = list_entry(node->node_list.next,struct plist_node, node_list);/* add the next plist_node into prio_list */if (list_empty(&next->prio_list))list_add(&next->prio_list, &node->prio_list); //情形3.a} //else 情形2list_del_init(&node->prio_list);} //else 情形1list_del_init(&node->node_list);plist_check_head(head);
}

删除有以下3种大情形:

  1. 如果待删节点prio_list为空(即和别的节点有相同prio值,且不是第一入队的节点);直接从node_list链表中删除。
  2. 如果待删节点prio_list非空,且是head中node_list链表的最后一个;先从prio_list删除,再重node_list散除。
  3. 如果待删节点prio_list非空,且不是head中node_list链表的最后一个;
    1. 如果待删节点的再node_list链表的下一个节点的prio_list为空(待删节点和node_list的下一节点有相同的prio值),需要先将下一个节点添加到prio_list链表,再进行下一步删除。
    2. 先从prio_list删除,再重node_list删除。

辅助函数

/*** 判断指定plist头是否空* plist_head_empty - return !0 if a plist_head is empty* @head:   &struct plist_head pointer*/
static inline int plist_head_empty(const struct plist_head *head)
{return list_empty(&head->node_list);
}/*** 判断指定plist节点是否空* plist_node_empty - return !0 if plist_node is not on a list* @node:  &struct plist_node pointer*/
static inline int plist_node_empty(const struct plist_node *node)
{return list_empty(&node->node_list);
}/*** plist_next - get the next entry in list* @pos:   the type * to cursor*/
#define plist_next(pos) \list_next_entry(pos, node_list)/*** plist_prev - get the prev entry in list* @pos:    the type * to cursor*/
#define plist_prev(pos) \list_prev_entry(pos, node_list)/*** 获取plist第一个节点* plist_first - return the first node (and thus, highest priority)* @head:    the &struct plist_head pointer** Assumes the plist is _not_ empty.*/
static inline struct plist_node *plist_first(const struct plist_head *head)
{return list_entry(head->node_list.next,struct plist_node, node_list);
}/*** 获取plist最后一个节点。* plist_last - return the last node (and thus, lowest priority)* @head:    the &struct plist_head pointer** Assumes the plist is _not_ empty.*/
static inline struct plist_node *plist_last(const struct plist_head *head)
{return list_entry(head->node_list.prev,struct plist_node, node_list);
}

Linux中的Plist -- 降序优先排序的双向链表相关推荐

  1. pandas中dataframe索引排序实战:pandas中dataframe索引降序排序、pandas中dataframe索引升序排序

    pandas中dataframe索引排序实战:pandas中dataframe索引降序排序.pandas中dataframe索引升序排序 目录

  2. Java中sort实现降序排序

    Java中sort实现降序排序 利用Collections的reverseOrder方法: import java.util.Arrays; import java.util.Collections; ...

  3. linux按文件大小显示,Linux显示按文件大小降序排列

    Linux显示按文件大小降序排列 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ ls -ls 总用量 56 12 -rw-r--r-- 1 youhaidon ...

  4. 输入整型数组和排序标识,对其元素按照升序或降序进行排序(华为OJ系列)

    输入整型数组和排序标识,对其元素按照升序或降序进行排序接口说明原型:void sortIntegerArray(Integer[] pIntegerArray, int iSortFlag);输入参数 ...

  5. linux 按列提取文件名,Linux展示按文件名降序文件

    Linux显示按文件名降序文件 Linux显示按文件名降序文件 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ ls -lr 总用量 56 drwxr-xr-x ...

  6. 奇数位升序偶数位降序链表排序

    题目描述:一个链表,奇数位升序偶数位降序,让链表变成升序的. 比如:1 8 3 6 5 4 7 2 9,最后输出1 2 3 4 5 6 7 8 9. 分析: 这道题可以分成三步: 首先根据奇数位和偶数 ...

  7. oracle中部门工资降序排列,oracle面试题整理二(10级学员 乔宇整理)

    Oracle面试题整理二(10级学员 乔宇整理) 1.查询工资最高的3 名员工信息 select * from (select * from emp order by sal desc) where ...

  8. python txt文件排序,使用Python在.txt文件中按數值(降序)排序高分列表

    I'm currently working on a challenge that requires me to save high scores to a .txt file. I'm happy ...

  9. java怎么对数组中数据进行降序排序?

    首先,想实现降序排序我们需要了解两个介绍Collections集合的两个方法: 一个是按照从小到大的排序sort方法. Collections.sort(); List<Integer> ...

最新文章

  1. 21、C#里面类的创建和使用
  2. linux mysql5.6 编码_CentOS 7下修改MySQL5.6编码方式 解决网站中文显示问号
  3. 艾伟也谈项目管理,谈谈如何说“不”
  4. python 好书推荐_关于Python的好书推荐(三)
  5. 超级好用的使用python批量更新MYsql,速度从一万条需要一天变道一万条需要10分钟左右
  6. “疯狂猜成语”软件用户体验
  7. 烂泥:NFS做存储与KVM集成
  8. StringUtils 中 isEmpty 和 isBlank 的区别
  9. Q115:Linux系统下CodeBlocks对PBRT-V3进行编译和调试
  10. Uva 12063 Zero and Ones
  11. cloudMusic.mps的前世今坑
  12. Visio网络及设备模板库
  13. postman安装html插件安装,Postman 安装与更新
  14. 【现代信号处理】 15 - 谱分析基础和周期图谱分析
  15. mapinfo二次开发之:MapX和MapXtreme区别
  16. SICP 第一章的练习
  17. (python)爬虫----八个项目带你进入爬虫的世界
  18. td标签高度属性不起作用
  19. 【散文】 如果今生我是你梦中的蝴蝶
  20. Android实现图片浏览功能(图片器原理实现)

热门文章

  1. 数据结构 耿国华 第三版
  2. #1024程序员节#活动勋章,当日发布原创博客即可获得
  3. 求导与原函数的奇偶性互换证明
  4. 不同scheam下查询视图报错ORA-01031的故障解决
  5. 右键菜单中新建EXCEL丢失解决办法
  6. 智慧旅游构建智能化服务平台指导方案
  7. Python数据可视化:学术图表可视化(实战篇—5)
  8. 关于山东职称评审论文发表
  9. 操作系统中的进程是如何 “调度” 的?
  10. sizeof 的小知识