• 约瑟夫环问题(报数问题)


    先说一下什么是约瑟夫环问题,这是百科的解释:

    约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。


    思路:

    因为n个人不定,所以采用链表。因为是连续报数的,所以是用循环链表。每数到m,那个m号的人就删除掉,然后从他身后一位重新开始,再数到m,再删除,一直这样。怎么样才能停止呢?就是当一开始的队伍没人的时候。就是一开始按顺序建立一个有顺序的链表1~n,再根据m删除,删除掉的人又重新组成一个链表,这就是出局的顺序。怎么根据m来删除呢?当从1号开始数,经过m-1个人就是要删除的那位。就是2,3,...m-1。再从m-1的后一位开始当作1,再经过m-1个人这样重复。

    下面我给出我写的代码:

    /* 关于我写的函数说明一下
     * head,root变量分别代表一开始按顺序的队伍和出局顺序的队伍
     * 插入函数中因为两个表的形成方式不同所以插入方式有所不同
     * 销毁函数也是一样
     * 约瑟夫问题的解决主要体现是在删除函数上
     */
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node
    {
    	int		num;
    	struct Node	*next;
    }Node;
    
    
    /* 初始化链表 */
    int InitList(Node **head, int n);
    
    /* 添加至链表,要做成循环链表 */
    int InsertList(Node *head, int n, int flag);	/* flag代表不同插入方式 */
    
    /* 删除 */
    int DeleteList(Node *head, Node *root, int m);
    
    /* 输出链表 */
    int DisplayList(Node *head);
    
    /* 销毁链表 */
    int DestroyList(Node *head, int flag);		/* 代表不同销毁方式 */
    
    /* 转置函数 */
    int Transpose(Node *head);
    
    int main(void)
    {
    	Node	*head = NULL;	/* 一开始存储按顺序的队伍 */
    	Node	*root = NULL;	/* 最后退出顺序的队伍 */
    	int	m = 0;		/* 指定退出的号码 */
    	int	n = 0;		/* 游戏的人数 */
    	int	flag = 0;	/* 用来表示在插入函数时0代表head, 1代表root */
    	printf("请输入人数和退出的号码:
    ");
    	scanf("%d %d", &n, &m);
    
    	/* 初始化 */
    	InitList(&head, n);	/* 这个是一开始按顺序派对的队伍 */
    	InitList(&root, n);	/* 这个是到最后储存退出顺序的队伍 */
    	
    	/* 添加 */
    	InsertList(head, n, flag);
    	
    	/* 输出 */
    	printf("按顺序排队:
    ");
    	DisplayList(head);
    
    	/* 根据指定的号码m来删除 */
    	DeleteList(head, root, m);
    	Transpose(root);		/* 因为在删除函数中以头插法生成,所以需要倒置 */
    
    	/* 输出 */
    	printf("退出完毕!现在输出游戏退出顺序:
    ");
    	DisplayList(root);
    	
    	/* 销毁链表 */
    	DestroyList(head, flag);
    	flag = 1;
    	DestroyList(root, flag);
    
    	return 0;
    }
    
    /* 初始化链表 */
    int InitList(Node **head, int n)
    {
    	(*head) = (Node *)malloc(sizeof(Node));
    	(*head)->num = n;		/* 头结点的num变量就储存人数n */
    	(*head)->next = NULL;
    	return 1;
    }
    
    /* 添加至链表,要做成循环链表 */
    int InsertList(Node *head, int n, int flag)
    {
    	Node	*rear = head;
    	Node	*current = head;
    	Node	*new = NULL;
    	int	i = 0;
    
    	/* 这是head的插入方式,尾插法 */
    	if (flag == 0)
    	{
    	for (i = 1; i <= n; i++)
    	{
    		new = (Node *)malloc(sizeof(Node));
    
    		if (new == NULL)
    		{
    			perror("Malloc error");
    			exit(1);
    		}
    		else
    		{
    			new->num = i;
    			rear->next = new;
    			rear = new;
    		}
    		rear->next = NULL;
    	}
    	rear->next = head->next;	/* 形成循环链表 */
    	}
    	/* 这是root的插入方式,头插法,可以不用循环链表,因为游戏已经结束 */
    	else
    	{
    		new = (Node *)malloc(sizeof(Node));
    
    		if (new == NULL)
    		{
    			perror("Malloc error");
    			exit(1);
    		}
    		else
    		{
    			new->num = n;
    			new->next = current->next;
    			current->next = new;
    		}
    	}
    
    return 1;
    }
    
    /* 删除 */
    int DeleteList(Node *head, Node *root, int m)
    {
    	Node	*current = head->next;
    	Node	*previous = NULL;
    	int	i = 0;
    	int	count = head->num;
    	int	flag = 1;
    
    	while (count != 0)	/* 此时队伍没人,就退出 */	
    	{
    		while (1)
    		{
    
    			/* 经过m-1个之后current指针就会指向要退出的元素 */
    			if (i == m-1)
    			{
    				i = 0;	/* 重新开始计数 */
    				break;
    			}
    
    			previous = current;
    			current = current->next;
    			i++;
    			
    		}
    		previous->next = current->next;			/* 删除元素 */
    		InsertList(root, current->num, flag);		/* 将删除出来的元素添加至新的链表中 */
    		free(current);
    		count--;					/* 每free一次就减少一个人 */
    		current = previous->next;			/* 从被删掉元素的后一位重新开始 */
    	}
    	return 1;
    }
    
    /* 输出链表 */
    int DisplayList(Node *head)
    {
    	Node	*current = head->next;
    	int	count = head->num;	
    	int	i = 1;
    	
    	while (1)
    	{
    		if (i != count)
    			printf("%d->", current->num);
    		else
    		{
    			printf("%d
    ", current->num);
    			break;
    		}
    			current = current->next;
    		i++;	
    	}
    
    	return 1;
    }
    
    /* 销毁链表 */
    int DestroyList(Node *head, int flag)
    {
    	
    	Node	*current = head;
    	Node	*previous = NULL;
    	int	count = head->num;	
    	int	i = 1;
    	
    	if(flag == 0)
    		free(head);
    	else
    	while (current != NULL)
    	{
    		previous = current;
    		current = current->next;
    		free(previous);
    	}
    	return 1;
    }
    
    /* 转置函数 */
    int Transpose(Node *head)
    {
    	Node *p1, *p2, *p3 = NULL;
    	p1 = head->next;
    	p2 = p1->next;
    
    	while (p2 != NULL)
    	{
    		p3 = p2->next;
    		p2->next = p1;
    		p1 = p2;
    		p2 = p3;
    	}
    	head->next->next = NULL;
    	head->next = p1;
    
    	return 1;
    }

    现在给出程序运行的结果:



    因为是新手,所以不懂得怎么优化代码,请多多包含。

  • 相关阅读:
    WPF 依赖属性
    WPF 利用附加属性创建FreezableCollection集合和反射实现控件参数以MVVM模式传递
    VS Code 使用插件让HTML和JS代码运行在火狐浏览器
    WPF 键盘导航附加属性解决TreeView的Tab导航焦点问题
    WPF 透视相机的UpDirection(向上方向)
    ABP框架——集成Mysql
    CentOS7部署.Net Core2.0站点(中)
    CentOS7部署.Net Core2.0站点(上)
    (转)非常完善的Log4net详细说明
    GitHub for Windows提交失败“failed to sync this branch”
  • 原文地址:https://www.cnblogs.com/fusae-blog/p/4256792.html
Copyright © 2020-2023  润新知