《关于建立了一年的博客终于打算动手——关于约瑟夫环的链表实现》

这是《数据结构(c语言)》的一次简单记录

第一次实验课是用链表完成了约瑟夫环

然后课上写完以后差点摸鱼被抓(写代码的事情能叫摸鱼吗(大声

其实链表也是有难点的,对于初学者来说可能链表抽象的地方就是:L = L -> next这里。

首先 L 是一个节点指针,里面的节点储存了数据和下一个节点的坐标。

L = L -> next其实就是让指针L指向L储存的下一个节点。

例如存在一个链表head -> 1 -> 2 -> 3 -> 4

L = head -> next (这里可以看出来,L此刻指向了1)

那么我们换一种写法

L= head;

L= L-> next(这里是不是就是和上面语句的作用是一样的呢,现在L的指向节点1)

让我们在操作一次

L= L ->next  (这里就是由1 指向了2)

由这个例子我们就可以直观的明白了L = L->next的意思了

来,试试看(

 以下就是上课水的代码了

 1 #include <stdio.h>
 2 #include <stdlib.h>         //包含malloc和free
 3 #include <stdbool.h>        //引入bool
 4 typedef int Elem;           //定义链表中的元素类型
 5 typedef struct List List;   //快捷定义struct List
 6 
 7 typedef struct List
 8 {
 9     Elem data;              //储存数据
10     List* next;             //储存下一个节点地址
11 } List;
12 
13 void InitList(List* L)
14 {
15     L->next = L;            //让头节点跟着的地址变为头指针;
16     L->data = 0;            //在头节点中储存该链表的长度
17 }
18 bool addList(List* L, int i, Elem data)     //i为插入位置,data为插入的数据
19 {
20     List* e = (List*)malloc(sizeof(List));  //为即将插入的节点申请内存空间
21     if (i <= 0 && i > L->data)              //如果插入位置非法则返回false
22         return false;
23     (L->data)++;                            //链表长度加一
24     for (int j = 1; j < i; j++)             //循环到(i-1)的位置
25     {
26         L = L->next;                        //每次循环指针都移动到下一个位置
27     }
28     e->data = data;                         //将数据存入待插入节点中
29     e->next = L->next;                      //e -> next = 原先第i个节点的地址 (原链表中的第i个节点变为了第(i+1)个节点)
30     L->next = e;                            // L -> next = 待插入的节点的地址 ((i-1)-> next = e) e变成了第i个节点
31     return true;
32 }
33 
34 void allList(List* L)
35 {
36     int len = L->data;                      //记录链表长度
37     for (int i = 1; i <= len; i++)
38     {
39         L = L->next;                        
40         printf("%d ", L->data);             
41     }
42     printf("\n");
43 }
44 void Josephus(List* L, int m, int k)        //从第m个人开始报数,报出k时退出
45 {
46     int len = L->data, num = 1;             //记录长度,初始化计数器
47     List* head = L;                         //记录头指针地址
48     for (int i = 1; i < m; i++)             // 因为是单向链表,为了后面删除方便让指针指向第(m-1)个元素
49     {
50         L = L->next;
51         if (head == L) {                    //当指向头指针时,跳过头指针
52             L = L->next;
53         }
54 
55     }
56     /*以第二次循环为例*/
57     //此时指针指向3,且计时器(num == 2) 与k相等 
58     while (len) {                           //当链表长度为0是跳出循环
59         if (head == L) {
60             L = L->next;    
61             continue;                        //跳过头指针且不让计数器增加
62         }
63         if (num == k)                        //如果计数器与k相等
64         {
65             List* empty = (List*)malloc(sizeof(List));      //申请临时空间储存被删除的节点
66             empty = L->next;                                //empty此时指向了4
67             if (empty == head)                              //如果empty指向头节点,跳过头节点指向下一个位置
68             {
69                 empty = empty->next;
70                 L = L->next;                                
71             }            
72             printf("出局编号为:%d\n", empty->data);        //输出出局的编号
73             L->next = empty->next;                          // 3 -> next = 4->next (1->2->3->5) 
74             num = 1;                                        //计数器归一
75             len--;                                          //链表长度减一
76             free(empty);                                    //释放4
77         }
78         L = L->next;                                        //指针右移一
79         num++;                                              //计数器加一
80     }
81 }
82 int main()
83 {
84     List L;
85     int x;
86     InitList(&L);                               //创建链表
87     for (int i = 1,j = 1; i <= 5; i++)          //添加链表中的元素
88     {
89         addList(&L, i, i);                      //该部分可以自行修改参数
90     }
91     allList(&L);                                //输出链表中的所有元素
92     Josephus(&L, 3, 2);                         //约瑟夫环 m = 3 k = 2
93     return 0;
94 }

(菜鸡发言

 

 

 

 

 

 

 

posted @ 2021-09-20 20:00  Taotao717  阅读(63)  评论(0)    收藏  举报