重写约瑟夫回环(循环单链表)

问题描述

设有n个人围坐在圆桌周围,现从某个位置m(1≤m≤n)上的人开始报数,报数到k的人就站出来。下一个人,即原来的第k+1个位置上的人,又从1开始报数,再报数到k的人站出来。依此重复下去,直到全部的人都站出来为止。试设计一个程序求出出列序列。

思路

  • 子问题1:查找第一个报数为 k 的?

  • 子问题2:何时退出?

#ifndef JOSEPH_CLINKLIST_H
#define JOSEPH_CLINKLIST_H

// 循环链表
// 最后一个结点的指针指向头结点
// 
// 有时候可以设置尾指针,更方便表的连接操作
typedef struct Node
{
	int elem;
	struct Node * next;
}clinklist, *pclinklist;

pclinklist clinklist_create(int size);
void clinklist_insert(pclinklist list, int locate, int elem);
void clinklist_delete_location(pclinklist list, int locate);
void clinklist_delete(pclinklist list, pclinklist node);
void clinklist_display(pclinklist list);
pclinklist clinklist_find(pclinklist list, int location);
int clinklist_is_tail(pclinklist list, pclinklist node);
int clinklist_is_head(pclinklist head, pclinklist node);
int clinklist_is_empty(pclinklist list);
int clinklist_size(pclinklist list);
void clinklist_update_head(pclinklist list);

#endif
#include <stdio.h>
#include <stdlib.h>
#include "joseph.h"

int main() {
	int size = 0;
	int m = 0;
	int k = 0;

	pclinklist list = NULL;

	printf("输入人数 n :");
	scanf_s("%d", &size);

	if (size == 0)
		return -1;

	printf("输入报数起点 m :");
	scanf_s("%d", &m);

	if (m <= 0 || m > size)
		return -2;

	printf("输入报数到几退出 k :");
	scanf_s("%d", &k);

	// 极端情况考虑,k > n , k = n, k = 1
	if (k == 0)
		return -3;

	list = clinklist_create(size);
	clinklist_display(list);

	// 找到 m 点
	pclinklist node = clinklist_find(list, m - 1);
	printf("开始从 %d 报数\n", node->elem);

	int index = 1;
	while (!clinklist_is_empty(list))
	{
		if (index == k)
		{
			printf("第 %d 号选手遗憾出局\n", node->elem);
			pclinklist new_node = node->next;
			
			clinklist_delete(list, node);
			
			node = new_node;
			if (clinklist_is_head(list, node))
				node = node->next;
			index = 1;
		}
		else
		{
			node = node->next;
			if (clinklist_is_head(list, node))
				node = node->next;
			index++;
		}
	}
	return 0;
}

pclinklist clinklist_create(int size)
{
	pclinklist node, head;
	head = (pclinklist)malloc(sizeof(clinklist));

	// 头结点 elem 表示链表大小,头结点 next 指向第一个元素
	head->elem = size;
	head->next = NULL;

	node = head;

	for (int i = 0; i < size; i++)
	{
		node->next = (pclinklist)malloc(sizeof(clinklist));
		node = node->next;
		node->elem = i + 1;
		node->next = NULL;
	}
	node->next = head;

	return head;
}

void clinklist_display(pclinklist plist)
{
	pclinklist head = plist;
	pclinklist node = head->next;
	while (1)
	{
		if (clinklist_is_head(head, node))
			break;

		printf("%d\t", node->elem);
		node = node->next;
	}
	printf("\n");
}

void clinklist_insert(pclinklist plist, int location, int elem)
{
	pclinklist head = plist;
	pclinklist inode = NULL;
	int size = clinklist_size(plist);

	if (location < 0 || location > size)
		return;

	inode = (pclinklist)malloc(sizeof(clinklist));
	inode->elem = elem;

	if (location == 0)
	{
		inode->next = head->next;
		head->next = inode;
	}
	else
	{
		pclinklist node = clinklist_find(plist, location - 1);
		pclinklist next = node->next;
		node->next = inode;
		inode->next = next;
	}
	clinklist_update_head(head);
}

void clinklist_delete_location(pclinklist plist, int location)
{
	pclinklist head = plist;
	int size = clinklist_size(plist);

	if (location < 0 || location >= size)
		return;

	if (location == 0)
	{
		pclinklist dnode = head->next;
		head->next = dnode->next;
		free(dnode);
	}
	else
	{
		pclinklist node = clinklist_find(plist, location - 1);
		pclinklist dnode = node->next;
		node->next = dnode->next;
		free(dnode);
	}
	clinklist_update_head(head);
}

void clinklist_delete(pclinklist plist, pclinklist node)
{
	pclinklist prior = plist;

	do
	{
		if (node == prior->next)
		{
			prior->next = node->next;
			free(node);
			break;
		}
		prior = prior->next;
	} while (!clinklist_is_head(plist, prior));

	clinklist_update_head(plist);
}

pclinklist clinklist_find(pclinklist list, int location)
{
	pclinklist head = list;
	pclinklist node = head->next;

	if (location == 0)
		return node;
	else
	{
		while (location != 0)
		{
			if (clinklist_is_head(head, node)) break;

			node = node->next;
			location--;
		}

		if (location != 0)
			return NULL;

		return node;
	}
}

int clinklist_is_tail(pclinklist head, pclinklist node)
{
	return (clinklist_is_empty(head) || node->next == head) ? 1 : 0;
}

int clinklist_is_head(pclinklist head, pclinklist node)
{
	return (head == node) ? 1 : 0;
}

int clinklist_is_empty(pclinklist list)
{
	return list == list->next;
}

int clinklist_size(pclinklist list)
{
	return list->elem;
}

void clinklist_update_head(pclinklist list)
{
	pclinklist head = list;
	pclinklist node = head->next;
	int size = 0;
	while (node != head)
	{
		size++;
		node = node->next;
	}
	head->elem = size;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值