一、问题描述
有15个人围成一圈,顺序从1到15编号。从第一个人开始报数,凡报到n的人退出圈子。用C语言写出程序,输入n(n>1)的值,输出最后留在圈子里的人的编号。
二、算法描述
void main( )
{
构建顺序表 L
把1-15这15个数逐个插入到 L 的尾部
输入n
While(顺序表 L 中元素多于一个)
{
for(i=1;i<n;i++)
{
取 L[0] 放到L的尾部;
删除L[0]
}
输出L[0]
删除 L[0];
}
输出L[0]
}
三、实现
#include<vector>
#include<iostream>
using namespace std;
void print(vector<int> &L)
{
if(L.size()==0)
{
cout<<"No data\n";
return;
}
int i;
for(i=0;i<L.size();i++)
{
cout<<L[i]<<" ";
}
cout<<endl;
}
int main( )
{
vector<int> L;
int i,n;
for(i=1;i<16;i++)
{
L.push_back(i);
}
//cin>>n;
n=3;
while(L.size()>1)
{
for(i=1;i<n;i++)
{
L.push_back(L[0]);
L.erase(L.begin());
}
cout<<L[0]<<" ";
L.erase(L.begin());
}
cout<<endl;
cout<<"最后剩余的是:";
cout<<L[0]<<" "<<endl;
return 0;
}
四、效率分析
这是一个双重循环,假设开始时有m个人
外层第 1 次循环时,插入尾部n-1次,删除头部n次。删除头部时,每次需要移动m-1次,则共移动n*(m-1)次;
外层第 2 次循环时,插入尾部n-1次,删除头部n次。删除头部时,每次需要移动m-1-1次,则共移动n*(m-1-1)次;
...
外层第 m-1 次循环时,剩余2个元素,插入尾部n-1次,删除头部n次。删除头部时,每次需要移动1次,则共移动n*1次;
综上,需要移动:n*[1+2+3+...+(m-1)]=n*m*(m-1)/2次。
所以,改算法的时间复杂度还是比较高的,主要在删除L[0]时,移动得比较频繁造成的。
怎样改进算法呢?
1、数到n的才删除;
2、用链表实现!!
我们在后续博客实现。