数据结构--线性表--约瑟夫问题

本文介绍了如何使用链表实现约瑟夫环问题,涉及链表的构建、插入、删除操作,以及头插法和尾插法的选择。实验目的是熟悉线性表在不同存储结构中的应用,通过实际操作理解链表操作策略。
摘要由CSDN通过智能技术生成

目录

一、问题描述

二、实验目的

三、需求分析 

四、方法描述

五、代码实现

六、实验结果测试

七、实验感想


一、问题描述

约瑟夫(Joseph)问题的一种描述是:编号为1,2,3,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码〈正整数〉,一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。

二、实验目的

熟悉线性表的基本运算在顺序存储结构和链式存储结构上的实现,其中重点熟悉链表的各种操作。

三、需求分析 

问题理解:构建链表,插入元素。删除链表操作,删除出列的节点,并且将前后节点连接起来,重复操作,直至所有节点出列。

解决问题的策略:

  1. 构造单向循环链表
  2. 输入相应数据,构造链表
  3. 按规则操作,输出该生节点删除,并连接前后节点,保持链表完整
  4. 重复操作,直至所有节点全部出列

四、方法描述

(1)插入:设计单循环链表,将元素头插法插入链表。保留头节点,加入节点时,加在头节点后面。而保证一开始就赋值的rear尾节点不用修改。

(2)删除:首先通过p指针查找到所要删除的节点的前一个节点,继而通过q=p->next简单地删除掉。假设所要查找的为第i个元素。

1)在堆中建立新节点p,通过循环查找到i-1,将此节点的地址赋给p。

2)设q指向第i个节点:若p=rear,则q=front->next; 否则,q=p->next;

3)即将q从链表中摘除:若q=rear,则p->next=front->next;否则,则p-next=q->next.

4)保存q元素的数据:x=q->data;

5)释放q元素:delete q;

(3)通过循环链表实现了循环查找到节点。关键部分为删除节点后进行链表的链接,从而保证链表的循环性。同时利用一个for循环来计数所查找过的节点。

五、代码实现

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

typedef struct LNode
{
    int mima;
    int num;
    struct LNode *next;
} LNode, *LinkList;

void CreateList(int n, LinkList L)
{
    LinkList p, q;
    int i;

    L->next = NULL;
    p = L;

    for (i = 1; i <= n; i++)
    {
        q = (LinkList)malloc(sizeof(LNode));
        q->num = i;
        scanf("%d", &(q->mima));
        p->next = q;
        p = q;
    }

    p->next = L->next;
}

void chuli(int m, int n, LNode *L)
{
    LinkList p, q;

    int new_mima, i;
    p = L;

    for (i = 1; i < m; i++) //找到第一个要出局的人,p指向要出局那个人的前一个,方便后续的删除操作
        p = p->next;
    while (n) //!当还有人没出去时!
    {
        new_mima = p->next->mima; //此时密码更新了

        printf("%d ", p->next->num); //出局

        q = p->next;        //将p->删除
        p->next = p->next->next;
        free(q);

        for (i = 1; i < new_mima; i++) //用新的密码new_mima重新来了
            p = p->next;

        n--; //记录:出去了一个人
    }
}

int main()
{
    LNode L;
    int m, n;

    scanf("%d", &m); //输入信息 ,m是初始密码,n是总人数
    scanf("%d", &n);

    CreateList(n, &L); //输入链表中的内容,创建循环链表
    chuli(m, n, &L);   //以约瑟夫问题的形式处理循环链表中的内容

    return 0;
}

六、实验结果测试

                    

七、实验感想

头插法和尾插法,头插法在插入操作频繁且需要保持插入顺序一致的情况下更加优势,而尾插法在插入操作较少且不需要保持插入顺序一致的情况下更加优势。头插法编程更适合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值