引言
【C/C++数据结构实验】这个系列是我这个学期上的数据结构课上老师布置的实验,实验题目如下。我一般用c++,但是没有用到类啥的,就是普普通通的面向过程的思想不是面向对象的思想,只是借用c++的一些方便的环境,比如形参处可以写——*&,引用型参数很好用。
有需要的同学们自取吧,虽然算法不是很巧妙,但是都是我实实在在学完了自己一点点写出来的,运行结果是完全没问题的。正好这门课结课了,发上来我也能再复习一下!
一、实验题目
上机实验题3:链表基本操作的实现
建立单链表存储数据(10,20,30,40,50,60,70,80,90,100),要求:
(1)头插法或尾插法建立单链表,并输出单链表中所有元素;
(2)输出单链表中的最大值和最小值;
(3)键盘输入一个值x,输出链表中第一个值为x的元素的位序;
(4)键盘输入一位序值b,在第b个元素之前插入值为500的元素,输出链表中的所有数据;
(5)键盘输入位序值m,删除位序为m的元素,输出链表中的所有数据;
(6)输出单链表的长度。
(要求尽量将每一个操作模块化,可以将链表头指针设置成全局变量,也可以采用引用型参数。)
二、实验具体算法(c++)
#include<iostream>
#include<cstdlib>
#define MaxSize 50
using namespace std;
typedef int ElemType;
//声明LinkNode类型
typedef struct LNode{
ElemType date;//存放元素值
struct LNode *next;//指向后继节点的指针域
}LinkNode;
//建立单链表,头插法
void CreateListR(LinkNode *&L,ElemType a[],int n)
{int i=0;
L=(LinkNode*)malloc(sizeof(LinkNode));
L->next=NULL;//建立单链表并且为其初始化,将其next域置零
LinkNode *p;
while(i<=n)
{
p=(LinkNode*)malloc(sizeof(LinkNode));//为每一个a[i]对应的数值建立一个新的结点,将a[i]的数值赋给这个新的结点
p->date=a[n-i];
p->next=L->next;//将p所指的结点插入到L链表的头节点之后的首节点位置
L->next=p;
i++;
}
}
//比较大小
void MaxMin(LinkNode *L)
{int max,min;
max=L->next->date;
min=L->next->date;
LinkNode *p=L->next;//p指向L链表的首节点
while(p->next!=NULL)
{
if(max<p->date)
max=p->date;
if(min>p->date)
min=p->date;
p=p->next;
}
cout<<"max="<<max<<";min="<<min<<endl;
}
//输出链表
void DispList(LinkNode *&L)
{
LinkNode *p=L->next;//p指向首结点
while(p->next!=NULL)
{
cout<<p->date<<" ";
p=p->next;//p指向L的下一个结点
}
cout<<endl;
}
//向链表中插入元素
bool ListInsert(LinkNode *&L,ElemType e,int i)
{int j=0;
LinkNode *s,*p=L->next;
if(i<1)
{cout<<"插入位序不合理!"<<endl;//注意,插入函数内的if语句必须要保证:符合if语句条件,输出相应的信息后就结束,不再执行其后续语句,否则会顺序执行下面的语句。可以定义函数为bool型,在每个if语句后执行相应的return(可以在return前正常输出提示信息,而让return只起到符合语句就推出插入函数的作用)。但是一定不能采用break语句,否则还是会继续(也可能break不合理无法运行)
return false;
}
while(p!=NULL&&j<i-1)//注意:链表无需注意该结点的下一个是否为空!!!!!只需要保证本结点不为空,就可以在本结点之前插入元素(链表存储空间不连续)
{
p=p->next;
j++;
}
if(p==NULL)
{
cout<<"第"<<i-1<<"个结点为空结点,第"<<i<<"个结点超出链表范围,无法插入!"<<endl;
return false;
}
else
{ s=(LinkNode*)malloc(sizeof(LinkNode));
s->date=e;
s->next=p->next;
p->next=s;
cout<<"插入成功!"<<endl;
return true;
}
}
//删除链表某位序对应的元素
bool ListDelect(LinkNode *&L,int i)
{
LinkNode *s,*p=L->next;//p指向L首结点
if(i<1)
{
cout<<"位序错误!"<<endl;
return false;
}
int j;
for(j=1;p!=NULL&&j<i-1;j++)//初始p指向首节点,即链表中第一个元素,故初始j=1。j的数值对应链表中元素位序(逻辑位序)
p=p->next;
if(p==NULL)
{
cout<<"给出的位序超出链表元素最大位序,不存在该结点,无法删除!"<<endl;
return false;
}
else
{
s=p->next;//!!!此步非常关键,如果不把第i个指针存起来,在删除时,无论是先连接还是先free都会出现问题——丢失掉第i个结点后续的结点
p->next = s->next;
free(s);//释放掉第i个结点
}
}
//按元素查找
void LocateList(LinkNode *L,ElemType e)
{
int i;
LinkNode *p=L->next;
for(i=1;p!=NULL&&p->date!=e;i++)//由于此处的p是指针,且没有为其分配内存空间,故p为纯指针,p表示指针p(所指向的值)的地址
p=p->next;
if(p==NULL)
cout<<"不存在数值"<<e<<",查找失败!"<<endl<<endl;
else
cout<<"查找成功,该元素位序为:"<<i<<endl<<endl;//注意,一般将最后的成功的结果的条件放在最后面。“先排除所有错误的情况,剩下的就是正确的结果!!!”
}
//返回链表长度
int ListLength(LinkNode *&L)
{
LinkNode *p=L->next;
int i=1;
while(p->next!=NULL)
{
p=p->next;
i++;
}
return i;
}
//销毁链表
void DestroyList(LinkNode *&L)
{
LinkNode *p=L,*s=L->next;
while(s->next!=NULL)
{
free(p);
p=s;
s=s->next;
}
free(s);
cout<<endl<<"链表销毁成功!"<<endl<<endl;
}
int main()
{
LinkNode *m;
int x,b,k,a[MaxSize];
for(int i=0;i<10;i++)
a[i]=(i+1)*10;
CreateListR(m,a,10);
cout<<"(1)输出链表:"<<endl;
DispList(m);
cout<<endl<<"(2)链表中最大元素与最小元素:"<<endl;
MaxMin(m);
cout<<endl<<"(3)将查找链表中第一个值为x的元素的位序,请输入值x:";
cin>>x;
LocateList(m,x);
cout<<"(4)将在位序b之前插入值为500的元素,请输入位序b:";
cin>>b;
ListInsert(m,500,b);
cout<<"输出链表:"<<endl;
DispList(m);
cout<<endl<<"(5)将删除链表中位序为k的元素,请输入位序值k:";
cin>>k;
ListDelect(m,k);
cout<<"输出链表:"<<endl;
DispList(m);
cout<<endl<<"(6)单链表长度为:"<<ListLength(m)<<endl;
DestroyList(m);
}
三、实验总结与收获
我怕我忘了,我记性不好,所以当时把能想到的,还有我自己调出来的错误都给写在注释里了。说实话,当时写实验报告的时候,实验收获是最难写的,尤其是前几个实验没有总结的意识,导致写完程序过几天写报告的时候脑子空空如也。大家一定要想到什么就写出来,记在脑子里真的会忘的!!(也可能我是金鱼的记忆???)