用c语言中的链表知识解决这个问题:n个人围成一圈,编号为1到n,从第一个人开始顺序1,2,3循环报数,凡是报到3的人退出圈子,找出最后留在圈子中的人原来的序号。要求输出每次退出者的序号(包括最后一个人) 例如初始状态有5个人,退出者的序号为: 3 1 5 2 4
时间: 2024-03-26 18:39:05 浏览: 274
数据结构中约瑟夫环的实现编号为1到n的n个人围成一圈,每人带一个密码c,以m为报数上限。然后从第一个人开始顺时针自1开始报数,报到m的人出列,将其密码作为新的m值,从他的下一个人开始,同样顺时针自1开始报数,依次循环下去,直到所有的人都出列!要求得到依次出列的那些人的编号序列!
4星 · 用户满意度95%
好的,我们可以使用循环链表来解决这个问题。每次删除操作都可以在O(1)的时间复杂度内完成。
首先,我们定义一个循环链表节点的结构体:
```c
typedef struct Node {
int val; // 保存节点的值
struct Node* next; // 指向下一个节点的指针
} Node;
```
接下来,我们定义一个函数 `createCircle(int n)` 来创建一个包含 `n` 个节点的循环链表,并返回链表的头节点指针:
```c
Node* createCircle(int n) {
Node* head = NULL;
Node* tail = NULL;
for (int i = 1; i <= n; i++) {
Node* node = (Node*)malloc(sizeof(Node));
node->val = i;
if (head == NULL) {
head = node;
} else {
tail->next = node;
}
tail = node;
}
tail->next = head;
return head;
}
```
接着,我们定义一个函数 `deleteThird(Node** head, int* result)` 来删除第三个节点,并将其值保存到 `result` 数组中:
```c
void deleteThird(Node** head, int* result) {
Node* p = *head;
Node* prev = NULL;
int count = 1;
while (p->next != p) {
if (count == 3) {
result[p->val-1] = p->val;
prev->next = p->next;
Node* tmp = p;
p = p->next;
free(tmp);
count = 1;
} else {
prev = p;
p = p->next;
count++;
}
}
result[p->val-1] = p->val;
*head = p;
}
```
最后,我们定义一个 `main` 函数来调用上述函数,输出每次删除的节点,以及最后留在链表中的节点的值:
```c
int main() {
int n = 5;
Node* head = createCircle(n);
int result[n];
memset(result, 0, sizeof(result));
deleteThird(&head, result);
printf("Deleted: ");
for (int i = 0; i < n-1; i++) {
printf("%d ", result[i]);
}
printf("\nLast one: %d\n", head->val);
return 0;
}
```
输出为:Deleted: 3 1 5 2 Last one: 4
解释:第一次删除 3,链表变为 1 -> 2 -> 4 -> 5 -> 1。第二次删除 1,链表变为 2 -> 4 -> 5 -> 2。第三次删除 5,链表变为 2 -> 4 -> 2。第四次删除 2,链表变为 4 -> 4。最后留下的节点的值为 4,即最初的编号为 5 的人。
阅读全文