线性表作业
一、约瑟夫问题
1.1 作业题
问题描述:n 个人围成一个圆圈,从第s个人开始顺时针报数, 报到m 的人出列。然后再从下一 个人开始,从 1 顺时针报数,报到m 的人出列,…,如此下去直到这些人全部出列。
用到:单向循环链表。
代码如下:
#include <iostream>
using namespace std;
struct Node {
int data;
Node *link;
Node (int d=0,Node *next=NULL ):data(d), link(next) { };
};
class Josephus {
private:
Node *first;//循环链表的头节点
int n; //链表节点个数
int s; //第一个报数人的序号
int m; //报数出局的数
public:
void createList();
void outputList();
Josephus(int N, int S, int M):n(N),s(S),m(M)
{
createList();
outputList();
}
};
void Josephus::createList()
{
Node *pre = NULL;
Node *cur = NULL;
Node *p = new Node(1);
first = p;
cur = p;
for (int i=2; i<=n; i++)
{
p = new Node(i);
pre = cur;
cur = p;
pre->link = cur;
}
cur->link = first;
}
void Josephus::outputList()
{
Node *pre = NULL;
Node *cur = first;
s--;
while (s--) //寻找第K个人(开始报数的人)
{
pre = cur;
cur = cur->link;
}
while (n--) //输出链表中所有的结点值
{
int y = m-1;
while (y--) //寻找报m的人
{
pre = cur;
cur = cur->link;
}
Node *p = cur;
cout << p->data << ",";
cur = cur->link; //删除节点的过程
pre->link = cur;
delete p;
p=NULL;
}
}
int main()
{
int n,s,m;
cout<<"请输入n、s、m:" <<endl;
cin>>n>>s>>m;
cout<<"出局顺序:"<<endl;
Josephus clist(n,s,m);
return 0;
}
1.2 相似问题其一
问题描述:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡是报到3的人退出圈子,问最后留下的是原来的几号。
用到:数组。
以下是书上给出的代码:不过我没能运行成功。原因:杀毒软件说它是病毒然后给我拦截了。😂
#include<iostream>
#define nmax 50
using namespace std;
int main()
{
int i,k,m,n,num[nmax],*p;
cout<<"please input the total of numbers:";
cin>>n;
p=num;
for(i=0;i<n;i++)
*(p+i)=i+1;
i=0;//累计参与游戏的人员位置
k=0;//累计报数值
m=0;//累计退出的人数
while(m<n-1)
{
if(*(p+i)!=0)k++;
if(k==3)
{
*(p+i)=0;
k=0;//报数值回归0
m++;//累加退出的人数
}
i++;
if(i==n)i=0; //当到达最后一个人时赋值回到0,保证形成环状
}
while(*p==0)p++;
cout<<*p<<"is left"<<endl;
return 0;
}
/*运行结果如下:
please input the total of numbers:23
8 is left*/
1.3 相似问题其二
问题描述:n个人轮流报数,报到number的人出局,剩下的成环继续轮流报数,问最后剩下的是谁?(设此处n=12,number=3)
用到:Vector类的函数:
push back() 在向量尾部加入一个元素
at() 获取对应索引的元素(也可使用 [] 访问)
size() 获取当前vector内的元素个数
begin() 返回向量头的迭代器
erase() 删除对应迭代器对应的元素
删除当前向量中的第i个元素写法为: erase(v.begin()+i )
迭代器此处不深入讲解,知道如何删除第1个元素即可。
分析:
n个人——向量初始容量为n
vector<int> v;//创建一个向量容器
const int n=12;
const int number=3;
number——每次跳跃距离
//设i是计算好的下标
//可以准确地删除已出局的人
v.erase(v.begin()+i);
剩下的成环——取余成环
i=(i+number-1)%v.size();
代码如下(来自本校某大佬)
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;//创建一个向量容器
const int n=12;
const int number=3;
for(int i=1;i<=n;i++){
v.push_back(i);//循环初始,给玩家编号
}
int i=0;
while(v.size()!=1) {//当只剩下一个人的时候结束
i=(i+number-1)%v.size();//取余成环,计算下一个出局的人的位置
v.erase(v.begin()+i);//剔除出局的人
}
cout<<v[0]<<endl;//获得最后一个人
return 0;
}
二、单向链表逆序
问题描述:设有一个表头指针为h的单链表。试设计一个算法,通过遍历一趟链表,将链表中所有结点的链接方向逆转。要求逆转结果链表的表头指针h指向原链表的最后一个结点。
用到:单向链表
代码如下:
#include <iostream>
using namespace std;
struct List
{
int data;
List *next;
};
List* createList(int n) //创建含有n个节点的单链表
{
List *head, *p, *cur;
cur=head = NULL; //初始化表头和中间指针
int i;
for (i = n; i > 0; --i)
{
p = new List; //申请空间,创建第一个节点
cin >> p->data; //往节点中存入数据信息
if (head == NULL)
{
head = p;
}
else
{
cur->next = p;
}
cur = p;
}
cur->next = NULL;
return head;
}
List *ReverseList(List *head) //逆置单链表
{
List *p, *r; //定义两个中间节点,用于顺移逆置链表节点
if (head->next == NULL)
return head;
p = head; //获取头节点地址
r = p->next; //获取链表第二个节点地址
p->next = NULL; //头节点变为尾节点,原链表表头指向空
while (r)
{
p = r;
r = r->next;
p ->next = head; //使第二个节点指向原先的头节点
head = p; //使第二个节点变为头节点,用于循环逆置
}
return head;
}
void print(List *head) //输出逆置后的单链表
{
List *p;
p = head;
while (p)
{
cout<<p->data;
p = p->next;
cout << " ";
}
cout << endl;
}
int main()
{
List *p, *q;
cout << "请输入单链表的节点个数:";
int n;
cin >> n;
cout << endl;
cout << "创建一个节点为" << n << "的单链表" << endl;
p = createList(n);
cout << endl;
cout << "这步为程序逆置单链表" << endl;
q = ReverseList(p);
cout << endl;
cout << "打印逆置后的单链表" << endl;
print(q);
cout << endl;
return 0;
}
/*说明:
输入要求:先输入要创建的节点个数。再分别输入各节点的数据域。
输出:逆序后的各节点的数据域。*/