1、实验1 链表及其应用
一、实验目的
1. 加深对线性表链式存储结构的理解;
2. 熟练掌握单链表类的描述方法及操作的C++实现;
3. 掌握链表结构的应用;
4. 加强对算法设计能力和程序调试能力的培养。
二、实验学时:建议2~4学时
三、基本知识(略)
四、实验内容
实验内容1 单链表的基本操作
1 问题描述
设计一个带表头结点的单链表类,实现单链表的创建、输出、插入、删除、查找、销毁等操作。
2 数据结构设计
根据问题要求,采用单链表存储结构存储线性表。在头文件LinkList.h中定义。
(1) 结点结构
template
2、t Node //结点结构
{ T data; //结点数据
Node*link;
Node(){ link=NULL;}
Node(T e,Node*next=NULL)
{ data=e;
link=next;
}
};
(2) 单链表类
单链表类的数据成员主要有单链表的头指针,根据要求其成员函数有构造、输出、插入、删除、查找、销毁等操作。
template
3、 //链表指针 public: LinkList(); //构造带表头结点的空单链表 LinkList(T data[],int mSize);//构造有mSize个元素的单链表 ~LinkList(){Clear();} //析构函数 bool Insert(int pos,const T&x); //在单链表第pos个元素前插入元素x bool Remove(int pos, T&x); //删除单链表第pos个元素 bool Replace(int pos,const T&x); //
4、将修改单链表第pos个元素为x
int Length()const; //求表长
bool IsEmpty() const ; //判空操作
void Clear() ; //清空操作
void Output() const ; //输出链表
bool search(const T&x) const;//查找元素x在表中是否存在
}; // Class LinkList
3 算法设计与实现
(1) 构造函数
#include"Linklist.h"
template
5、LinkList() //构造函数1
{ //创建带表头结点的空单链表
head=new Node
6、data[i]); p->link=r; //链接到p指针所指结点之后 p=p->link; //p指针后移 } } (2) 插入操作 a) 插入原理:(在p所指结点之后插入s所指结点。) 在进行插入操作时,要先确定待插入结点(s所指结点)的link指针(s->link)指向,再修改链表指针(p->link)指向,如图1.1和图1.2所示,即 s->link= p->link; p->link=s; b) 算法描述:(在单链表的第pos个元素之前插入元素x) ① 若pos<1,则插入失败,结束; ② 扫描单链表,寻找单
7、链表中第pos-1个元素结点的指针p;
③ 若p存在(p非空)则在其后插入,操作成功,否则不能插入。
c) 算法实现
template 8、
p=p->link;
i++;
}
if(!p) //插入位置不合法
return false;
s=new Node 9、ext;
b) 算法步骤:(删除单链表中的第pos个元素)
① 若pos<1,则删除失败,结束;
② 在单链表中找第pos -1个元素结点的指针p;
③ 若p和p->link均非空,则删除p->link所指结点,否则删除失败。
c) 实现
template 10、le(p->link && i 11、put() const //输出链表
{
Node 12、 // current指向首元结点
while(current!=NULL) //依次扫描链表结点,并逐个释放空间
{
Node 13、
if(current->data==x)
break;
else
current=current->link; //指针后移
return current!=NULL;
}
4 测试
(1)测试代码
#include 14、ut<<"| 1____________输出链表 |"< 15、查找 |"< 16、i++)
data[i]=rand()%100;//用随机数发生器产生100以内的整数
LinkList 17、入位置:"; cin>> pos;
cout<<"插入元素:"; cin>>elem;
if(L.Insert(pos,elem)) //插入成功
cout<<"在第"<< pos <<"个元素前成功插入"< 18、 cout<<"单链表的第"<< pos <<"个元素"< 19、rch(elem))
cout<<"查找成功!"< 20、是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,从某人开始,从1起,报到k则出圈,下一个人再从1报起,如此下去直到圈中只有一人为止,最后一人称为优胜者。求优胜者的编号。
2 数据结构设计
对于n个人的编号(1,2,…,n)可用线性表进行组织,因是n个人按顺时针方向围坐一圈,故可用循环链表存储方式存储,要设计循环链表类和约瑟夫环类。
首先要解决好约瑟夫环类和循环链表类的关系问题,二者关系可以有三种处理方式:一是循环链表类作为约瑟夫环类的基类;二是约瑟夫环类中含有循环链表类的一个对象作为其成员;三是循环链表仅作为约瑟夫环类求优胜者操作的过程中所借助的手段,即作为为约瑟夫环类求优胜者编号 21、成员函数int GetWinner()的局部变量来处理。这里仅以第三种方式为例给出设计过程。
(1) 循环链表结点结构
template 22、实指向循环链表中任一结点的指针均可,故设置current)。
template 23、 CircleLinkList (); //析构函数
bool InsertAfter(const T&x); //在current所指结点之后插入x
bool RemoveCurrent(T&x); //删除current所指结点
void movenext(int n=1); //current后移n次
T GetCurrentData(){return current->data;}
bool toLocatioin(T &t);//让current指向t结点,若没有则current不移动
void 24、Output() const ; //输出循环链表
}; // Class CircleLinkList
(3) 约瑟夫环类
约瑟夫环类提供构造和设置圈中人数numOfBoy(编号为1~numOfBoy)、报数起始点startPosition、报数间隔interval,并能由此求得最终优胜者。
class Joseph // 约瑟夫环类
{
private:
int numOfBoy; //圈中人数
int startPosition; //报数起始点
int interval; //报数间隔
public:
J 25、oseph(int boys,int start,int m):
numOfBoy(boys),startPosition(start),interval(m){}//构造函数
void setNumOfBoy(int num){numOfBoy=num;}//重置圈中人数
void setStartPosition(int start){startPosition=start;}//重置起始点
void setInterval(int inter){interval=inter;}//重置报数间隔
int GetWinner();//求得最终优胜者编号
v 26、oid print(); //输出约瑟夫环
};
3 算法设计与实现
(1) 求约瑟夫环优胜者
a) 原理:
根据总人数numOfBoy建立编号分别为1~numOfBoy的循环链表,如上图所示,设立一个报数器,先找到报数起始点,然后从起始点开始,从1开始报数,报到间隔interval则出圈(即删除该结点),如此下去,直到循环链表中只有一个元素为止,最后一个元素即为优胜者。
b) 算法步骤:
① 给定圈中人数numOfBoy、报数起始点startPosition、报数间隔interval;
② 以编号1~numOfBoy创建循环链表;
③ 找到报数起始结点start 27、Position;
④ 当圈中人数大于1时,重复做:
从当前结点依次从1报到interval,则删除当前结点,并将当前指针指向下一结点。
⑤ 返回圈中最后剩下的人的编号。
c) 实现
int Joseph::GetWinner()//获得最终优胜者
{
CircleLinkList 28、Position); //找到报数起点
cout< 29、t() //输出约瑟夫环
{
cout<<"圈中人数:"<< numOfBoy< 30、 Node 31、Node 32、rent=front=s->link=s;
else //原循环链表非空
{
s->link=current->link;
current->link=s;
front=current;
current=s;
}
return true;
}
(6) 循环链表删除操作
template 33、urrent->data;
if(current==front)//链表中只有一个元素
{
delete current;
current=front=NULL;
}
else
{
front->link=current->link;//修改链表指针
delete current;
current=front->link;
}
return true;
}
(7) 循环链表输出
template 34、//输出循环链表
{
if(!current)//循环链表为空
return ;
Node 35、ont=current; // front后移
current=current->link; //current后移
}
}
(9) 循环链表定位操作
template 36、data!=t) //寻找元素t
{
front1=current1;
current1=current1->link;
if(current1==current)// 已寻找一圈没有元素为t的结点
return false;
}
current=current1; //current指向元素为t的结点
front=front1;
return true;
}
4 测试
(1)测试代码
void main()
{
int total,interv,startboy;
cout<<"请输入初始数据:小 37、孩数,起始小孩号码,间隔数:\n";
cin>>total>>startboy>>interv;
Joseph jose(total,startboy,interv);
jose.print();
cout<<"优胜者编号为: "<






