数据结构单链表的相关操作
包含了带头单链表和不带头单链表:主要包括创建单链表、插入元素、删除元素、查找元素等本篇文章代码段:
#include<stdlib.h> // 引入带malloc和free函数的头文件
#define ElemType int//定义默认的数据元素类型
//定义单链表结点类型
typedef struct LNode
{
//每个结点存放一个数据元素
int data;
// 指针指向下一个节点
struct LNode *next;
}LNode,*LinkList;
//初始化单链表(带头结点)
bool InitList1(LinkList &L)
{
//分配一个头结点
L=(LNode*) malloc(sizeof(LNode));
//内存不足,分配失败
if(L==NULL)
return false;
//初始化为空链表
L->next=NULL;
return true;
}
//初始化单链表(不带头结点)
bool InitList2(LinkList &L)
{
//初始化为空链表
L=NULL;
return true;
}
//判断单链表是否为空 (带头结点)
bool Empty1(LinkList L)
{
if (L->next==NULL)
return true;
else
return false;
}
//判断单链表是否为空 (不带头结点)
bool Empty2(LinkList L)
{
if (L==NULL)
return true;
else
return false;
}
//求单链表的长度(带头结点)
int Length1(LinkList L)
{
//len为计数器,用以统计表长
int len=0;
LNode *p=L;
while(p->next!=NULL)
{
p=p->next;
len++;
}
return len;
}
//求单链表的长度(不带头结点)
int Length2(LinkList L)
{
//len为计数器,用以统计表长
int len=0;
LNode *p=L;
//如果不为空长度至少为1
if(p!=NULL)
len+=1;
while(p->next!=NULL)
{
p=p->next;
len++;
}
return len;
}
//头插法建立单链表(带头结点)
LinkList List_HeadInsert1(LinkList &L)
//逆向建立单链表
{
printf("请输入结点值,输入8888代表结束输入操作!\n");
LNode *s;
//设置元素类型为整型
int x;
//创建头结点
L=(LinkList)malloc(sizeof(LNode));
//初始为空链表
L->next=NULL;
//输入结点的值
scanf("%d",&x);
//当输入值为8888时结束输入操作,可以为设置任意值
while(x!=8888)
{
//创建新结点
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
//将新结点插入表中,L为头结点
L->next=s;
scanf("%d",&x);
}
return L;
}
//头插法建立单链表(不带头结点)
LinkList List_HeadInsert2(LinkList &L)
//逆向建立单链表
{
printf("请输入结点值,输入8888代表结束输入操作!\n");
LNode *s;int x;
//输入结点的值
scanf("%d",&x);
//当输入值为8888时结束输入操作,可以为设置任意值
while(x!=8888)
{
s=(LNode*)malloc(sizeof(LNode));//创建新结点
s->data=x;
s->next=L;
//将新结点插入表中,L为第一个结点
L=s;
scanf("%d",&x);
}
return L;
}
//尾插法建立单链表(带头结点)
LinkList List_TailInsert1(LinkList &L)
//正向建立单链表
{
printf("请输入结点值,输入8888代表结束输入操作!\n");
//设置元素类型为整型
int x;
LNode *s;
//r为表尾指针
LNode *r=L;
//创建头结点
L=(LinkList)malloc(sizeof(LNode));
scanf("%d",&x);//输入结点的值
//输入8888表示结束输入操作,可以为设置任意值
while(x!=8888)
{
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
r->next=s;
//r指向新的表尾结点
r=s;
scanf("%d",&x);
}
//尾结点指针置空,防止指向未知区域
r->next=NULL;
return L;
}
//尾插法建立单链表(不带头结点)
LinkList List_TailInsert2(LinkList &L)
//正向建立单链表
{
printf("请输入结点值,输入8888代表结束输入操作!\n");
//设置元素类型为整型
int x;
LNode *s;
//输入第一个结点的值
scanf("%d",&x);
//创建第一个结点
L=(LNode*)malloc(sizeof(LNode));
L->data=x;
L->next=NULL;
LNode *r=L;//r为表尾指针
scanf("%d",&x);//输入结点的值
//输入8888表示结束输入操作
while(x!=8888)
{
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
r->next=s;
//r指向新的表尾结点
r=s;
scanf("%d",&x);
}
//尾结点指针置空,防止指向未知区域
r->next=NULL;
return L;
}
//在第i个位置插入元素e(带头结点)
bool LinkInsert1(LinkList &L,int i,ElemType e)
{
if(i<1)
return false;
LNode *p;//指针p指向当前扫描到的结点
int j=0;//当前指向的是第几个结点
p=L;//L指向头结点,头结点是第 0个结点(不存数据)
while (p!=NULL && j<i-1)//循环找到i-1个结点
{p=p->next;
j++;
}
if(p==NULL)//i值不合法
return false;
LNode *s=(LNode *)malloc(sizeof(LNode)) ;
s->data=e;
s->next=p->next;
p->next=s;//将结点s连到p之后
return true; //插入成功
}
//在第i个位置插入元素e(不带头结点)
bool LinkInsert2(LinkList &L,int i,ElemType e)
{
if(i<1)
return false;
if(i==1){//插入第一个结点操作与其他结点操作不同
LNode *s=(LNode *)malloc(sizeof(LNode));
s->data=e;
s->next=L;
L=s;//头指针指向新结点
return true;
}
LNode *p;//指针p指向当前扫描到的结点
int j=1;//当前指向的是第几个结点
p=L;//L指向第一个结点(注意:不是头结点)
while (p!=NULL && j<i-1)//循环找到i-1个结点
{p=p->next;
j++;
}
if(p==NULL)//i值不合法
return false;
LNode *s=(LNode *)malloc(sizeof(LNode)) ;
s->data=e;
s->next=p->next;
p->next=s;//将结点s连到p之后
return true; //插入成功
}
//按序号查找结点值(带头结点)
LNode *GetElem1(LinkList L,int i)
{
int j=1;//计数,初始为 1
LNode *p=L->next;//头指针赋值给p
if(i==0)
return L;//若i等于0,返回头结点
if(i<1)
return NULL;//若i无效,返回NULL
while(p!=NULL && j<i){//从第一个结点开始找,查找第i个元素
p=p->next;
j++;
}
return p;//返回第i个指针,若i大于表长,则返回NULL
}
//按序号查找结点值(不带头结点)
LNode *GetElem2(LinkList L,int i)
{
int j=1;//计数,初始为 1
LNode *p=L;//头指针赋值给p
if(i<1)
return NULL;
while(p!=NULL && j<i){//从第2个结点开始找,查找第i个元素
p=p->next;
j++;
}
return p;//返回第i个指针,若i大于表长,则返回NULL
}
//按值查找,找到数据域==e的结点(带头结点)
LNode * LocateElem1(LinkList L,ElemType e)
{
LNode *p=L->next;
//从第一个结点开始查找数据域为e的结点
while (p!=NULL &&p->data!=e)
p=p->next;
return p;//找到后返回该节点指针,否则返回NULL
}
//按值查找,找到数据域==e的结点(不带头结点)
LNode * LocateElem2(LinkList L,ElemType e)
{
LNode *p=L;
//从第一个结点开始查找数据域为e的结点
while (p!=NULL &&p->data!=e)
p=p->next;
return p;//找到后返回该节点指针,否则返回NULL
}
//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p,ElemType e)
{
if(p==NULL)
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL)//内存分配失败
return false;
s->data=e;//用结点s保存数据元素e
s->next=p->next;
p->next=s; //将结点s连到p之后
return true;
}
//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode *p,ElemType e)
{
if(p==NULL)
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if(s==NULL)//内存分配失败
return false;
s->next=p->next;
p->next=s; //将新结点s连到p之后
s->data=p->data;//将p中元素复制到s中
p->data=e;//p中元素覆盖为e
return true;
}
//删除第i个元素(带头结点)
bool ListDelete1 (LinkList &L,int i,ElemType &e)
{
if(i<1)
return false;
LNode *p;//指针p指向当前扫描到的结点
int j=0;//当前指向的是第几个结点
p=L;//L指向头结点,头结点是第 0个结点(不存数据)
while (p!=NULL && j<i-1)//循环找到i-1个结点
{
p=p->next;
j++;
}
if(p==NULL)//i值不合法
return false;
if(p->next==NULL) //第i- 1个结点后已无其他结点
return false;
LNode *q=p->next;//令q指向被删除的结点
e=q->data;//用e返回元素的值
p->next=q->next;//将*q结点从链中“断开”
free(q);//释放结点的存储空间
return true; //删除成功
}
//删除第i个元素(不带头结点)
bool ListDelete2(LinkList &L,int i,ElemType &e)
{
if(i<1)
return false;
if(i==1)
{
LNode *p;
p=L;
e=p->data;
L=p->next;
free(p);
return true;
}
LNode *p;
int j=1;
p=L;
while(p!=NULL&&j<i-1)
{
p=p->next;
j++;
}
if(p==NULL)//i值不合法
return false;
if(p->next==NULL) //第i- 1个结点后已无其他结点
return false;
LNode *q=p->next;//令q指向被删除的结点
e=q->data;//用e返回元素的值
p->next=q->next;//将*q结点从链中“断开”
free(q);//释放结点的存储空间
return true; //删除成功
}
//删除指定结点p 注意:如果结点p为尾结点该方法会操作失败!
bool DeleteNode(LNode *p)
{
if(p==NULL)
return false;
LNode *q=p->next;//令q指向*p的后继结点
p->data=q->data;//和后继结点交换数据域
p->next=q->next;//将*q从链中“断开”
free(q);//释放后继结点的存储空间
return true;
}
//带头结点的链表输出函数
void Display1(LinkList &L)
{
LNode*q =L->next;
while(q)
{
printf("%d ",q->data);
q=q->next;
}
printf("\n");
}
//不带头结点的链表输出函数
void Display2(LinkList &L){
LNode*q =L;
while(q)
{
printf("%d ",q->data);
q=q->next;
}
printf("\n");
}
//带头结点的操作
void LinkOperation1(LinkList &L)
{
int x;
int i;
int e;
LNode *p;
printf("请选择后续操作:\n1.插入元素\n2.删除元素\n3.查询链表元素\n4.查询链表当前长度\n5.展示链表\n6.返回主菜单\n");
scanf("%d",&x);
while(x<1 or x>6)
{
printf("操作错误,请选择正确的操作方式:\n1.插入元素\n2.删除元素\n3.查询链表元素\n4.查询链表当前长度\n5.展示链表\n6.返回主菜单\n");
scanf("%d",&x);
}
if(x==1)
{
printf("请输入您要插入元素的位序及其值(第一个为位序,第二个为其值,以逗号隔开)\n");
scanf("%d,%d",&i,&e);
if(LinkInsert1(L,i,e))
{
printf("插入成功!在第%d个位置插入了元素%d!\n是否继续插入元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("插入失败,是否重新输入插入元素位序及其值:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
while(x==1)
{
printf("请输入您要插入元素的位序及其值(第一个为位序,第二个为其值,以逗号隔开)\n");
scanf("%d,%d",&i,&e);
if(LinkInsert1(L,i,e))
{
printf("插入成功!在第%d个位置插入了元素%d!\n是否继续插入元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("插入失败,是否重新输入插入元素位序及其值:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
}
}
else if(x==2)
{
printf("请输入您要删除的元素的位序\n");
scanf("%d",&i);
if(ListDelete1(L,i,e))
{
printf("删除成功!删除了第%d个位置的元素%d!\n是否继续删除元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("删除位序不合法,删除失败,是否继续删除:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
while(x==1)
{
printf("请输入您要删除的元素的位序\n");
scanf("%d",&i);
if(ListDelete1(L,i,e))
{
printf("删除成功!删除了第%d个位置的元素%d!\n是否继续删除元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("删除位序不合法,删除失败,是否继续删除:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
}
}
else if(x==3)
{
printf("请输入您要查询的位序\n");
scanf("%d",&i);
while(GetElem1(L,i)==NULL)
{
printf("查询失败,是否继续操作:\n1.继续查询\n2.结束查询\n");
scanf("%d",&x);
if(x==1)
{
printf("请输入您要查询的位序\n");
scanf("%d",&i);
}
else
{
break;
}
}
if(GetElem1(L,i)!=NULL)
{
p=GetElem1(L,i);
e=p->data;
printf("第%d个元素的值为:%d\n",i,e);
}
}
else if(x==4)
{
int len;
len=Length1(L);
printf("当前链表的长度为%d!",len);
}
else if(x==5)
{
Display1(L);
}
}
//不带头结点的操作
void LinkOperation2(LinkList &L)
{
int x;
int i;
int e;
LNode *p;
printf("请选择后续操作:\n1.插入元素\n2.删除元素\n3.查询链表元素\n4.查询链表当前长度\n5.展示链表\n6.返回主菜单\n");
scanf("%d",&x);
while(x<1 or x>6)
{
printf("操作错误,请选择正确的操作方式:\n1.插入元素\n2.删除元素\n3.查询链表元素\n4.查询链表当前长度\n5.展示链表\n6.返回主菜单\n");
scanf("%d",&x);
}
if(x==1)
{
printf("请输入您要插入元素的位序及其值(第一个为位序,第二个为其值,以逗号隔开)\n");
scanf("%d,%d",&i,&e);
if(LinkInsert2(L,i,e))
{
printf("插入成功!在第%d个位置插入了元素%d!\n是否继续插入元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("插入失败,是否重新输入插入元素位序及其值:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
while(x==1)
{
printf("请输入您要插入元素的位序及其值(第一个为位序,第二个为其值,以逗号隔开)\n");
scanf("%d,%d",&i,&e);
if(LinkInsert2(L,i,e))
{
printf("插入成功!在第%d个位置插入了元素%d!\n是否继续插入元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("插入失败,是否重新输入插入元素位序及其值:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
}
}
else if(x==2)
{
printf("请输入您要删除的元素的位序\n");
scanf("%d",&i);
if(ListDelete2(L,i,e))
{
printf("删除成功!删除了第%d个位置的元素%d!\n是否继续删除元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("删除位序不合法,删除失败,是否继续删除:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
while(x==1)
{
printf("请输入您要删除的元素的位序\n");
scanf("%d",&i);
if(ListDelete2(L,i,e))
{
printf("删除成功!删除了第%d个位置的元素%d!\n是否继续删除元素:\n1.继续\n2.结束\n",i,e);
scanf("%d",&x);
}
else
{
printf("删除位序不合法,删除失败,是否继续删除:\n1.继续\n2.结束\n");
scanf("%d",&x);
}
}
}
else if(x==3)
{
printf("请输入您要查询的位序\n");
scanf("%d",&i);
while(GetElem2(L,i)==NULL)
{
printf("查询失败,是否继续操作:\n1.继续查询\n2.结束查询\n");
scanf("%d",&x);
if(x==1)
{
printf("请输入您要查询的位序\n");
scanf("%d",&i);
}
else
{
break;
}
}
if(GetElem2(L,i)!=NULL)
{
p=GetElem2(L,i);
e=p->data;
printf("第%d个元素的值为:%d\n",i,e);
}
}
else if(x==4)
{
int len;
len=Length2(L);
printf("当前链表的长度为%d!",len);
}
else if(x==5)
{
Display2(L);
}
}
//带头结点操作
void test1(int &x){
printf("带头结点单链表的操作: \n");
//声明一个指向单链表的指针
LinkList L;
//初始化单链表
InitList1(L);
printf("您必须创建单链表才可以进行后续操作,请选择创建方式:\n1.头插法\n2.尾插法\n");
scanf("%d",&x);
while(x!=1 and x!=2)
{
printf("操作错误,请选择正确的创建方式:\n1.头插法\n2.尾插法\n");
scanf("%d",&x);
}
if(x==1)
{
List_HeadInsert1(L);
printf("操作成功!\n");
}
else
{
List_TailInsert1(L);
printf("操作成功!\n");
}
//引用函数进行操作
LinkOperation1(L);
printf("是否继续进行其他操作:\n1.继续\n2.结束并返回主菜单\n");
scanf("%d",&x);
//询问用户是否继续进行操作
while(x==1)
{
LinkOperation1(L);
printf("是否继续进行其他操作:\n1.继续\n2.按其他数字结束并返回主菜单\n");
scanf("%d",&x);
}
}
//不带头结点操作
void test2(int &x)
{
printf("不带头结点单链表的操作: \n");
//声明一个指向单链表的指针
LinkList L;
//初始化单链表
InitList2(L);
//创建单链表
printf("您必须创建单链表才可以进行后续操作,请选择创建方式:\n1.头插法\n2.尾插法\n");
scanf("%d",&x);
while(x!=1 and x!=2)
{
printf("操作错误,请选择正确的创建方式:\n1.头插法\n2.尾插法\n");
scanf("%d",&x);
}
if(x==1)
{
List_HeadInsert2(L);
printf("操作成功!\n");
}
else
{
List_TailInsert2(L);
printf("操作成功!\n");
}
//引用函数进行操作
LinkOperation2(L);
printf("是否继续进行其他操作:\n1.继续\n2.结束并返回主菜单\n");
scanf("%d",&x);
//询问用户是否继续进行操作
while(x==1)
{
LinkOperation2(L);
printf("是否继续进行其他操作:\n1.继续\n2.按其他键数字结束并返回主菜单\n");
scanf("%d",&x);
}
}
//主菜单界面
int menu(int &x)
{
printf("<主菜单>请选择功能:\n1.带头结点操作\n2.不带头结点操作\n3.结束程序\n");
scanf("%d",&x);
while(x!=1 and x!=2 and x!=3)
{
printf("操作错误,请选择正确的单链表操作方式:\n1.带头结点\n2.不带头结点\n3.结束程序\n");
scanf("%d",&x);
}
if(x==1)
{
test1(x);
printf("操作成功!\n");
}
else if(x==2)
{
test2(x);
printf("操作成功!\n");
}
else
{
exit(0);
}
}
int main()
{
int x;
menu(x);
while(x)
{
menu(x);
}
return 0;
}