在计算机科学中,循环链表是一种特殊的链表结构,其中最后一个节点指向头节点,从而形成一个闭合环。本文将介绍如何使用C语言实现一个循环链表,并通过此结构解决著名的约瑟夫问题。
一、循环链表的基本结构
首先,我们定义循环链表的节点结构体。每个节点包含一个整数数据和一个指向下一个节点的指针。
typedef struct Node {
int data; // 节点数据
struct Node* next; // 指向下一个节点的指针
} *node_ptr;
在这里,`Node`结构体包含一个整型成员`data`,用于存储节点值,以及一个指向下一个节点的指针`next`。
二、创建节点
我们定义一个函数`create_node`来创建新节点:
node_ptr create_node(int data) {
node_ptr s = (node_ptr)malloc(sizeof(Node)); // 动态分配内存
if (!s) {
printf("节点开辟失败\n");
return NULL; // 返回NULL表示创建失败
}
s->data = data; // 设置节点数据
s->next = NULL; // 初始化next指针为NULL
return s; // 返回新节点
}
该函数首先动态分配内存,然后初始化节点的数据和指针。
三、创建循环链表
我们使用`circular_linklist`函数创建一个循环链表:
node_ptr circular_linklist(int n) {
node_ptr head = create_node(1); // 创建头节点
node_ptr temp = head; // 指向当前节点
for (int i = 2; i <= n; i++) {
temp->next = create_node(i); // 创建新节点并链接
temp = temp->next; // 移动到新节点
}
temp->next = head; // 最后一个节点指向头节点,形成循环
return head; // 返回链表头
}
在该函数中,我们首先创建头节点,然后通过循环创建后续节点,并在最后将最后一个节点的`next`指针指向头节点,以形成循环链表。
四、约瑟夫问题的处理
约瑟夫问题是一个经典的数学问题,描述了一群人围坐成一圈,每隔一定数量的人就会被淘汰,最后剩下的那个人即为胜利者。我们使用`process`函数来解决这一问题:
void process(node_ptr head, int m, int n) {
node_ptr current = head; // 当前节点
node_ptr prev = NULL; // 前一个节点
if (current == NULL) {
printf("head is empty\n");
return; // 检查链表是否为空
}
if (m > 1) {
while (current->next != current) { // 直到只剩一个节点
for (int i = 1; i < m; i++) {
prev = current; // 移动前一个节点
current = current->next; // 移动当前节点
}
printf("去除: %d\n", current->data); // 输出被淘汰的节点
prev->next = current->next; // 更新链表链接
free(current); // 释放被淘汰节点的内存
current = prev->next; // 移动到下一个节点
}
printf("\n");
printf("胜利者: %d\n", current->data); // 输出胜利者
free(current); // 释放最后一个节点
} else if (m < 1) {
printf("人数错误\n");
return; // 检查m的有效性
} else if (m == 1) {
printf("胜利者: %d\n", n); // 特殊情况处理
}
}
在该函数中,我们首先检查链表是否为空。然后,如果`m`大于1,我们进入一个循环,直到只剩下一个节点。在每次循环中,我们移动到第`m`个节点并将其淘汰。最后,输出胜利者的信息。
五、总结
本文介绍了如何使用C语言实现一个循环链表,并通过此结构解决约瑟夫问题。循环链表的结构使得在节点之间的遍历变得更加灵活,同时也为解决特定问题提供了便利。通过掌握循环链表的实现及约瑟夫问题的解决方法,读者可以更深入地理解链表的特性及其应用。希望本文能够帮助读者在实际编程中灵活运用循环链表。
Lk.h
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} *node_ptr;
node_ptr create_node(int data);
node_ptr circular_linklist(int n);
void process(node_ptr head, int m,int n);
Lk.cpp
#include "Lk.h"
node_ptr create_node(int data) {
node_ptr s = (node_ptr)malloc(sizeof(Node));
if (!s) {
printf("节点开辟失败\n");
return NULL;
}
s->data = data;
s->next = NULL;
return s;
}
node_ptr circular_linklist(int n) {
node_ptr head = create_node(1);
node_ptr temp = head;
for (int i = 2; i <= n; i++) {
temp->next = create_node(i);
temp = temp->next;
}
temp->next = head;
return head;
}
void process(node_ptr head, int m,int n) {
node_ptr current = head;
node_ptr prev = NULL;
if (current == NULL){
printf("head is empty\n");
return;
}
if (m > 1){
while (current->next != current) {
for (int i = 1; i < m; i++) {
prev = current;
current = current->next;
}
printf("去除: %d\n", current->data);
prev->next = current->next;
free(current);
current = prev->next;
}
printf("\n");
printf("胜利者: %d\n", current->data);
free(current);
}
else if(m<1){
printf("人数错误\n");
return;
}
else if(m == 1)
{
printf("胜利者: %d\n", n);
}
}
main
#include"Lk.h"
int main() {
/*typedef struct Node {
int data;
struct Node* next;
} *node_ptr;
node_ptr create_node(int data);
node_ptr circular_linklist(int n);
void process(node_ptr head, int m);*/
int n = 0;
int m = 1;
printf("人数: ");
scanf_s("%d", &n);
printf("步长:");
scanf_s("%d", &m);
printf("\n");
node_ptr head = (node_ptr)malloc(sizeof(Node));
head = circular_linklist(n);
process(head, m,n);
//无需再次进行内存释放
head = NULL;
return 0;
}

1185

被折叠的 条评论
为什么被折叠?



