0
点赞
收藏
分享

微信扫一扫

【数据结构】实验四:循环链表

司马吹风 2023-07-30 阅读 48

实验四  循环链表

一、实验目的与要求

1)熟悉循环链表的类型定义和基本操作;

2灵活应用循环链表解决具体应用问题。

二、实验内容

题目一:有n个小孩围成一圈,给他们从1开始依次编号,从编号为1的小孩开始报数,数到第m个小孩出列,然后从出列的下一个小孩开始重新报数,数到第m个小孩又出列,……如此反复直到所有的小孩全部出列为止,求整个出列序列,例如:当n=6,m=5 时的出列序列是5,4,6,2,3,1 . 

题目二:围绕着山顶有10个洞,一只狐狸和一只兔子住在各自的洞里。狐狸想吃掉兔子。一天,兔子对狐狸说:“你想吃我有一个条件,先把洞从110编上号,你从10号洞出发,先到1号洞找我;第二次隔1个洞找我,第三次隔2个洞找我(第一次看1号洞,第二次看3号洞,第三次看6号洞),以后依次类推,次数不限,若能找到我,你就可以饱餐一顿。不过在没有找到我以前不能停下来。”狐狸满口答应,就开始找了。它从早到晚进了100次洞,也没找到兔子,请问,兔子可能躲在几号洞里,打印输出所有安全洞的编号。(使用一个循环单链表解决问题)

三、实验结果

1)请将调试通过的源代码粘贴在下面。(代码注意书写规范、主要模块要有功能注释)

题目一源代码:

#include <cstdio>
#include <malloc.h>
#include <iostream>
using namespace std;

typedef struct node{
	int no;//小孩编号
	struct node *next;		
}child;

//创建无头结点
void createlist(child *&head, int n){
	int i;
	child *p,*tail;//指向新建循环单链表的尾结点
	head=(child*)malloc(sizeof(child));
	head->no=1;//建立no为1结点的单链表
	tail=head;
	for(i=2;i<=n;i++){
		p=(child*)malloc(sizeof(child));
		p->no=i;//建立一个存放编号i的结点
		tail->next=p;
		tail=p;//将p结点链到末尾
	}
	tail->next=head;//构成一个首结点为head的循环单链表
}

//求出列顺序(约瑟夫问题) 
void joseph(int n,int m){
	//n->总数 m->出列数 
	int i,j; 
	child *head,*p,*q;
	createlist(head,n);//初始化列表 
	
	//出列n个小孩
	for(i=1;i<=n;i++){
		p=head; 
		j=1;
		//从head结点开始报数,报到第m-1个结点
		while(j<m-1){
			j++;//报数递增
			p=p->next;//移到下一个结点
		}
		q=p->next;//q指向第m个结点
		cout<<q->no<<" ";//该结点出列
		p->next=q->next;
		free(q);//删除q结点(出列结点) 
		head=p->next;//从下一个结点重新开始
	}
}

int main(){
	int n,m;//n->总数 m->出列数
	cin>>n>>m;
	joseph(n,m);
	return 0;
}

题目一结果展示:

 

 题目二源代码:

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;

//创建结点 
typedef struct node{
    int a,b;//a为安全洞的标记,b为洞的序号
    struct node *next;
}node;

//主函数->find safe holes
int main(){
    node *p,*q;
    p=(node*)malloc(sizeof(node));
    p->b=1;
    p->a=1;
    q=p;//记录头结点 
     
    int i=0;
    while(i<9){
    	//创建十个结点 
        p->next=(node*)malloc(sizeof(node));
        p=p->next;//移动到下一个新结点 
        p->b=i+2;//洞的序号
        p->a=0;
        i++;
    }
    p->next=q;//构建循环 
    p=p->next;//回到头结点 
    
    //寻找安全洞并标记狐狸洞(进100次洞) 
    for(i=0;i<100;i++){
    	int j;
    	int temp=(i+2)%10;//序号归类为1-10 
        for(j=0;j<temp;j++){
            p=p->next;
        }
		p->a=1;//标记狐狸洞 
    }
    
    //输出安全洞 
    for(i=0;i<10;i++){
        if(p->a==0){
        	//非兔子洞已经进行标记 
        	cout<<"可能在第"<<p->b<<"个洞里面"<<endl;
		}
        p=p->next;//遍历,移动到下一个结点 
    }
    return 0;
}

题目二结果展示:

 

2)请分析你程序中每个功能模块的算法时间复杂度。

题目一:

构建含有n个元素的循环链表。时间复杂度为O(n)

本段代码由两层循环构成。内层循环通过从head结点开始报数,报到第m-1个结点,此时寻找到第m个结点(利用第m-1个结点的后继结点)并删除。外层循环在每剔除一个结点后再一次进行遍历。时间复杂度为O(n²)

题目二:

构建含有n个元素的循环链表,a为安全洞的标记,b为洞的序号。时间复杂度为O(n)

本段代码由两层循环构成。内层循环通过题目所给的狐狸进洞的规律,对其所有进入过的洞进行标记(即a=1),便于后续锁定兔子安全洞的位置。外层循环为题目所给的狐狸进洞的总次数(即100次进洞寻找兔子),并继承上一次进洞的位置。时间复杂度为O(n²)

通过之前化简进洞的序号,本段代码利用遍历输出安全洞的位置,即通过从开始的结点中遍历,寻找a标记为0的结点序号并输出。时间复杂度为O(n)


 其他参考:

#include<iostream>
using namespace std;

// 定义结构体 
struct CLNode  
{
	int num;
	CLNode *next;
};
// 初始化链表 
void Initlist(CLNode *&L){  //注意引用!!! 
	L=new CLNode;
	L->next=L;
}
// 创建链表元素
void Creatlist(CLNode *&L,int n){
	CLNode *p=L;
	for(int i=1;i<=n;i++){
		CLNode *q=new CLNode;
		q->num=i;
		q->next=L;   //循环链表的指针指向 
		p->next=q;
		p=q;
	}
}
// 输出链表元素
void Outlist(CLNode *&L){
	CLNode *p=L;
	cout<<"输出小孩序号如下:"<<endl; 
	while(p->next!=L){
		p=p->next;
		cout<<p->num<<" ";
	}
	cout<<endl; 
}
// 输出出列序列
void Output(CLNode *&L,int m){
	CLNode *p=L->next;
	CLNode *pre=L;//定义pre指针以便删除元素操作 
	for(int i=1;i<=m;){
		if(p->next==L){
			if(p->next->next==L)//循环结束条件 
			break;
			else{
				pre=pre->next->next;
				p=p->next->next;
			}
		}
		else{
			pre=pre->next;
			p=p->next;
		}
		i++;
		if(i==m){
			cout<<p->num<<" ";
			pre->next=p->next;
			CLNode *q=p;
			p=p->next;
			q->next=NULL;
			delete q;
			if(p!=L) //注意条件! 
			i=1;
			else
			i=0;  //注意避开头结点 
		}
	}
}
// 释放空间 
void Destroylist(CLNode *&L){
	 delete L;//删除头结点 
}

int main(){
	CLNode *L;       //定义头指针 
	Initlist(L);     //初始化链表 
	
	int n,m;
	cout<<"请输入小孩的总人数:"<<endl;
	cin>>n; 
	Creatlist(L,n);  //插入链表元素 
	
	Outlist(L);      //输出链表元素 
	
	cout<<"请输出出列序号:"<<endl;
	cin>>m;
	cout<<"当n="<<n<<",m="<<m<<"时的出列序号为:"<<endl;
	Output(L,m);    //根据序号输出依次链表元素 
	Destroylist(L);//释放空间 
}
#include<iostream>
using namespace std;
// 定义结构体
struct CLNode  
{
	int num;
	CLNode *next;
};
// 初始化链表
void Initlist(CLNode *&L){  //注意引用!!! 
	L=new CLNode;
	L->next=L;
}
// 创建链表元素
void Creatlist(CLNode *&L,int n){
	CLNode *p=L;
	for(int i=1;i<=n;i++){
		CLNode *q=new CLNode;
		q->num=i;
		q->next=L;   //循环链表的指针指向 
		p->next=q;
		p=q;
	}
}
// 输出链表元素 
void Outlist(CLNode *&L){
	CLNode *p=L;
	cout<<"输出山洞序号如下:"<<endl; 
	while(p->next!=L){
		p=p->next;
		cout<<p->num<<" ";
	}
	cout<<endl; 
}
// 寻找安全洞 
void Safenum(CLNode *&L){
	cout<<"安全洞的编号可能为:"<<endl;
	CLNode *p=L;
	int a[101];    //储存被循环到的链表元素 
	int i=1;
	while(i<=100){   //使循环次数足够多 
		for(int j=0;j<i;j++){
			if(p->next==L)
			p=p->next->next;
			else
			p=p->next;
		}
		a[i-1]=p->num;
		i++;
	}
	for(int j=1;j<=10;j++){
		for(i=0;i<100;i++){
	    	if(a[i]==j)
	    	break;
    	} 
    	if(i>=100)
    	cout<<j<<" ";
	}
}
// 释放空间
void Destroylist(CLNode *&L){
	CLNode *p=L->next;
	while(p!=L){ //除了头结点的所有结点 
		CLNode *q=p;
		p=p->next;
		q->next=NULL;
		delete q;
	}
	 delete p;//删除头结点 
}

int main(){
	CLNode *L;       //定义头指针 
	Initlist(L);     //初始化链表 

	Creatlist(L,10);  //插入链表元素 
	
	Outlist(L);      //输出链表元素 
	
	Safenum(L);    //找到安全洞 
	Destroylist(L);//释放空间 
}
举报

相关推荐

0 条评论