实验3 线性表的链式存储讲解.docx
《实验3 线性表的链式存储讲解.docx》由会员分享,可在线阅读,更多相关《实验3 线性表的链式存储讲解.docx(25页珍藏版)》请在冰豆网上搜索。
![实验3 线性表的链式存储讲解.docx](https://file1.bdocx.com/fileroot1/2023-1/23/1dc673f0-7357-4c22-811f-74aab00e6572/1dc673f0-7357-4c22-811f-74aab00e65721.gif)
实验3线性表的链式存储讲解
实验报告三线性表的链式存储
一、实验目的:
(1)掌握单链表的基本操作的实现方法。
(2)掌握循环单链表的基本操作实现。
(3)掌握两有序链表的归并操作算法。
二、实验内容:
(请采用模板类及模板函数实现)
1、线性表链式存储结构及基本操作算法实现
[实现提示](同时可参见教材p64-p73页的ADT描述及算法实现及ppt)函数、类名称等可自定义,部分变量请加上学号后3位。
也可自行对类中所定义的操作进行扩展。
所加载的库函数或常量定义:
(1)单链表存储结构类的定义:
templateclassLinkList;//前视定义,便于使用友元
template
classNode
{friendclassLinkList;//友元类
private:
datatypedata;
Node*next;//此处也可以省略
}
template
classLinkList
{
public:
LinkList();//建立只有头结点的空链表
LinkList(datatypea[],intn);//建立有n个元素的单链表
~LinkList(){}//析构函数,释放整个链表空间
intLength();//求单链表的长度
datatypeGet(inti);//取单链表中第i个结点的元素值
voidInsert(inti,datatypex);//在单链表中第i个位置插入元素值为x的结点
voiddestroy()//在单链表中删除所有的结点
voidPrintList();//遍历单链表,按序号依次输出各元素
intEmpty()//判断表是否为空
private:
Node*head;//单链表的头指针
};
(2)初始化带头结点空单链表构造函数实现
输入:
无
前置条件:
无
动作:
初始化一个带头结点的空链表
输出:
无
后置条件:
头指针指向头结点。
template
LinkList:
:
LinkList()
{
head=newNode;
head->next=NULL;
}
(3)利用数组初始化带头结点的单链表构造函数实现
输入:
已存储数据的数组及数组中元素的个数
前置条件:
无
动作:
利用头插或尾插法创建带头结点的单链表
输出:
无
后置条件:
头指针指向头结点,且数组中的元素为链表中各结点的数据成员。
template
LinkList:
:
LinkList(datatypea[],intn)
{inti;
Node*s;
head=newNode;
head->next=NULL;
for(i=0;i{
s=newNode;
s->data=a[i];
s->next=head->next;
head->next=s;
}
}
(4)在带头结点单链表的第i个位置前插入元素e算法
输入:
插入位置i,待插入元素e
前置条件:
i的值要合法
动作:
在带头结点的单链表中第i个位置之前插入元素e
输出:
无
后置条件:
单链表中增加了一个结点
template
voidLinkList:
:
Insert(inti,datatypex)
{
Node*p;intj;
p=head;j=0;//指针p初始化
while(p&&j{
p=p->next;//指针p后移
j++;
}//找插入点
if(!
p)
cout<<"i不合法!
";
else{
Node*s;
s=newNode;
s->data=x;
s->next=p->next;
p->next=s;
}
}
(5)在带头结点单链表中删除第i个元素算法
输入:
删除第i个结点,待存放删除结点值变量e
前置条件:
单链表不空,i的值要合法
动作:
在带头结点的单链表中删除第i个结点,并返回该结点的值(由e传出)。
输出:
无
后置条件:
单链表中减少了一个结点
template
datatypeLinkList:
:
Delete(inti)
{if(head->next==NULL)
Cout<<”表为空,无法删除!
”;
Node*p;
intj;
p=head;j=0;
while(p&&j{
p=p->next;
j++;
}//找到第i-1个结点
if(!
p||!
p->next)
throw“i不合法”;
else{
q=p->next;
x=q->data;
p->next=q->next;
deleteq;
returnx;
}
}
(6)遍历单链表元素算法
输入:
无
前置条件:
单链表不空
动作:
遍历输出单链表中的各元素。
输出:
无
后置条件:
无
template
voidLinkList:
:
PrintList()
{Node*p;
p=head->next;//p指向首结点
while(p)//p!
=NULL
{
cout<data;
cout<<””;
p=p->next;
}
}
(7)求单链表表长算法。
输入:
无
前置条件:
无
动作:
求单链表中元素个数。
输出:
返回元素个数
后置条件:
无
template
intLinkList:
:
Length()
{
Node*p;
p=head->next;
inti=0;
while(p)
{
p=p->next;
i++;
}
returni;
}
(8)判单链表表空算法
输入:
无
前置条件:
无
动作:
判表是否为空。
输出:
为空时返回1,不为空时返回0
后置条件:
无
template
intLinkList:
:
Length()
{if(head->next=NULL)
return1;
return0;
}
(9)获得单链表中第i个结点的值算法
输入:
无
前置条件:
i不空,i合法
动作:
找到第i个结点。
输出:
返回第i个结点的元素值。
后置条件:
无
template
datatypeLinkList:
:
Get(inti)
{
Node*p;
intj;//计数器
p=head->next;j=1;//或p=head;j=0;
while(p&&j
{
p=p->next;//工作指针p后移
j++;
}
if(!
p)
cout<<“i值不合法,超过了元素的个数!
";
elsereturnp->data;
}
(10)删除链表中所有结点算法(这里不是析构函数,但功能相同)
输入:
无
前置条件:
单链表存在
动作:
清除单链表中所有的结点。
输出:
无
后置条件:
头指针指向空
template
voidlinklist:
:
destroy()
{
Node*p;
while(head->next!
=NULL)
{
p=head;
head=head->next;
deletep;
}
head->next=NULL;
}
(11)上机实现以上基本操作,写出main()程序:
参考p72
voidmain()
{
inta[]={9,2,3,4,5,6},n=6;
LinkListmylist;
for(inti=0;imylist.Insert(i,a[i]);
cout<<"yichishuchushuju:
"<mylist.PrintList();
cout<cout<<"表长为:
"<cout<mylist.Insert(5,8);
mylist.PrintList();
cout<cout<<"表长为:
"<mylist.Empty();
mylist.destroy();
cout<cout<<"表长为:
"<}
粘贴测试数据及运行结果:
2、参考单链表操作定义与实现,自行完成单循环链表的类的定义与相操作操作算法。
(1)利用数组初始化带头结点的单循环链表构造函数实现
输入:
已存储数据的数组及数组中元素的个数
前置条件:
无
动作:
利用头插或尾插法创建带头结点的单循环链表
输出:
无
后置条件:
头指针指向头结点,且数组中的元素为链表中各结点的数据成员,尾指针指向头结点。
template
linklist:
:
linklist(datatypea[],intn)
{
node*s;
head=newnode;
head->next=head;
for(inti=0;i{
s=newnode;
s->data=a[i];
s->next=head->next;
head->next=s;
}
}
(2)在带头结点单循环链表的第i个位置前插入元素e算法
输入:
插入位置i,待插入元素e
前置条件:
i的值要合法
动作:
在带头结点的单循环链表中第i个位置之前插入元素e
输出:
无
后置条件:
单循环链表中增加了一个结点
template
voidlinklist:
:
insert(inti,datatypeitem)
{
node*p;intj;
p=head;
j=0;//指针p初始化
while(p->next!
=head&&j{
p=p->next;//指针p后移
j++;
}//找插入点
if(!
p)
cout<<"i不合法!
";
else
{
node*s;
s=newnode;//申请一个结点
s->data=item;//将插入元素保存在P结点中
s->next=p->next;
p->next=s;
}
}
(3)在带头结点单循环链表中删除第i个元素算法
输入:
删除第i个结点,待存放删除结点值变量e
前置条件:
单循环链表不空,i的值要合法
动作:
在带头结点的单循环链表中删除第i个结点,并返回该结点的值(由e传出)。
输出:
无
后置条件:
单循环链表中减少了一个结点
template
datatypelinklist:
:
Delete(inti)
{if(head->next==head)
cout<<"表为空,无法删除!
";
node*p,*q;
intj;
p=head;
j=0;
while(p->next!
=head&&j{
p=p->next;
j++;
}
if(!
p)
cout<<"i不合法";
else{
datatypex;
q=p->next;
x=q->data;
p->next=q->next;
deleteq;
returnx;
}
}
(4)遍历单循环链表元素算法
输入:
无
前置条件:
单循环链表不空
动作:
遍历输出单循环链表中的各元素。
输出:
无
后置条件:
无
template
voidlinklist:
:
putlist()
{node*p;
p=head->next;//p=head;
if(p->next==head)
cout<<"表为空";
else
while(p!
=head)//p->next!
=head
{
cout<data<<"";//p=p->next;
p=p->next;//cout<data<<"";
}
}
(5)上机实现以上基本操作,写出main()程序:
voidmain()
{
inta[]={45,89,9,13,8,2},n=6;
linklists;
for(inti=0;is.insert(i,a[i]);
s.insert(1,14);
cout<<"第一次遍历链表元素输出:
"<s.putlist();
s.Delete(3);
cout<<"第二次遍历表输出;"<s.putlist();
}
粘贴测试数据及运行结果:
3、采用链式存储方式,并利用单链表类及类中所定义的算法加以实现线性表La,Lb为非递减的有序线性表,将其归并为新线性表Lc,该线性表仍有序(未考虑相同时删除一重复值)的算法。
模板函数:
#include
templateclasslinklist;//前视定义
template
classnode
{
friendclasslinklist;
private:
typedata;
node*next;
};
template
classlinklist
{
private:
node*head;
public:
linklist();//无参构造函数
linklist(typea[],intn);//有参构造函数
voidprintlist();//遍历链表
typeinsert(inti,typeitem);//在第i个结点元素前插入元素item
intlength();//求链表长度
voidsort();//对新的链表元素排序并输出
typeget(inti);//获得第i个结点元素
};
template
linklist:
:
linklist()
{
head=newnode;
head->next=NULL;
}
template
linklist:
:
linklist(typea[],intn)
{
node*s;
head=newnode;
head->next=NULL;
for(inti=0;i{
s=newnode;
s->data=a[i];
s->next=head->next;
head->next=s;
}
}
template
typelinklist:
:
insert(inti,typeitem)
{
node*p;
intj=0;
p=head;
while(p&&j{
p=p->next;//指针p后移
j++;
}
if(!
p)
cout<<"i不合法!
";
else
{
node*s;
s=newnode;//申请一个结点
s->data=item;//将插入元素保存在s结点中
s->next=p->next;
p->next=s;
returnitem;
}
}
template
intlinklist:
:
length()
{
node*p;
p=head;
intn=0;
while(p!
=NULL)
{
p=p->next;
n++;
}
returnn;
}
template
typelinklist:
:
get(inti)
{
node*p;
intj=0;
p=head;
while(p&&j{
p=p->next;
j++;
}
if(!
p)
cout<<"i值不合法!
";
else
returnp->data;
}
template
voidlinklist:
:
sort()
{
node*p,*q;
typetemp;
p=head;
while(p)
{
q=p->next;
while(q)
{
if(p->data>q->data)
{
temp=p->data;
p->data=q->data;
q->data=temp;
}
q=q->next;
}
p=p->next;
}
}
template
voidlinklist:
:
printlist()
{
node*p;
p=head->next;
while(p)
{
cout<data<<"";
p=p->next;
}
}
voidmain()
{
inta[]={1,66,0,5,2,6,7};
intb[]={3,4,6,7,8,76};
linklistLa(a,7);
linklistLb(b,6);
cout<<"第一组元素输出:
";
La.printlist();
cout<cout<<"第二组元素输出:
";
Lb.printlist();
cout<for(inti=2;i{
La.insert(i,Lb.get(i));//将数组a的元素插入到b当中去
}
cout<<"合并后的元素为:
"<La.sort();//排序
La.printlist();
cout<cout<<"合并后元素个数为:
"<}
粘贴测试数据及运行结果:
选做题:
1、按一元多项式ADT的定义,实现相关操作算法:
ADTPNodeis
Data
系数(coef)
指数(exp)
指针域(next):
指向下一个结点
Operation
暂无
endADTPNode
ADTPolynomialis
Data
PNode类型的头指针。
Operation
Polynomail
初始化值:
无
动作:
申请头结点,由头指针指向该头结点,并输入m项的系数和指数,建立一元多项式。
DestroyPolyn
输入:
无
前置条件:
多项式已存在
动作:
消毁多项式。
输出:
无
后置条件:
头指针指向空
PolyDisplay
输入:
无
前置条件:
多项式已存在,不为空
动作:
输出多项式各项系数与指数
输出:
无
后置条件:
无
AddPoly
输入:
另一个待加的多项式
前置条件:
一元多项式pa和pb已存在。
动作及后置条件:
完成多项式相加运算,(采用pa=pa+pb形式,并销毁一元多项式pb)
输出:
无
endADTPolynomial
2、实现一元多项式的减法,操作描述如下:
SubPoly
输入:
待减的多项式pb
前置条件:
一元多项式pa和pb已存在。
动作及后置条件:
完成多项式减法运算,即:
pa=pa-pb,并销毁一元多项式pb。
输出:
无
3、参考P74-P79页双向链表的存储结构定义及算法,编程实现双向链表的插入算法和删除算法。
#include
templateclasslinklist;
template
classnode
{friendclasslinklist;
private:
typedata;
node*next,*prior;
};
template
classlinklist
{
public:
linklist();//建立只有头结点的空链表
linklist(typea[],intn);//建立有n个元素的双向链表
~linklist(){}//析构函数,释放整个链表空间
intlength();//求双向链表的长度
typeinsert(inti,typex);//在双向链表中第i个位置插入元素值为x的结点
typeDelete(inti);//删除第i个位置的元素
voidprintlist();//遍历双向链表,按序号依次输出