使用linux内核的list解决约瑟夫环问题

1、约瑟夫环问题:N个人围成一圈,从第一个开始报数,第M个将被淘汰,下一个重新从1开始报数,继续淘汰第M个,直到最后剩下一个。例如N=5,M=2,淘汰的顺序是:2,4,1, 5,最后获胜的是3

2、linux内核list.h:linux-5.12/drivers/gpu/drm/nouveau/include/nvif/list.h

3、代码清单:

.
├── include
│   └── list.h
├── log
│   ├── log_level_time.c
│   └── log_level_time.h
└── main.c

4、log文件夹下的log_level_time.c、log_level_time.h为自定义log打印,详情见上一篇博文"C语言实现带时间log打印及log级别设置"

5、代码解释

头文件及数据结构

  1 #include <unistd.h>
  2 #include <stdlib.h>
  3 #include "include/list.h"
  4 #include "log/log_level_time.h"
  5 
  6 struct jos_s {
  7         struct list_head list;
  8         int man_num;
  9 };
 10

定义变量


 11 int main(int argc, char* argv[])
 12 {
 13         int opt;
 14         int cnt_all, key;
 15         int i;
 16         int cnt_off = 0;
 17         struct jos_s *jos;
 18         struct list_head head;
 19 

使用main函数参数进行log初始化,比如-v 1打印DEBUG 以上级别,-v  -1打印WARN以上级别,不设置则默认打印INFO以上级别

 20         log_init(argc, argv);
 21 

main函数参数传入M和N值

 22         while((opt = getopt(argc, argv, ":c:k:")) != -1) {
 23                 switch (opt) {
 24                 case 'c':
 25                         cnt_all = atoi(optarg);
 26                         break;
 27                 case 'k':
 28                         key = atoi(optarg);
 29                         break;
 30                 default:
 31                         break;
 32                 }
 33         }
 34 
 35         LOG_INFO("cnt_all = %d, key = %d", cnt_all, key);
 36 

根据参数申请内存

 37         jos = malloc(cnt_all * sizeof(struct jos_s));
 38         if (jos == NULL) {
 39                 LOG_ERROR("malloc error");
 40                 return -1;
 41         }
 42 

使用list.h的接口,建立约瑟夫环。其中INIT_LIST_HEAD初始化链表头。list_add_tail在链表尾部添加元素,并且新添加的最后一个元素指向链表头,即环形链表。

 43         INIT_LIST_HEAD(&head);
 44 
 45         for(i = 0; i < cnt_all; i++) {
 46                 jos[i].man_num = i + 1;
 47                 list_add_tail(&jos[i].list, &head);
 48         }
 49 

模拟游戏规则,进行循环报数淘汰,直到剩下最后一个胜利者。其中list_for_each_entry_safe,为遍历链表接口。

 50         struct jos_s *pos;
 51         struct jos_s *n;
 52 
 53         while (head.next != head.prev) {
 54                 list_for_each_entry_safe(pos, n, &head, list) {
 55                         cnt_off++;
 56                         if (cnt_off == key) {
 57                                 cnt_off = 0;
 58                                 LOG_DEBUG("del %d", pos->man_num);
 59                                 list_del(&pos->list);
 60                         }
 61                 }
 62         }
 63 

输出最后获胜者。其中list_entry,根据list找到struct。

 64         pos = list_entry(head.next, struct jos_s, list);
 65         LOG_INFO("the winner is: %d", pos->man_num);
 66 
 67         free(jos);
 68         return 0;
 69 }

6、结果演示

十人,淘汰数是5,获胜者是3

$ ./jos -c 10  -k 5
[2021-05-24 00:59:14.567] [              main.c:  35] [INFO ]  cnt_all = 10, key = 5
[2021-05-24 00:59:14.569] [              main.c:  65] [INFO ]  the winner is: 3

加入参数-v 1打印DEBUG信息,输出淘汰顺序

$ ./jos -c 10  -k 5 -v 1
[2021-05-24 01:01:18.904] [              main.c:  35] [INFO ]  cnt_all = 10, key = 5
[2021-05-24 01:01:18.907] [              main.c:  58] [DEBUG]  del 5
[2021-05-24 01:01:18.908] [              main.c:  58] [DEBUG]  del 10
[2021-05-24 01:01:18.912] [              main.c:  58] [DEBUG]  del 6
[2021-05-24 01:01:18.914] [              main.c:  58] [DEBUG]  del 2
[2021-05-24 01:01:19.028] [              main.c:  58] [DEBUG]  del 9
[2021-05-24 01:01:19.028] [              main.c:  58] [DEBUG]  del 8
[2021-05-24 01:01:19.028] [              main.c:  58] [DEBUG]  del 1
[2021-05-24 01:01:19.028] [              main.c:  58] [DEBUG]  del 4
[2021-05-24 01:01:19.028] [              main.c:  58] [DEBUG]  del 7
[2021-05-24 01:01:19.028] [              main.c:  65] [INFO ]  the winner is: 3

一亿人,淘汰数是5,最后获胜者是35852477

 ./jos -c 100000000  -k 5 
[2021-05-23 15:20:37.278] [              main.c:  35] [INFO ]  cnt_all = 100000000, key = 5
[2021-05-23 16:41:10.463] [              main.c:  65] [INFO ]  the winner is: 35852477

7、list.h代码可从linux内核源码获取,本文使用的linux5.12源码的linux-5.12/drivers/gpu/drm/nouveau/include/nvif/list.h

------谢谢阅读------

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值