C语言中的循环链表与约瑟夫问题的实现

在计算机科学中,循环链表是一种特殊的链表结构,其中最后一个节点指向头节点,从而形成一个闭合环。本文将介绍如何使用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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值