单链表的基本操作
一、实验目的:
1、复习C语言程序设计中的知识。
2、掌握线性表的链式存储结构的表示和实现方法。
3、掌握单链表基本操作的算法实现。
二、实验内容:
1.建立单链表。
2.在单链表上实现插入、删除和查找等操作。
三、实验要求:
编写实现单链表基本操作的以下函数,并在此基础上设计一个主程序完成如下功能:
⑴初始化单链表L,类型自选;
⑵用头插法建立单链表L;
⑶用尾插法建立单链表L;
⑷输出单链表L的长度;
⑸输出单链表L的第i个元素(按位置查找);
⑹输出给定元素的位置(按内容查找);
⑺在第i个元素前插入给定元素(在第i个位置插入);
⑻删除单链表L的第i个元素;
⑼输出单链表;
⑽清空单链表(只保留头结点);
⑾菜单函数;
⑿单链表逆置;
⒀建立一个非递减排序的单链表。
四、实验设计:
单链表的存储结构
typedef struct Node //结点类型定义
{ ElemType data;
struct Node *next;
} *LinkList,Node; // LinkList为单链表的类型名
实现顺序表所需的函数共涉及12个函数:
main() : 主函数
menu() : 菜单函数
InitList() :初始化函数
Create_LinkListF() :头插法建立单链表
Create_LinkListR() :尾插法建立单链表
LinkList_Length() :求单链表长度函数
GetData_LinkList() :单链表的位置查找函数
Search_LinkList() :单链表的内容查找函数
InsList() :单链表的的插入函数
DeleteNo_LinkList() :单链表的的指定位置结点删除函数
Print_LinkList() :单链表的遍历函数
SetNull_LinkList() :单链表的清空函数
单链表的函数描述
(1)函数名:main()
输入:输入你选择的菜单编码,最后输入两个getchar()用于清除缓存区
输出:主函数调用菜单函数后输入菜单编码,调用相应的功能函数,每调完一个后按任意键就又返回主菜单,继续调用其他函数,当输出编码错误是输出“输入1~9之间的数字”,当所有功能完成后输出“程序结束”
算法描述:在while循环语句中,首先调用menu()函数,再用switch ()语句通过menu()函数中相应编码执行后面功能函数的调用,每执行一个功能函数后就跳出switch ()语句,继续输入其他的编码执行其他相应函数,一直到实现完所有的功能函数,最后如果输入编码错误是输出“输入1~9之间的数字”,另外,在switch ()语句中还要执行将1赋值给quit,如果当quit=1是就结束while循环语句,最后每调完一个功能函数后就输出“按任意键返回主菜单!”以及当所有功能完成后输出“程序结束”
(2)函数名:menu()
输入:无
输出:首先输出每个编码所代表的功能函数的作用,再输出“输入需要访问的编号”
算法描述:把编码与功能函数一一对应
(3)函数名:InitList()
输入:无
输出:成功初始化就输出“初始化成功”
算法描述:首先定义一个单链表,之后在堆区申请分配一块指定大小的内存空间来存放单链表L,如果申请分配内存空间成功,就让单链表的头指针指向空指针,并且输出“初始化成功”
(4)函数名:Create_LinkListF()
输入:输入你所建立单链表的元素
输出:首先输出输入的提示语句,建表完成后输出“头插法建立成功”
算法描述:首先定义单链表L,Node指针变量p,单链表元素的类型,再输入单链表的元素,之后用while循环语句,在循环体中,先在堆区申请分配一块指定大小的内存空间来存放节点p,然后把第一个元素赋值给p节点的数据域,再让p节点的指针指向原来头指针L指向的节点,最后再将原来头指针L指向p节点,当输入“#”时跳出while循环语句,建表完成后输出“头插法建立成功”,最后返回单链表
(5)函数名:Create_LinkListR()
输入:输入你所建立单链表的元素
输出:首先输出输入的提示语句,建表完成后输出“尾插法建立成功”
算法描述:首先定义单链表L,Node指针变量p和tail,单链表元素的类型,让头节点等于尾节点,再输入单链表的元素,之后用while循环语句,在循环体中,先在堆区申请分配一块指定大小的内存空间来存放节点p,然后把第一个元素赋值给p节点的数据域,再让尾节点的指针指向p节点,再让p节点指向尾节点,最后尾节点的指针指向空指针,当输入“#”时跳出while循环语句,建表完成后输出“尾插法建立成功”,最后返回单链表
(6)函数名:LinkList_Length()
输入:无
输出:输出单链表的长度
算法描述:首先定义单链表L,Node指针变量p,整形变量j,让p指向指向头节点,再用while循环语句,当p->next存在,p一直指向p的下一个节点,p每移动一次,j加1,直到p->next不存在时跳出while循环语句,最终输出单链表的长度
(7)函数名:GetData_LinkList()
输入:输入单链表查找的序号
输出:首先输出输入单链表查找的序号的提示语句,如果输入的数字不在顺序表范围之内就输出“访问位置不合理”或者“访问为空”,如果访问位置正确就输出取出的元素
算法描述:首先定义单链表L,Node指针变量p,整形变量i,j,输入单链表查找的序号,如果输入的数字不在顺序表范围之内就输出“访问位置不合理”,如果输入的数字在顺序表范围之内,首先让头节点指向p节点,再用while循环语句,当p->next存在同时j<i时,p一直指向p的下一个节点,p每移动一次,j加1,直到p->next不存在或者j>i时跳出while循环语句,如果i=j,就输出查找的元素,如果就j>i,就输出“访问为空”
(8)函数名:Search_LinkList()
输入:输入单链表查找的内容
输出:首先输出输入单链表查找的内容的提示语句,最后输出内容在单链表中的位置
算法描述:首先定义单链表L,Node指针变量p,整形变量j,元素的类型,输入你要在单链表中查找的元素,让p指向首元节点,再用while循环语句,当p存在时,如果p的数据域不等于查找的元素,就让p一直指向p的下一个节点,p每移动一次,j加1,直到p不存在时跳出while循环语句,最后输出查找元素的位置
(9)函数名:InsList()
输入:输入插入位置和元素
输出:首先输出输入插入位置和元素的提示语句,当插入的数字不在顺序表范围之内就输出“插入错误”,如果当前位置pre为空, 表示已找完还未数到第i个,就输出“插入位置不合理!”,当成功插入就输出“插入成功”
算法描述:先定义单链表L,Node指针变量pre,s,整形变量i,k,元素的类型,输入插入的位置和元素,当插入的数字不在顺序表范围之内就输出“插入错误”,让pre指向头节点,再用while循环语句,如果pre不为空同时k小于输入位置的前一个元素,就让pre一直指向pre的下一个节点,pre每移动一次,k加1,如果pre为空,就输出“插入位置不合理!”,在堆区申请分配一块指定大小的内存空间来存放节点s,把输入的元素赋值给s的数据域,再让s节点的指针指向原来pre指向的节点,最后再将pre指向s节点,当成功插入就输出“插入成功”
(10)函数名:DeleteNo_LinkList()
输入:输入删除的位置
输出:首先输出输入删除的位置的提示语句,如果p->next=NULL就输出删除结点的位置i不合理!当成功删除就输出“删除成功”
算法描述:先定义单链表L,Node指针变量p,r,整形变量i,输入删除的位置
,让p指向头节点,再用while循环语句,如果p->next不为空同时k小于输入位置的前一个元素,就让p一直指向p的下一个节点,p每移动一次,k加1,如果p为空,就输出“删除结点的位置i不合理!”,r指向p节点,p指向p的下下一个节点,当成功删除就输出“删除成功”
(11)函数名:Print_LinkList()
输入:无
输出:首先输出单链表的遍历的提示语句,再输出单链表的遍历
算法描述:先定义单链表L,Node指针变量p,让p指向首元节点,再用while循环语句,如果p不为空,就依次输出每个元素,并让p指向p的下一个节点
(12)函数名:SetNull_LinkList()
输入:无
输出:输出成功清空单链表
算法描述:首先单链表L,Node指针变量p,再用while循环语句,如果p存在,就让p指向头节点,L指向L的下一个节点,释放p,当全部清空就输出“成功清空单链表!”,并返回单链表
五、实验总结
- 在运行第6个按内容查找的时候,刚开始输入元素后,按回车键无法正常输出,检查代码也完全没问题,就卡在这一直进行不下去,最后想到可能是受空白字符的影响,如果没有加的话在我们输入第一个字符并以空格结束输入后,该字符与’\n’会一起进入标准流输入,’\n’便会作为第二个scanf语句的内容输入,从而让你的程序出现问题。 而加空格便会屏蔽空白字符。最后在输入控制符前加了一个空格后成功输出。
- 在运行第8个删除单链表中的指定位置的元素时,刚开始运用的时老师的代码,函数中有三个参数,但最终一直没能实现出来,最后改为两个参数,稍微改动了一些,最终成功实现。
六、代码实现
1、单链表的基本操作
#include<stdio.h>
#include<malloc.h>
#include <cstdlib>
typedef char ElemType;
typedef struct Node //结点类型定义
{ ElemType data;
struct Node *next;
} *LinkList,Node; // LinkList为单链表的类型名
void menu()
{
system("cls");
printf("***---1单链表的初始化---***\n");
printf("***---2头插法单链表的建立和遍历---***\n");
printf("***---3尾插法单链表的建立和遍历---***\n");
printf("***---4单链表的长度---***\n");
printf("***---5单链表按位置查找---***\n");
printf("***---6单链表按内容查找---***\n");
printf("***---7在单链表的第i个元素前插入指定元素---***\n");
printf("***---8删除单链表中的第i个元素---***\n");
printf("***---9单链表的遍历---***\n");
printf("***---10单链表的清空---***\n");
printf("***---11退出程序---***\n");
printf("***---请输入需要访问的编号是(1~10)---***\n");
}
LinkList InitList(LinkList L)
{ L=(Node *) malloc (sizeof(Node));
L->next=NULL;
printf("初始化成功\n");
}
LinkList Create_LinkListF()//头插法建立带头结点的单链表函数
{ ElemType x;
LinkList L;
Node *p;
printf("请输入数据直到输入#结束:\n");
scanf("%c", &x);
while (x != '#')
{p = (LinkList) malloc( sizeof(Node ) );
p->data = x;
p->next = L->next;
L->next = p;
scanf("%c", &x);
}
printf("头插法建立成功!\n");
return( L );
}
LinkList Create_LinkListR( ) //尾插法
{ ElemType x;
LinkList L;
Node *p, *tail;
tail = L;
printf("请输入数据直到输入#结束:\n");
scanf("%c", &x);
while (x != '#')
{ p = (Node *) malloc( sizeof( Node ) );
p->data = x;
tail->next = p;
tail = p;
tail->next = NULL;
scanf("%c", &x);
}
printf("尾插法建立成功!\n");
return( L );
}
int LinkList_Length (LinkList L)
{ Node *p = L; //p指向头结点
int j = 0;
while( p->next)
{ p=p->next; //所指的是第j个结点
j ++;
}
printf("输出单链表的长度:%d\n",j);
}
//按序号查找
Node *GetData_LinkList(LinkList L, int i)
{ Node *p;
int j = 0;
printf("请输入单链表查找的序号:");
scanf("%d",&i);
if (i <= 0)
printf("访问位置不合理\n");
p = L;
while( p->next && j < i )
{ p = p->next;
j ++;
}
if ( i == j)
printf("%c\n",p->data); //找到第i个节点
else
printf("访问为空\n");
}
//按内容查找
int Search_LinkList(LinkList L, ElemType key)
{ Node *p;int j =0;
printf("请输入单链表查找的内容:");
scanf(" %c",&key) ;
p = L->next;
while( p!=NULL&&p->data != key )
{p = p->next;
j++;
}
if(p)
printf("输出查找内容的位置:%d\n",j);
}
//在带头结点的单链表L中第i个位置插入值为e的新结点
void InsList(LinkList L, int i, ElemType e)
{ Node *pre, *s;
printf("输入插入的位置和元素:");
scanf("%d %c",&i,&e);
int k;
if(i<=0)
printf("插入错误!\n");
pre=L; k=0;
while(pre!=NULL&&k<i-1)
//在第i个元素之前插入, 则先找到第i-1个数据元素的存储位置, 使指针pre指向它
{pre=pre->next;
k=k+1;
}
if(! pre)
//如果当前位置pre为空, 表示已找完还未数到第i个,所以一定是插入位置不合理所致
printf("插入位置不合理!\n");
s=(Node*)malloc(sizeof(Node)); //为e申请一个新的结点并由s指向它
s->data=e; //将待插入结点的值e赋给s的数据域
s->next=pre->next; //完成插入操作
pre->next=s;
printf("插入成功!\n");
}
int DeleteNo_LinkList(LinkList L, int i)
/* 在带头结点的单链表L中删除第i个元素, 并将删除的元素保存到变量*e中 */
{ printf("输入删除的元素的位置:");
scanf("%d",&i);
Node *p, *r;
int k;
p=L; k=0;
while(p->next!=NULL&&k<i-1)
/* 寻找被删除结点i的前驱结点i-1使p指向它 */
{p=p->next;
k=k+1;
}
if(k!=i-1) /* 即while循环是因为p->next=NULL而跳出的 */
{
printf("删除结点的位置i不合理!\n");
return 0;
}
r=p->next;
p->next=p->next->next; /* 删除结点r */
printf("删除成功!\n");
}
void Print_LinkList( LinkList L)
{ Node *p = L->next;
printf("单链表的遍历:");
while(p != NULL)
{printf(" %c ", p->data);
p = p->next;
}
}
LinkList SetNull_LinkList(LinkList L)
{ Node *p;
while(p)
{p=L;
L=L->next;
free(p);
}
printf("成功清空单链表!\n");
return(L);
}
int main()
{LinkList L;int i,select,quit=0;ElemType key,e;
while(1)
{ menu();
scanf("%d",&select);
switch (select)
{
case 1:L=InitList(L);break;
case 2:L=Create_LinkListF();Print_LinkList(L);break;
case 3:L=Create_LinkListR();Print_LinkList(L);break;
case 4:LinkList_Length(L);break;
case 5:GetData_LinkList(L,i);break;
case 6:Search_LinkList(L,key);break;
case 7:InsList(L,5,e);break;
case 8:DeleteNo_LinkList(L,7);break;
case 9:Print_LinkList(L);break;
case 10:SetNull_LinkList(L);break;
case 11:quit=1;break;
default:printf("输入1~10之间的数字\n");break;
}
if(quit==1)
{
break;
}
printf("按任意键返回主菜单!\n");
getchar();
getchar();
printf("程序结束!\n");
}
return 0;
}
3、单链表的应用
#include<stdio.h>
#include<malloc.h>
typedef char ElemType;
typedef struct Node //结点类型定义
{ ElemType data;
struct Node *next;
} *LinkList,Node; // LinkList为单链表的类型名
LinkList InitList(LinkList L)
{ L=(Node *) malloc (sizeof(Node));
L->next=NULL;
return L;
}
LinkList Create_LinkListF()//头插法建立带头结点的单链表函数
{ ElemType x;
LinkList L;
Node *p;
printf("请输入数据直到输入#结束:\n");
scanf("%c", &x);
while (x != '#')
{p = (LinkList) malloc( sizeof(Node ) );
p->data = x;
p->next = L->next;
L->next = p;
scanf("%c", &x);
}
return( L );
}
LinkList Create_LinkListR() //尾插法
{ ElemType x;
LinkList L;
Node *p, *tail;
tail = L;
printf("请输入数据直到输入#结束:\n");
scanf("%c", &x);
while (x != '#')
{ p = (Node *) malloc( sizeof( Node ) );
p->data = x;
tail->next = p;
tail = p;
tail->next = NULL;
scanf("%c", &x);
}
return( L );
}
void Print_LinkList( LinkList L)
{ Node *p = L->next;
while(p != NULL)
{printf(" %c ", p->data);
p = p->next;
}
}
int main()
{ LinkList L;
L=Create_LinkListF();
printf("单链表的逆置:");
Print_LinkList(L);
printf("\n");
L= Create_LinkListR( );
printf("单链表的升序建立:");
Print_LinkList(L);
return 0;
}