线性表应用(约瑟夫环问题)

问题描述:  
  设有n个人围坐在圆桌周围,现从某个位m(1<=m<=n)上的人开始报数,报数到k的人就站出来。下一个人,即原来的第k+1位置上的人又从1开始报数,再报数到k的人站出来。依此重复下去,直到全部的人都站出来为止。输出这个序列。

经典的使用循环链表问题



算法分析:
  1.圆桌可以使用单循环链表来实现,出列就相当于在链表中删除元素。
  2.首先程序需要两个函数①创建一个不带头结点的循环链表(模拟圆桌)②另一个函数实现出列操作

存储示意图:
存储示意图:
  每次找出需要出列的结点,要经过k次循环移动指针。全部结点出列需要经过n个k次循环。



参考代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define OVERFLOW -1

typedef int Elemtype;    //定义数据元素类型

typedef struct Cnode     //结点类型定义
{
	Elemtype data;
	struct Cnode *next;
}CNode;

CNode *joseph;             //定义全局变量

//创建单循环链表
int Creat_list(CNode *clist, int n)
{
	CNode *p=NULL;
	CNode *q=NULL;
	int i;
	clist = NULL;
	for (i = n; i >= 1; i--)
	{
		p = (CNode *)malloc(sizeof(CNode));
		if (p == NULL)
		{
			return OVERFLOW;    //存储分配失败
		}
		p->data = i;              //赋值
		p->next = clist;
		clist = p;
		if (i == n)
			q = p;             //q指向尾部
	}
		q->next = clist;         //尾部和头部连接起来建立循环链表
		joseph = clist;          //将创建好的循环链表头指针赋给全局变量
		return 1;
}

//寻找指定元素输出
int Joseph(CNode *clist, int m, int n, int k)
{
	int i;
	CNode *p, *q;
	if (m > n)                 //起始位置不对
	{
		return -1;
	}
	if (!Creat_list(clist, n))
	{
		return -1;           //链表创建失败
	}
	p = joseph;               //p指向创建好的循环链表
	for (i = 1; i < m; i++)
	{
		p = p->next;                   //*p指向m位置的结点
	}
	while (p)
	{
		for (i = 1; i < k - 1; i++)    //找到要输出结点的前一个结点
			p = p->next;
		q = p->next;                    //q指向要输出的结点
		printf(" %d", q->data);
		if (p->next == p)
		{
			p = NULL;                  //删除最后一个结点
		}
		else
		{
			p->next = q->next;          
			p = p->next;                 
			free(q);
		}
	}
	clist = NULL;
	return 1;
}

void main()
{
	int m = 0;
	int n = 0;
	int k = 0;
	CNode *clist;
	clist = NULL;                    //初始化clist
	printf("请输入圆桌总人数:", n);
	scanf("%d", &n);
	printf("请输入首次开始报数的位置:", m);
	scanf("%d", &m);
	printf("第几个人出列?", k);
	scanf("%d", &k);
	Creat_list(clist, n);
	printf("输出序列如下:\n");
	Joseph(clist, m, n, k);
	printf("\n");
	system("pause");

}

测试结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值