您的位置:首页 > 理论基础 > 数据结构算法

关于约瑟夫环用list实现遇到的奇怪问题

2012-11-30 15:34 519 查看


该问题是在Weiss著的《数据结构与算法分析(C++描述+第三版)习题中的3.6题遇到的

先把自己遇到问题的代码粘出来,本人的编译环境是windows7下的g++ (GCC) 4.6.1
#include<iostream>
#include<list>
using namespace std;

int main()
{
int n=0,m=0,i=0;
cout<<"please input the number of player : "<<endl;
cin>>n;
cout<<"please input the times of transfer"<<endl;
cin>>m;
list<int> aa;
for(i=0;i<n;i++)
aa.push_back(i+1);
list<int>::iterator itr=aa.begin();
while(aa.size()>1)
{
for(i=0;i<m;i++)
{
if(itr==aa.end())
itr=aa.begin();
cout<<*itr++<<endl;
cout<<*itr<<endl;
}
cout<<*itr<<" player game over!"<<endl;
itr=aa.erase(itr);
}
return 0;
}
先试一种简单的情况,输入n=5,m=1
please input the number of player :

5

please input the times of transfer

1

1

2

2 player game over!

3

4

4 player game over!

5

1

1 player game over!

到此处程序就挂掉了,根据上面的输出,刚开始分析以为第三次进入while后
itr已经指向的值是5,进入for语句cout<<*itr++<<endl;输出itr指向5后自加一次,
然后cout<<*itr<<endl;输入itr指向1,认为itr在最后一个元素做自加运算会自动指向list的第一个位置,按此思路,程序继续往下走把cout<<*itr<<" player game over!"<<endl;打出来,接下来调用erase方法删除第一个元素,把返回值即下一个元素的迭代器给itr,看似没有问题但程序却挂那儿不走了
下面给出找出问题后正确的代码
#include<iostream>
#include<list>
using namespace std;

int main()
{
int n=0,m=0,i=0;
cout<<"please input the number of player : "<<endl;
cin>>n;
cout<<"please input the times of transfer"<<endl;
cin>>m;
list<int> aa;
for(i=0;i<n;i++)
aa.push_back(i+1);
list<int>::iterator itr=aa.begin();
//	cout<<*aa.begin()<<" "<<*aa.end()<<endl;
while(aa.size()>1)
{
for(i=0;i<m%n;i++)
{
if(itr==aa.end())
itr=aa.begin();
//			cout<<*itr<<endl;
itr++;
//			cout<<*itr<<endl;
if(itr==aa.end())
itr=aa.begin();
}
cout<<*itr<<" player game over!"<<endl;
itr=aa.erase(itr);
n--;
if(itr==aa.end())
itr=aa.begin();
}
cout<<*aa.begin()<<" player win the game!"<<endl;
return 0;
}


输入同上,输出的结果如下

please input the number of player :

5

please input the times of transfer

1

1 1

1

2

2 player game over!

3

4

4 player game over!

5

1

1 player game over!

3

5

5 player game over!

3 player win the game!

问题其实出在迭代器指向最后一个元素时,做自加运算后itr实际是指向了end标记,
那为什么上面出问题的情形下cout<<*itr<<endl;输出了1呢,难道是巧合吗???
这个我也不知道是不是巧合还是C++标准里有什么特殊的规定,输出的1其实是list中end标记指向的值,
原因可以见cout<<*aa.begin()<<" "<<*aa.end()<<endl;的输出值 1 1
所以当接下来调用erase方法删除end当然就出错了
总结:一些需要做循环操作的程序中,在自加运算前后都要判断迭代器是否指向end,
是的话手动让它指向begin。
本人刚学数据结构和算法,不知道这问题是不是很二,大牛轻拍哈
有兴趣的童鞋可以研究一下迭代器end指向的值是不是都是1或者end指向的值是怎么规定的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Algorithm C++ 数据结构