数据结构单链表的相关操作

数据结构单链表的相关操作

包含了带头单链表和不带头单链表:主要包括创建单链表、插入元素、删除元素、查找元素等

本篇文章代码段:

#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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值