目录
目的
验证单链表及其上的基本操作
内容及要求
- 定义单链表类。
- 实验验证如下算法的正确性、各种功能及指标:
1)创建单链表;
2)插入操作:分别在当前结点后、表头、表尾插入值为x的结点;
3)删除操作:分别删除表头结点、表尾结点和当前结点的后继结点;
4)存取操作:分别存取当前结点的值和单链表中第k个结点的值;
5)查找操作:查找值为x的元素在单链表中出现的位置(是链表中的第几个元素)。 - 为便于观察程序的运行结果,设计的输出函数能在屏幕上以规范、直观的形式输出计算结果。例如将链
表输出成如下形式:[1]->[2]->[3]->[4]->[5] - 测试程序时,对所有输入变量取遍各种有代表性的值。
- 为了增强程序的可读性,程序中要有适当的注释。
实验过程
算法设计、代码编写、程序调试、测试数据设计、测试
算法设计
先编写有关单链表操作的各个函数:
InitList(LinkList *&L);
DestroyList(LinkList *&L);
ListEmpty(LinkList *L);
ListLength(LinkList *L);
DispList(LinkList *L);
GetElem(LinkList *L,int i,ElemType &e);
LocateElem(LinkList *L,ElemType e);
ListInsert(LinkList *&L,int i,ElemType e);
ListDelete(LinkList *&L,int i,ElemType &e);
之后的五个函数对应主函数中的五项功能,通过选择结构语句确定执行哪项功能。
代码编写
#include <stdio.h>
#include <malloc.h>
typedef char ElemType;
typedef struct LNode /*定义单链表结点类型*/
{
ElemType data;
struct LNode *next;
} LinkList;
void InitList(LinkList *&L)
{
L=(LinkList *)malloc(sizeof(LinkList)); /*创建头结点*/
L->next=NULL;
}
void DestroyList(LinkList *&L)
{
LinkList *p=L,*q=p->next;
while (q!=NULL)
{
free(p);
p=q;
q=p->next;
}
free(p);
}
int ListEmpty(LinkList *L)
{
return(L->next==NULL);
}
int ListLength(LinkList *L)
{
LinkList *p=L;
int i=0;
while (p->next!=NULL)
{
i++;
p=p->next; }
return(i);
}
void DispList(LinkList *L)
{
LinkList *p=L->next;
while (p!=NULL)
{
printf("%c",p->data);
p=p->next;
}
printf("\n");
}
int GetElem(LinkList *L,int i,ElemType &e) //查找值
{
int j=0;
LinkList *p=L;
while (j<i && p!=NULL)
{
j++;
p=p->next; }
if (p==NULL || i<1) // 当超出上界或者下界时,查询失败
{
printf("您输入的元素位置数据不合法!\n");
return 0;
}else
{
e=p->data;
return 1;
}
}
int LocateElem(LinkList *L,ElemType e) //查找位置
{
LinkList *p=L->next;
int n=1;
while (p!=NULL && p->data!=e)
{
p=p->next;
n++;
}
if (p==NULL)
return(0);
else
return(n);
}
int ListInsert(LinkList *&L,int i,ElemType e) //插入节点
{
int j=0;
LinkList *p=L,*s;
while (j<i-1 && p!=NULL)
{
j++;
p=p->next;
}
if (p==NULL || i<=0) /*未找到第i-1个结点*/
{
printf("插入失败!\n");
return 0;
}else /*找到第i-1个结点*p*/
{ s=(LinkList *)malloc(sizeof(LinkList)); /*创建新结点*s*/
s->data=e;
s->next=p->next; /*将*s插入到*p之后*/
p->next=s;
printf("插入完成!\n") ;
return 1;
}
}
int ListDelete(LinkList *&L,int i,ElemType &e) //删除节点
{ int j=0;
LinkList *p=L,*q;
while (j<i-1 && p!=NULL)
{
j++;
p=p->next; }
if (p==NULL || i <1 ||q==NULL ) /*未找到第i-1个结点*/
{
return 0;
}else /*找到第i-1个结点*p*/
{ q=p->next; /*q指向要删除的结点*/
e=q->data;
p->next=q->next; /*从单链表中删除*q结点*/
free(q); /*释放*q结点*/
return 1; }
}
// void InitList(LinkList *&L);
// void DestroyList(LinkList *&L);
// int ListEmpty(LinkList *L);
// int ListLength(LinkList *L);
// void DispList(LinkList *L);
// int GetElem(LinkList *L,int i,ElemType &e);
// int LocateElem(LinkList *L,ElemType e);
// int ListInsert(LinkList *&L,int i,ElemType e);
// int ListDelete(LinkList *&L,int i,ElemType &e);
int three(LinkList *h,int pos,ElemType &e){
Sur:printf("\n请输入你要查询的数据元素的位置(数字):");
scanf("%d", &pos) ;
if(GetElem(h,pos,e))
{
printf("单链表h的第%d个元素=%c\n", pos, e);
} else {
printf("查询失败!\n");
SurEle: printf("你是否要继续查询?(Y/N)") ;
getchar();
char ele;
scanf("%c", &ele) ;
switch (ele)
{
case 'Y':
case 'y': goto Sur ; break;
case 'N':
case 'n': printf("您选择放弃再次查询!\n") ; break;
default: printf("您输入的数据不合法!请重新输入:\n"); goto SurEle ; break;
}
}
}
int two(LinkList *h,ElemType e){
SurCon:printf("\n请输入你要查找的数据元素的值:") ;
getchar();
scanf("%c", &e) ;
if (LocateElem(h,e))
{
printf("查找成功,元素%c的位置=%d\n", e, LocateElem(h,e));
} else {
printf("查询失败!你输入的数据元素的值不存在!\n") ;
SurConEle: printf("你是否要继续查询?(Y/N)") ;
getchar();
char ele;
scanf("%c", &ele) ;
switch (ele)
{
case 'Y':
case 'y': goto SurCon ; break;
case 'N':
case 'n': printf("您选择放弃再次查询!\n") ; break;
default: printf("您输入的数据不合法!请重新输入:\n"); goto SurConEle ; break;
}
}
}
int one(LinkList *h){
printf("\n请输入你要插入的数据元素的位置和数据元素值(以逗号隔开):");
int pos;
ElemType e;
scanf("%d,%c", &pos, &e);
if (ListInsert(h, pos, e))
{
printf("输出成功插入元素后的单链表h:");
DispList(h);
}
}
int four(LinkList *h,int pos,ElemType &e){
Dle:printf("\n请输入你要删除的数据元素的位置:");
//getchar();
scanf("%d", &pos) ;
if(ListDelete(h,pos,e))
{
printf("删除成功!你删除的位置的数据元素值为%c\n", e) ;
printf("输出成功删除元素后单链表h:");
DispList(h);
printf("你是否要继续删除?(Y/N)") ;
getchar();
char ele;
scanf("%c", &ele) ;
switch (ele)
{
case 'Y':
case 'y': goto Dle ; break;
case 'N': case 'n': printf("您选择不再继续删除!\n") ; break;
default: printf("您输入的数据不合法!请重新输入:\n"); goto Dle ; break;
}
} else
{
printf("删除失败!请检查你输入的数据元素的位置!\n") ;
DleEle: printf("你是否要继续再次尝试删除?(Y/N)") ;
getchar();
char ele;
scanf("%c", &ele) ;
switch (ele)
{
case 'Y':
case 'y': goto Dle ; break;
case 'N':
case 'n': printf("您选择放弃尝试删除!\n") ; break;
default: printf("您输入的数据不合法!请重新输入\n"); goto DleEle ; break;
}
}
}
int five(LinkList *h){
printf("\n释放单链表h。。。\n");
DestroyList(h);
printf("\n释放单链表h成功!!\n");
}
int main() {
int pos;
LinkList *h;
ElemType e;
printf("(1)初始化单链表h\n");
InitList(h);
// printf("\n(2)依次插入a,b,c元素\n");
// ListInsert(h, 1, 'a');
// ListInsert(h, 2, 'b');
// ListInsert(h, 3, 'c');
// printf("\n(3)输出单链表h:");
// DispList(h);
// printf("\n(4)单链表h长度=%d\n",ListLength(h));
// printf("\n(5)单链表h为%s\n",(ListEmpty(h)?"空":"非空"));
int choice;
while(1){
printf("\n\n1:插入元素\n2:查询元素的位置\n3:查询元素的值\n4:删除元素\n5:释放单链表\n");
scanf("%d",&choice);
switch(choice){
case 1:one(h);break;
case 2:two(h,e);break;
case 3:three(h,pos,e);break;
case 4:four(h,pos,e);break;
case 5:five(h);break;
}
}
return 0;
}
程序调试
- 单链表的操作main.cpp [Error] ‘pos’ was not declared in this scope
进行分析后发现错误是由于并未在函数中声明pos的类型,当把pos声明为int类型时,错误消失。 - 单链表的操作main.cpp [Error] too few arguments to function ‘int two(LinkList*, ElemType)’
进行分析后发现错误是由于调用函数时传参不够,当把e传进去后,错误消失。
测试数据设计
先输入1,选择插入元素功能;然后输入1,a;在第一个节点插入a;
之后再输入2,b;在第一个节点后插入b;
再输入3,c;在第二个节点后插入c;
再输入2,选择查询元素位置功能;然后输入b;返回2;
再输入3,选择查询元素的值功能;然后输入1,返回a;
再输入4,选择删除元素功能;然后输入1,返回删除成功,输出b,c;
再输入5,选择释放单链表功能;返回释放成功。
结果
总结
- 程序运行过程中有许多冗杂的地方,还有许多需要改进的地方。
- 关于错误方面,构造存储结构时需要注意字母的大小写。还有遇到输入数据错误时应加上返回语句return 0,否则会出现程序检查时没有错误但运行时出现内存错误的提示。在函数调用时函数的形参不能写类型。