张小五学算法与数据结构第四天(下):线性表的链式存储结构练习题

今天把题目进行补充说明加上一个小练习题,单向循环链表的约瑟夫环问题。

约瑟夫环问题是一个经典的数学问题,题目大致为编号分别为1,2,......,n个人围坐在一圈,约定序号为k(1<=k<=n)得人从1开始计数,数到m的那个人出列,他的下一位又从1开始计数,数到m的那个人又出列,直到所有人都出列为止。

看完这个题目之后我们就可以清楚的反应出这是一个可以用单项循环链表来完成的问题。所以我们先写出算法思路:用一个不带头结点的循环链表来处理Josephu问题,先构成一个有n个结点的单项循环链表,然后从k结点起从1计数,计到m时,对应结点从列表中删除;然后再从删除的下一个节点开始计数,直到所有节点全部列出时算法截止。

程序代码为:

linklist.h:

/*
作者:张小五
时间:2018年1月29日

*/
#ifndef LINKLIST_H_
#define LINKLIST_H_

typedef struct node{ //结点类型
    int data; //结点的数据域
    struct node *next; //结点元素的后继指针域
}linkNode,*linkp;


void CreateList(linkp H); //建立单链表
void PrintList(linkp H);//打印单链表
linkp GetList(linkp H,int i);//根据序号查找
void InsertList(linkp H,int x ,int i);//插入元素
void DeleteList(linkp H,int i);//删除元素
void L1n_Ln1(linkp H);//倒置列表
void Josephu(linkp H,int n ,int k,int m); //约瑟夫环问题

#endif // LINKLIST_H_
linklist.c

//约瑟夫环问题
void Josephu(linkp H,int n,int k,int m){
    //首先我们需要先创建一个单向循环链表
    int i;
    linkp p,r;
    H = NULL;
    printf("排列之前的链表为:\n");
    for(i=1;i<=n;i++){ //建立一个循环链表
        p = (linkp)malloc(sizeof(linkNode));
        p->data = i;
        if(H==NULL){
            H = p;
            r = p;
        }else{
            r->next = p; //r结点代替头结点不停移动链接本表
            r=p;
        }
        printf("%d ",p->data);
    }
    p->next = H; //尾结点链接头结点,形成一个环
    p = H;
    printf("\n排列之后的链表为:\n");
    for(i=1;i<k;i++){//寻找第K个结点
        r = p;
        p = p->next;
    }
    while (p->next!=p){ //当结点数大于1时
       for(i=1;i<m;i++){//依次报数
        r = p;
        p = p->next;
    }
    r->next = p->next; //删除报数出的结点
    printf("%d ",p->data);//打印输出
    free(p); //释放删除的结点空间
    p = r->next; //从下一节点开始重新计数
    }
    printf("%d",p->data); //最后一个出列的数
    free(p);
}
main.c

/*
作者:张小五
时间:2018年1月29日

*/
#include "stdio.h"
#include "linklist.h"
#include "linklist.c"
int main(int argc,char *argv[]){
    linkp H;
    /*H =(linkp)malloc(sizeof(linkNode));
    H->next = NULL;
    CreateList(H);
    PrintList(H);*/
    /*int i;
    linkp temp;
    printf("请输入要查找的位置:");
    scanf("%d",&i);
    temp = GetList(H ,i-1);
    if(temp!=NULL){
        printf("你要查找的数值是%d\n",temp->data);
    }else{
        printf("你要查找的位置不存在!\n");
    }*/
    /*int x,i;
    printf("请输入要插入的数据和位置:\n");
    scanf("%d %d",&x,&i);
    InsertList(H,x,i-1);*/

    /*int i ;
    printf("请输入要删除的位置:");
    scanf("%d",&i);
    DeleteList(H,i-1);*/

    /*L1n_Ln1(H);
    PrintList(H);*/
    int n,k,m;
    printf("请依次输入排列的数据个数,开始的位置,间隔数量:\n");
    scanf("%d %d %d",&n,&k,&m);
    Josephu(H,n,k,m);


    return 0;
}
运行结果截图:


当然,这个问题还有很多其他的解决形式,比如说双向循环链表,在这里就不列出代码了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张小五丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值