数据结构考研复习--线性表3(约瑟夫环)
2015-10-17 16:48
253 查看
约瑟夫环这个在一开始看的时候是一个相当蛋疼的问题,本节将为大家讲述约约瑟夫环利用循环链表以及递归来进行求解
**约瑟夫环问题的原来描述为,设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。 稍微简化一下。
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
思路:容易想到的就是用环链表来做,构建一个环链表,每个结点的编号为0, 1, …… n-1。每次从当前位置向前移动m-1步,然后删除这个结点。最后剩下的结点就是胜利者。**
我们先来非递归的算法
这样的效率显然不是最高的,时间复杂度o(mn),
接下来看递归算法
公里公道的说,这个递归算法真不好想。
我们先反过来想,如果只有一个人,那么他一定就是我们要求的,如果有两个人,那么他一定跟如果只有一个人的那种情况有关,通过只有一个人我们一定会得到一些线索,同理,我们算n个人的约瑟夫环,必然跟n-1个人的约瑟夫环有关,……一定跟2个人的有关,一定跟一个人的有关。那么到底有什么规律呢?这是我们即将要讨论的问题
我们假设m = 8 , n = 3
1>>很显然第一个被删除的数是(m-1)%n
2>>假设第二轮开始的数是K,那么只有n-1个人
那么我就知道,这n-1个人,如果说我们现在知道了胜利者,他的编号是X,那么说他在链表中一开始是(k+x)%n,
其中, k = m%n,带入式子我们知道其实对于n个人,胜利者的编号是(X+m)%n
还记得我们的X是什么吗???—>n-1个人时的胜利者
那么简而言之,要求n个人最终的胜利者,我们只需要知道n-1个人时候的情况就行了,同理要知道n-1个人必须先求出n-2个人………..必须先求出1个人的情况,一个人编号自然是0,转化成代码就是
**约瑟夫环问题的原来描述为,设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。 稍微简化一下。
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
思路:容易想到的就是用环链表来做,构建一个环链表,每个结点的编号为0, 1, …… n-1。每次从当前位置向前移动m-1步,然后删除这个结点。最后剩下的结点就是胜利者。**
我们先来非递归的算法
void JosephusProblem_Solution1(int n, int m) //n个人,每m退出 { int i = 0; LinkList *pm; LinkList *pcur; LinkList *head = (LinkList *)malloc(sizeof(LinkList)); LinkList *plast; pcur = head; pcur->next = head; head->data = 0; //构造循环链表 for (i = 1; i <10;i++) { pm = (LinkList *)malloc(sizeof(LinkList)); pm->data = i; pcur->next = pm; pcur = pm; } pcur->next = head; //over pcur = head; while(pcur != pcur->next) { //前进m-1步 for (i = 0;i<m-1;i++) { plast = pcur; pcur = pcur->next; } //删除 plast->next = pcur->next; free(pcur); pcur = plast->next; } printf("%d ",pcur->next->data); }
这样的效率显然不是最高的,时间复杂度o(mn),
接下来看递归算法
公里公道的说,这个递归算法真不好想。
我们先反过来想,如果只有一个人,那么他一定就是我们要求的,如果有两个人,那么他一定跟如果只有一个人的那种情况有关,通过只有一个人我们一定会得到一些线索,同理,我们算n个人的约瑟夫环,必然跟n-1个人的约瑟夫环有关,……一定跟2个人的有关,一定跟一个人的有关。那么到底有什么规律呢?这是我们即将要讨论的问题
我们假设m = 8 , n = 3
1>>很显然第一个被删除的数是(m-1)%n
2>>假设第二轮开始的数是K,那么只有n-1个人
K -------> 0 K+1------> 1 K+2------> 2 //假设最终他是胜利者 ... k-2-----> n-2
那么我就知道,这n-1个人,如果说我们现在知道了胜利者,他的编号是X,那么说他在链表中一开始是(k+x)%n,
其中, k = m%n,带入式子我们知道其实对于n个人,胜利者的编号是(X+m)%n
还记得我们的X是什么吗???—>n-1个人时的胜利者
那么简而言之,要求n个人最终的胜利者,我们只需要知道n-1个人时候的情况就行了,同理要知道n-1个人必须先求出n-2个人………..必须先求出1个人的情况,一个人编号自然是0,转化成代码就是
fun(1) = 0; fun(n) = ( fun(n-1) + m ) %n;
int JosephusProblem_Solution2(int n, int m ) { if (n==1) { return 0; } return (JosephusProblem_Solution2(n-1, m) + m) % n; }
相关文章推荐
- 数据结构考研复习--线性表2
- 数据结构与算法(选择性插入排序)
- 数据结构考研复习--线性表1
- 1.数据结构和算法的基础笔记
- SDUT 数据结构实验之栈六:下一较大值(二)
- 数据结构与算法是什么
- 数据结构考试
- THU数据结构编程作业一:列车调度(Train)
- Language of FatMouse(trie树)
- Python基本数据结构 习题及源码
- 数据结构基础7_链队的实现
- 数据结构之链表(链接)
- 堆排序
- 数据结构实验之栈六:下一较大值(二)【OJ-3333】【自己写的封装的栈代码】
- hbase系统架构及数据结构
- 【数据结构与算法分析】1.1 找出N个数字中第K大的数
- 数据结构栈应用之进制转换
- What Are You Talking About(trie树或map)
- opencv学习笔记(十三)——数据结构
- 数据结构c字符串操作语言版本