每日一题14:数组与链表组合方案下的Josephus问题
2015-04-04 09:38
344 查看
愚人节快乐!几天没写程序,今天继续!Josephus问题是说N个人围成一个圈传热土豆,先约定一个数M,当传递了M次的时候拿着土豆的人出局,然后将土豆给出局人的下一个人,游戏继续,直到最后只剩下一个人,求出局人的序列(按出局顺序排列)。
这个问题可以用数组实现,但是需要标记代表出局人的元素,并且没遍历一个元素就要检查该元素是否已被标记为出局,这样程序运行时间必然会变慢。另一种方式是使用一个链表,每次把出局的节点删除掉。这样的解决方案非常直观,只需要关注链表中的节点,因为在链表中的节点就是没有出局的。删除节点只是指针的调整,非常迅速,但是释放删除的节点占用的空间会比较费时,当输入N很大时会占用大量的时间。所以采用一种链表与数组结合的方式,可以克服两种方式的缺点。
结合的方式就是把链表放在一个数组中!初始时,每个元素的next指针指向数组的下一个元素,最后一个指向第一个(我们需要的是一个循环链表)。这样我们就可以实现在数组中跳跃性的访问而不必关心访问的节点是否是被标记为出局,最后只要一次性释放掉数组所占用的空间就好了,不用管链表节点的释放!
程序中losers数组的最后一个元素保存的是最后胜利的人,之前才是出局人序列。
生活中许多事情也像写程序,哪里不会出点bug呢,但是bug总会被修复的不是吗?
这个问题可以用数组实现,但是需要标记代表出局人的元素,并且没遍历一个元素就要检查该元素是否已被标记为出局,这样程序运行时间必然会变慢。另一种方式是使用一个链表,每次把出局的节点删除掉。这样的解决方案非常直观,只需要关注链表中的节点,因为在链表中的节点就是没有出局的。删除节点只是指针的调整,非常迅速,但是释放删除的节点占用的空间会比较费时,当输入N很大时会占用大量的时间。所以采用一种链表与数组结合的方式,可以克服两种方式的缺点。
结合的方式就是把链表放在一个数组中!初始时,每个元素的next指针指向数组的下一个元素,最后一个指向第一个(我们需要的是一个循环链表)。这样我们就可以实现在数组中跳跃性的访问而不必关心访问的节点是否是被标记为出局,最后只要一次性释放掉数组所占用的空间就好了,不用管链表节点的释放!
[code]#include "stdafx.h" #include <iostream> using namespace std; struct person { int id; person* next; }; struct person_list { int count; person* first; person* last; }; person_list* init(int n) { person* p = new person ; for (int i = 0; i < n - 1; ++i) { p[i].id = i + 1; p[i].next = &p[i+1]; } p[n - 1].id = n; p[n - 1].next = &p[0]; person_list* persons = new person_list; persons->count = n; persons->first = p; persons->last = &p[n - 1]; return persons; } int* solve(int n,int m) { if(n < 1 || m < 0) return NULL; person_list* persons = init(n); person* first = persons->first; person* t = first; int count = persons->count; int *losers = new int ; int j = 0; while(count > 1) { person* q = NULL; for (int i = 0; i < m; ++i) { q = first; first = first->next; } if(first == persons->first) { persons->first = first->next; persons->last = persons->first; } else if(first == persons->last) { q->next = first->next; persons->last = q; } else { q->next = first->next; } --count; losers[j++] = first->id; first = first->next; } losers[j] = persons->first->id; delete []t; delete persons; return losers; } int _tmain(int argc, _TCHAR* argv[]) { int n = 5, m = 1; int* losers = solve(n,m); for (int i = 0; i < n; ++i) { cout<<losers[i]<<' '; } cout<<endl; delete[]losers; return 0; }
程序中losers数组的最后一个元素保存的是最后胜利的人,之前才是出局人序列。
生活中许多事情也像写程序,哪里不会出点bug呢,但是bug总会被修复的不是吗?
相关文章推荐
- 利用数组模拟的链表解决Josephus问题
- 使用数组的方法,解决Josephus问题
- 用数组求解Josephus问题
- .NET:关于byte数组在用StreamWriter文件写出后出现多余字符的解决方法及VS方案文件图标显示问题
- Josephus(约瑟夫)问题----分别用循环链表和数组实现
- 分别用 数组和链表处理约瑟夫环问题
- Q14 密码问题 字符数组初始化memset
- 约瑟夫环问题(不带头结点单循环链表实现和数组实现)
- 院版每日一题(2) 数组乘积问题
- Josephu 问题:数组实现和链表实现
- 约瑟夫问题(Josephus问题)的递推O(n)解法、循环解法、单循环链表解法
- Josephu 问题解决策略:数组与链表的融合,十倍速度的差距(百万级数据)
- Josephus问题的链表实现
- 链表形式的josephus问题
- 从n个数组中任意选取一个元素的所有组合的Java实现(组合问题)
- 关于任一数组的组合问题
- 数据结构之链表与数组(二) -单向链表上的简单操作问题
- 【每日面试题】链表相关问题2
- 关于动态存储分配函数的调用,在已经过排序的数组中查找及删除内容的操作,余数的分析,删除字符数组中的空格,对链表的逆置,在源字符串中查找子字符串的个数,函数指针以及函数的调用,循环赋值带来的问题以及插入
- 每日编程14之取单链表中间元素