文章目录
一、实验目的
(1)掌握线性表的链接存储结构;
(2)验证链接表及其基本操作的实现;
(3)掌握数据结构及算法的程序实现的基本方法。
二、实验内容
在线性表中实现如下操作:
(1)插入一个新元素到第i
个位置。
(2)删除第i
个位置的元素。
(3)显示线性表中所有元素的值。
(4)检索表中第i
个元素。
(5)求表的长度。
要求:请用链表实现,设计菜单,根据菜单提示进行操作。
三、问题分析
线性表链式存储结构的特点是:用一组任意的存储单元存储线性表的数据元素。用单链表表示线性表时,数据元素之间的逻辑关系是由结点中的指针指示的。单链表是一种动态结构,对于每个链表来捉,它所占用的空间大小和位置是不需要预先分配的。所以创建单链表的过程,先初始化单链表,即从“空表”的初始状态,依次建立各元素结点,并插入到链表中。那么创建整个单链表有两种方法:头插法和尾插法,有了非空的单链表后就可以进行其余的操作。
四、算法设计
4.1、插入一个新元素到第i个位置算法思路
①声明一个指针p指向链表的第一个结点,初始化j
从0
开始;
②当j<i-1时,遍历链表,让p的指针向后移动,不断指向下一结点,j
累加1
;
③若到链表末尾p
为空,说明第i
个元素不存在,否则查找成功,在系统中生成一个空结点q;
④将数据元素e
赋值给q->data
;
⑤将q
结点插入到链表中,q->next=p->next;p->next=q;
⑥返回成功。
//插入元素
int ListInsert(LinkList &L,int i, ElemType e){
LinkList p = L, q;
int j = 0;
while(p && j < i - 1){//寻找第i-1个结点
p = p ->next;
j++;
}
if(!p || i < 1)
return ERROR;//i大于表长+1或小于1
q = new LNode; //生成新结点q
q -> data = e; //将结点q 的数据域置为e
q -> next = p -> next;//将结点q 插入L中
p -> next = q;
return OK;
}
4.2、删除第i个位置的元素算法思路
①声明一个指针p
指向链表的第一个结点,初始化j
从0
开始;
②当j<i-1时,遍历链表,让p的指针向后移动,不断指向下一结点,j
累加1
;
③若到链表末尾p
为空,说明第i
个元素不存在,否则查找成功,将预删除的结点p->next
赋值给q
;
④执行删除标准语句p->next = q->next
;
⑤将q
结点中的数据赋值给e
,作为返回;
⑥释放q
结点,返回成功。
//删除元素
int ListDelete(LinkList &L,int i, ElemType &e){
LinkList p = L,q;
int j = 0;
while(p -> next && j < i-1){//寻找第i个结点,并令p指向其前驱
p = p -> next;
j++;
}
if(!(p -> next) || i < 1)
return ERROR; //删除位置不合理
q = p -> next; //临时保存被删结点的地址以备释放
p -> next = q -> next; //改变被删除结点前驱结点的指针域
e = q -> data; //保存被删除节点的数据域
delete q; //释放被删除结点的空间
return OK;
}
4.3、显示线性表中所有元素的值算法思路
①判断链表L是否为空,若链表为空,则输出“表空!
”,并返回;
②声明一个指针p
指向链表的第一个结点,当单链表非空时,遍历链表,输出链表的数据,并让p
的指针后移,不断指向下一结点。
//显示线性表
void DispList(LinkList L){
printf("单链表为:");
if(ListEmpty(L)){
printf("表空!\n");
return;
}
LinkList p = L -> next;
while(p){
printf("%d ",p -> data);
p = p -> next;
}
printf("\n");
}
4.4、检索表中第i个元素算法思路
①声明一个指针p指向链表的第一个结点,初始化j从1开始;
②当j<i时,遍历链表,让p的指针向后移动,不断指向下一结点, j
累加1
;
③若到链表末尾p
为空,说明第i
个元素不存在;
④否则查找成功,返回结点p的数据。
//检索元素
int GetElem(LinkList L,int i,ElemType &e){
LinkList p = L->next;
int j = 1;
while(p != NULL && j < i){
p = p ->next;
j++;
}
if (!p || i < 1)
return ERROR;
e = p->data;
return OK;
}
4.5、求表的长度算法思路
①声明一个指针p
指向链表的第一个结点,初始化i
从0
开始;
②若链表非空,遍历链表, i
累加1
,让p
的指针向后移动,不断指向下一结点;
③返回统计节点数i的值。
//求表长
int LengthList(LinkList L){
LinkList p = L -> next;//p指向第一个结点
int i = 0;
while(p){
i++;
p = p->next;
}
return i;
}
五、程序界面
主菜单界面,可实现13种操作
六、总结
该程序所包含的内容有线性表的初始化、创建、元素插入、删除元素、查找元素和长度统计,具体操作根据屏幕提示进行。最后以“0”
的输入来结束程序!
当要在单链表的第i
个位置插入一个元素时,必须先将单链表第i
个元素之后的所有元素依次后移一个位置,以便腾空一个位置,再把新元素插入到该位置。当要删除第i
个元素时,也只需将地i个元素之后的所有元素前移一个位置。以及遍历链表时逐一遍历,指针结点后移。程序的时间和空间效率均为O(n)
。
通过对该程序的调试与运行,使得对线性表的功能及其构成有了进一步的了解! 一个完整的程序,是由许多模块所组成的,要使程序能正常运行,必须使每个功能都能正常运行,且能相互连接。就像一个建筑,需要有许多结构组成,任何一个结构都不能有差错!
七、代码
最后呈现一下全部代码
#include<stdio.h>
#define OK 1
#define ERROR 0
#define ListSize 100
typedef int ElemType;
typedef struct Node{
ElemType data;
struct Node *next;
}LNode,*LinkList;
//构造一个空的单链表L,初始化
int IniList(LinkList &L){
L = new LNode;//为头结点分配存储单元
if(!L)
return ERROR;//无足够的内存空间,初始化失败
L -> next = NULL;
return OK;
}
//销毁链表
int DestoyList(LinkList &L){
LinkList p;
while (L){
p = L;
L = L->next;
delete p;
}
return OK;
}
//将L重置为空表
void ClearList(LinkList &L){
LinkList p,q;
p = L->next;//p指向第一个结点
while(p){ //没到表尾
q = p ->next;
delete p;
p = q;
}
L -> next = NULL;//头指针指针域为空
}
//返回L中数据元素个数
int LengthList(LinkList L){
LinkList p = L -> next;//p指向第一个结点
int i = 0;
while(p){
i++;
p = p->next;
}
return i;
}
//若L为空表,则返回true, 否则返回false
int ListEmpty(LinkList L){
if(L->next == NULL)
return true;
else
return false;
}
LinkList LocateElem(LinkList L,ElemType e){
LinkList p;
p = L->next;
while(p && p->data != e)
p = p ->next;
return p;//返回L中值为e的数据元素的位置,查找失败返回NULL
}
//在带头结点的单链表L中查找第i各元素
int GetElem(LinkList L,int i,ElemType &e){
LinkList p = L->next;
int j = 1;
while(p != NULL && j < i){
p = p ->next;
j++;
}
if (!p || i < 1)
return ERROR;
e = p->data;
return OK;
}
//将值为e的新结点插入到表的第i个结点的位置上
int ListInsert(LinkList &L,int i, ElemType e){
LinkList p = L, q;
int j = 0;
while(p && j < i - 1){//寻找第i-1个结点
p = p ->next;
j++;
}
if(!p || i < 1)
return ERROR;//i大于表长+1或小于1
q = new LNode; //生成新结点q
q -> data = e; //将结点q 的数据域置为e
q -> next = p -> next;//将结点q 插入L中
p -> next = q;
return OK;
}
//按序号删除结点
int ListDelete(LinkList &L,int i, ElemType &e){
LinkList p = L,q;
int j = 0;
while(p -> next && j < i-1){//寻找第i个结点,并令p指向其前驱
p = p -> next;
j++;
}
if(!(p -> next) || i < 1)
return ERROR; //删除位置不合理
q = p -> next; //临时保存被删结点的地址以备释放
p -> next = q -> next; //改变被删除结点前驱结点的指针域
e = q -> data; //保存被删除节点的数据域
delete q; //释放被删除结点的空间
return OK;
}
//按值删除结点
int ListDeleteValue(LinkList &L,ElemType e){
LinkList p = L,q = L -> next;
while(q && q -> data != e){ //寻找元素值等于e的结点,并令p指向其前驱
p = q;
q = q -> next;
}
if (!q)
return ERROR; //没有找到值为e的结点
p -> next = q -> next; //改变被删除节点的前驱结点的指针域
delete q; //释放被删除结点的空间
return OK;
}
//在单链表的头部插入结点建立单链表
void CreateList_F(LinkList &L,int n){
//逆位序输入n个元素的值,建立单链表L
//要求,在用前插法创建单链表之前,需要执行InitList()初始化单链表,
//即先建立一个带表头结点的空表
LinkList p;
printf("请按逆序依次输入元素的值:");
for(int i = n ; i > 0; i--){
p = new LNode; //生成新结点
scanf("%d",&p -> data); //输入元素值
p -> next = L -> next ;
L ->next = p; //插入到表头
}
}
//在单链表的尾部插入结点建立单链表
void CreateList_R(LinkList &L,int n){
//正位序输入n个元素的值,建立带头结点的单链表L
//要求,在用前插法创建单链表之前,需要执行IntList()初始化单链表,
//即先建立一个带表头结点的空表
LinkList p, r = L;
printf("请按正序依次输入元素的值:");
for(int i = 0;i < n;i++){
p = new LNode; //生成新结点
scanf("%d",&p -> data); //输入元素值
p -> next = NULL;
r -> next = p; //插入到表尾
r = p; //r指向新的尾结点
}
}
//输出线性表
void DispList(LinkList L){
printf("单链表为:");
if(ListEmpty(L)){
printf("表空!\n");
return;
}
LinkList p = L -> next;
while(p){
printf("%d ",p -> data);
p = p -> next;
}
printf("\n");
}
int _flushall(void){
}
//显示菜单
void Showmenu(){
printf("\n");
printf(" --线性表链式存储基本运算演示-- \n");
printf("***********************************\n");
printf("* 1 ----单链表的初始化 *\n");
printf("* 2 ----销毁单链表 *\n");
printf("* 3 ----清空单链表 *\n");
printf("* 4 ----求单链表的长度 *\n");
printf("* 5 ----判断单链表是否为空 *\n");
printf("* 6 ----检索表中第i个元素的值 *\n");
printf("* 7 ----检索元素值为e的元素 *\n");
printf("* 8 ----插入数据元素 *\n");
printf("* 9 ----按序号删除数据元素 *\n");
printf("* 10----按值删除数据元素 *\n");
printf("* 11----按头插法创建单链表 *\n");
printf("* 12----按尾插法创建单链表 *\n");
printf("* 0 ----退出 *\n");
printf("***********************************\n");
printf("请选择菜单号(0--12): ");
}
void List(){
int choice;
ElemType item;
int Position;
int number;
LinkList L;
int flag = 0; //是否创建好了单链表
while(choice){
Showmenu();
_flushall();
scanf("%d",&choice);
switch(choice){
case 1:
printf("初始化单链表操作\n");
if(IniList(L)){
printf("初始化成功!\n");
flag = 1; //标志顺序表的存在
}
else{
printf("初始化失败!\n");
}
break;
case 2:
if(flag){ //单链表存在
DestoyList(L);
flag = 0; //单链表已删除
printf("单链表删除成功! \n");
}
else {
printf("单链表不存在,操作失败! \n");
}
break;
case 3:
if(flag){ //单链表存在
ClearList(L);
printf("单链表清空成功!\n");
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 4:
if(flag){ //单链表存在
printf("单链表元素个数为 %d \n",LengthList(L));
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 5:
if(flag){ //单链表存在
printf("单链表%s.\n",ListEmpty(L)?"空":"不空");
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 6:
if(flag){ //单链表存在
printf("请输入元素的位序号:");
scanf("%d",&Position);
if(GetElem(L,Position,item)){
printf("第%d个元素为:%d\n",Position,item);
}
else{
printf("输入的位序号有误!\n");
}
DispList(L);
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 7:
if(flag){ //单链表存在
printf("请输入元素的值:");
_flushall();
scanf("%d",&item);
LinkList P = LocateElem(L,item);
if(P){
printf("该元素找到,地址为 %x !\n",P);
}
else{
printf("该元素没找到!\n");
}
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 8:
if(flag){ //单链表存在
printf("请输入元素的值:");
_flushall();
scanf("%d",&item);
printf("请输入要插入数据元素的位序号:");
scanf("%d",&Position);
if(ListInsert(L,Position,item))
printf("该元素插入成功!\n");
else
printf("输入的位序号有误!");
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 9:
if(flag){ //单链表存在
printf("请输入要删除数据元素的位序号:");
scanf("%d",&Position);
if(ListDelete(L,Position,item)){
printf("删除的元素为 %d !\n",item);
}
else{
printf("输入的位序号有误!");
}
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 10:
if(flag){ //单链表存在
printf("请输入要删除的元素:");
_flushall();
scanf("%d",&item);
if(ListDeleteValue(L,item)){
printf("删除的元素为 %d!\n",item);
}
else{
printf("该元素不存在,删除失败!\n");
}
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 11:
if(flag){ //单链表存在
ClearList(L); //清空单链表
printf("按头插法创建单链表\n");
printf("请输入要插入元素的个数:");
scanf("%d",&number);
_flushall();
CreateList_F(L,number);
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 12:
if(flag){ //单链表存在
ClearList(L); //清空单链表
printf("按尾插法创建单链表\n");
printf("请输入要插入元素的个数:");
scanf("%d",&number);
_flushall();
CreateList_R(L,number);
DispList(L); //输出线性表
}
else{
printf("单链表不存在,操作失败! \n");
}
break;
case 0:
printf("\n\t程序结束!\t\n");
DestoyList(L);
break;
default:
printf("\n\t选择错误,请重新输入!\t\n");
break;
}
}
}
int main(){
List();
return 0;
}