线性表作业

一、约瑟夫问题

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-1
参考链接1-2(百度百科)

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;
}
/*说明:
输入要求:先输入要创建的节点个数。再分别输入各节点的数据域。
输出:逆序后的各节点的数据域。*/

参考链接2-1
参考链接2-2

posted @ 2020-05-04 00:03  繁辰一梦  阅读(279)  评论(0)    收藏  举报