线性表的链式存储结构

线性表的链式存储结构

实验目的:

通过本次实验,掌握较复杂线性表的顺序存储结构、基本操作及应用。

实验原理:

  数据结构的选择:选择链式存储结构是因为它可以动态地插入和删除节点,适合处理约瑟夫问题中的动态变化。
  动态操作的实现:链式存储结构允许在不移动其他元素的情况下,通过改变指针来实现节点的插入和删除,这在约瑟夫问题中是必要的。
  循环链表的特性:循环链表使得问题更加简洁,因为排除操作可以在一个环中完成,不需要特殊处理边界条件。
  算法的效率:通过优化算法,例如使用两个指针(一个快指针和一个慢指针),可以提高解决约瑟夫问题的效率。

实验内容:

  初始化链表:创建一个包含 n 个节点的循环链表,每个节点代表一个人,节点中存储编号信息。
  报数和排除:从头节点开始,进行循环遍历,每次遍历到第 m 个节点时,将其从链表中删除(即断开该节点的前一个节点和后一个节点的连接),同时将头节点移动到下一个节点,继续进行报数和排除操作。
  循环直至结束:重复上述步骤,直到链表中只剩下一个节点,该节点即为最终剩下的人,记录其编号。
  输出结果:输出最后剩下的人的编号,即为约瑟夫问题的解。

实验步骤及结果:

#include<stdio.h>
#include<stdlib.h>

// 定义链表节点的结构体
typedef struct Node{
    int data; // 存储节点的数据
    struct Node* next; // 指向下一个节点的指针
} Node;

// 创建一个新节点的函数
Node* Create(){
    Node* head; // 定义头指针
    head = (Node*)malloc(sizeof(Node)); // 动态分配内存给新节点
    if (head == NULL) { // 检查内存分配是否成功
        exit(1); // 如果失败,则退出程序
    }
    head->next = NULL; // 新节点的下一个节点初始化为NULL
    return head; // 返回新节点的指针
}

int main()
{
    int n, m, i; // 定义变量n和m,分别代表人数和报数
    Node * tail, * p, * q; // 定义尾指针、遍历指针p和q
    Node* head = Create(); // 创建链表的头节点

    // 提示用户输入人数和报数
    printf("请输入围成一圈的人数: ");
    scanf("%d", &n); // 读取用户输入的人数
    printf("请输入报数出局的数字: ");
    scanf("%d", &m); // 读取用户输入的报数

    // 判断输入是否有效
    if (n == 0 || m == 0) { // 如果人数或报数为0,则直接结束程序
        return 0;
    } else {
        tail = head; // 初始时,尾指针指向头节点
        // 循环创建新节点并插入到链表中
        for (i = 0; i < n; i++) {
            p = (Node*)malloc(sizeof(Node)); // 动态分配新节点
            if (p == NULL) { // 检查内存分配是否成功
                printf("申请失败!\n");
                exit(1);
            }
            p->data = i + 1; // 设置新节点的数据
            tail->next = p; // 将新节点插入到链表的尾部
            p->next = head->next; // 新节点的下一个节点指向头节点的下一个节点
            tail = p; // 更新尾指针为新节点
        }
    }

    p = head->next; // 遍历指针p从第一个节点开始
    q = tail; // 遍历指针q从最后一个节点开始
    i = 1; // 报数从1开始

    // 进行报数出局操作,直到链表中只剩下一个节点
    while (p != q) {
        if (i == m) { // 如果报数达到m,则当前节点p出局
            q->next = p->next; // 将p的下一个节点连接到q的后面
            printf("%d ", p->data); // 打印出局节点的数据
            free(p); // 释放内存,防止内存泄漏
            p = q->next; // 更新遍历指针p到下一个节点
            i = 1; // 重新开始报数
        } else { // 如果未达到报数m,遍历指针p和q都向后移动一位
            q = p; // q先移动到p的位置
            p = q->next; // 然后p移动到q的下一个位置
            i++; // 报数加1
        }
    }

    // 打印最后一个出局的节点的数据
    printf("%d\n", p->data); 
    return 0; // 程序结束
}

结语

  实验中通过C语言实现了约瑟夫问题,观察到链表的动态变化和算法执行过程,但存在效率和内存管理的问题。通过实验,我们可以观察到链表在每一步操作中的动态变化,包括节点的添加、删除和指针的更新。这有助于我们理解链表数据结构的特点和操作过程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值