【数据结构】1.2线性表的链式表示(单链表)

本文代码为学习总结,如果错误敬请指正!感谢各位大佬 😃

1.1线性表的顺序表示(顺序表)

带头结点的单链表

结点定义

/*使用 typedef,之后可用于直接定义参数
	如LNode *GetElem (LinkList L)
	  LNode强调返回的是一个节点
	  LinkList强调L是一个单链表 
*/
typedef struct LNode{
	int data; 
	struct LNode *next;
}LNode,*LinkList;

初始化

//(带头结点的空表) 初始化
bool InitList(LinkList &L){
	L=(LinkList)malloc(sizeof(LNode));//动态分配内存 
	if(L==NULL){//内存分配失败 
		return false;
	}
	//不管带不带头结点,头指针始终指向链表的第一个结点
	//而头结点是带头结点的链表中第一个结点,结点内通常不存储信息 
	L->next=NULL;//带头结点(若不带头结点,则可表示为L==NULL) 
	return true;
} 

构建链表

头插法构建链表

//头插构建 (反向) 
//头插法的重要作用:链表的逆置 
LinkList List_HeadInsert(LinkList &L){
	printf("头插法构建链表:(以空格间隔、9999结束)\n"); 
	LNode *s;
	int x;
	L=(LinkList)malloc(sizeof(LNode));//创建头结点 
	L->next=NULL;//初始为空链表(!!!!!!!必须得加 ) 
	scanf("%d",&x);//输入结点的值 
	while(x!=9999){//输入9999 表示结束 
		s=(LNode*)malloc(sizeof(LNode));//创建新结点(由系统生成一个LNode型的结点,同时将该节点的起始位置赋给指针变量s) 
		s->data=x;
		s->next=L->next;
		L->next=s;//L为头指针 
		scanf("%d",&x);
	}
	return L;
}

尾插法构建链表

//尾插构建,正向 
LinkList List_TailInsert(LinkList &L){
	printf("尾插法构建链表:(以空格间隔、9999结束)\n"); 
	int x;
	L=(LinkList)malloc(sizeof(LNode));//创建头结点 
	LNode *s,*r=L;//r为表尾指针 
	L->next=NULL;//初始为空链表(!!!!!!!必须得加 ) 
	scanf("%d",&x);//输入结点的值 
	while(x!=9999){//输入9999 表示结束 
		s=(LNode*)malloc(sizeof(LNode));//创建新结点(由系统生成一个LNode型的结点,同时将该节点的起始位置赋给指针变量s) 
		s->data=x;
		r->next=s;
		r=s;//r指向新的表尾结点 
		scanf("%d",&x);
	}
	r->next=NULL;//尾结点指针置空,即为最后结点,下一结点为空 
	return L;
}

查找结点

按值查找结点

//按值查找(带头结点,头结点可以看为i=0) 
LNode *LocateElem(LinkList L,int e){
	LNode *p=L->next;//指向第一个结点 
	while(p!=NULL && p->data!=e){//查找数据域为e的结点 
		p=p->next;
	}
	return p; //找到后返回该指针,否则返回NULL 
} 

按位序查找结点

//按位序查找(带头结点,结点可以看为i=0) 
LNode *GetElem(LinkList L,int i){
	if(i<0){
		return NULL;
	}
	if(i==0){
		return L;//头结点 
	} 
	LNode *p;//指针p指向当前扫描到的结点 
	int j=1;//当前p指向的是第几个结点 
	p=L->next;//L指向第一个结点 
	while(p!=NULL && j<i){//循环找到第i个结点 
		p=p->next;
		j++;
	}
	return p;//返回第i个头结点的指针,若大于表长,则返回NULL 
} 


插入

在指定结点前插入

//前插,在p结点前插入元素e 
bool InsertPriorNode(LNode *p,int 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->data=p->data;
	p->data=e; 
	return true;
} 

在指定结点后插入

//后插,在p结点后插入元素e 
bool InsertNextNode(LNode *p,int e){
	if(p==NULL){//考虑到健壮性 
		return false;
	}
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if(s==NULL){//内存分配失败 
		return false;
	}
	s->data=e;
	s->next=p->next;
	p->next=s;//将s连到p之后 
	return true;
} 

在指定位序插入元素

//按位序插入,在第i个位置插入元素e(带头结点)
bool ListInsert1(LinkList &L,int i,int e){
	if(i<1){
		return false;
	}
	
	LNode *p=GetElem(L,i-1);//找到第i-1个结点,等价于下面部分注释代码
//	LNode *p;
//	int j=0;
//	p=L;
//	while(p!=NULL && j<i-1){
//		p=p->next;
//		j++;
//	}

	return InsertNextNode(p,e); //后插,等价于下面部分注释代码
//	LNode *p;
//	if(p==NULL){
//		return false;
//	}
//	LNode *s =(LNode*)malloc(sizeof(LNode));
//	s->data=e;
//	s->next=p->next;
//	p->next=s;
//	return true;
}

求单链表长度

//求长度 (带头结点 ) 
int Length(LinkList L){
	int len=0;
	LNode *p=L;
	while(p->next!=NULL){
		p=p->next;
		len++;
	}
	return len;
}

删除

按位序删除结点

//(带头结点)按位序删除
bool ListDelete(LinkList &L,int i,int &e){
	if(i<1){
		return false;
	}
	LNode *p=GetElem(L,i-1);//找到第i-1个结点 ,等价于下面部分注释代码
//	LNode *p;
//	int j=0;
//	p = L;
//	while(p!=NULL && j<i-1){
//		p=p->next;
//		j++;
//	}
	if(p==NULL){
		return false;
	}
	if(p->next==NULL){
		return false;
	}
	LNode *q=p->next;
	e=q->data;
	p->next=q->next;
	free(q);
	return true;
} 
 

删除指定结点

 //删除指定结点p
bool DeleteNode(LNode *p){
	if(p==NULL){
		return false;
	}
	LNode *q=p->next;//q指向*p的后继节点 
	p->data=p->next->data;//和后继节点交换数据域 
	p->next=q->next;//将*q结点从链中断开 
	free(q);//释放内存 
	return true;
} 

打印输出

 //打印输出链表 
void PrintList(LinkList L){
	LNode *p=L->next;//指向第一个结点 
	if(p==NULL){
		printf("这是空链表!\n");
	}
	printf("表长为:%d\n",Length(L)); 
	while(p!=NULL){
		printf("%d\n",p->data);
		p=p->next;
	} 
} 

完整代码及运行结果

代码

#include<stdlib.h>
#include<stdio.h>

//结点定义 
#define MaxSize 50//线性表最大长度 

/*使用 typedef,之后可用于直接定义参数
	如LNode *GetElem (LinkList L)
	  LNode强调返回的是一个节点
	  LinkList强调L是一个单链表 
*/
typedef struct LNode{
	int data; 
	struct LNode *next;
}LNode,*LinkList;

//(带头结点的空表) 初始化
bool InitList(LinkList &L){
	L=(LinkList)malloc(sizeof(LNode));//动态分配内存 
	if(L==NULL){//内存分配失败 
		return false;
	}
	//不管带不带头结点,头指针始终指向链表的第一个结点
	//而头结点是带头结点的链表中第一个结点,结点内通常不存储信息 
	L->next=NULL;//带头结点(若不带头结点,则可表示为L==NULL) 
	return true;
} 
 
//头插构建 (反向) 
//头插法的重要作用:链表的逆置 
LinkList List_HeadInsert(LinkList &L){
	printf("头插法构建链表:(以空格间隔、9999结束)\n"); 
	LNode *s;
	int x;
	L=(LinkList)malloc(sizeof(LNode));//创建头结点 
	L->next=NULL;//初始为空链表(!!!!!!!必须得加 ) 
	scanf("%d",&x);//输入结点的值 
	while(x!=9999){//输入9999 表示结束 
		s=(LNode*)malloc(sizeof(LNode));//创建新结点(由系统生成一个LNode型的结点,同时将该节点的起始位置赋给指针变量s) 
		s->data=x;
		s->next=L->next;
		L->next=s;//L为头指针 
		scanf("%d",&x);
	}
	return L;
}

//尾插构建,正向 
LinkList List_TailInsert(LinkList &L){
	printf("尾插法构建链表:(以空格间隔、9999结束)\n"); 
	int x;
	L=(LinkList)malloc(sizeof(LNode));//创建头结点 
	LNode *s,*r=L;//r为表尾指针 
	L->next=NULL;//初始为空链表(!!!!!!!必须得加 ) 
	scanf("%d",&x);//输入结点的值 
	while(x!=9999){//输入9999 表示结束 
		s=(LNode*)malloc(sizeof(LNode));//创建新结点(由系统生成一个LNode型的结点,同时将该节点的起始位置赋给指针变量s) 
		s->data=x;
		r->next=s;
		r=s;//r指向新的表尾结点 
		scanf("%d",&x);
	}
	r->next=NULL;//尾结点指针置空,即为最后结点,下一结点为空 
	return L;
}
 
 
//按值查找(带头结点,头结点可以看为i=0) 
LNode *LocateElem(LinkList L,int e){
	LNode *p=L->next;//指向第一个结点 
	while(p!=NULL && p->data!=e){//查找数据域为e的结点 
		p=p->next;
	}
	return p; //找到后返回该指针,否则返回NULL 
} 

//按位序查找(带头结点,结点可以看为i=0) 
LNode *GetElem(LinkList L,int i){
	if(i<0){
		return NULL;
	}
	if(i==0){
		return L;//头结点 
	} 
	LNode *p;//指针p指向当前扫描到的结点 
	int j=1;//当前p指向的是第几个结点 
	p=L->next;//L指向第一个结点 
	while(p!=NULL && j<i){//循环找到第i个结点 
		p=p->next;
		j++;
	}
	return p;//返回第i个头结点的指针,若大于表长,则返回NULL 
} 

//后插,在p结点后插入元素e 
bool InsertNextNode(LNode *p,int e){
	if(p==NULL){//考虑到健壮性 
		return false;
	}
	LNode *s = (LNode *)malloc(sizeof(LNode));
	if(s==NULL){//内存分配失败 
		return false;
	}
	s->data=e;
	s->next=p->next;
	p->next=s;//将s连到p之后 
	return true;
} 

//前插,在p结点前插入元素e 
bool InsertPriorNode(LNode *p,int 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->data=p->data;
	p->data=e; 
	return true;
} 

//按位序插入,在第i个位置插入元素e(带头结点)
bool ListInsert1(LinkList &L,int i,int e){
	if(i<1){
		return false;
	}
	LNode *p=GetElem(L,i-1);//找到第i-1个结点
//	LNode *p;
//	int j=0;
//	p=L;
//	while(p!=NULL && j<i-1){
//		p=p->next;
//		j++;
//	}

	return InsertNextNode(p,e); 
//	if(p==NULL){
//		return false;
//	}
//	LNode *s =(LNode*)malloc(sizeof(LNode));
//	s->data=e;
//	s->next=p->next;
//	p->next=s;
//	return true;
}
/*
//按位序插入,在第i个位置插入元素e(不带头结点)
bool ListInsert2(LinkList &L,int i,int 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;
	int j=1;
	p=L;
	while(p!=NULL && j<i-1){
		p=p->next;
		j++;
	}
	return InsertNextNode(p,e); 
//	if(p==NULL){
//		return false;
//	}
//	LNode *s =(LNode*)malloc(sizeof(LNode));
//	s->data=e;
//	s->next=p->next;
//	p->next=s;
//	return true;
}
*/
//求长度 (带头结点 ) 
int Length(LinkList L){
	int len=0;
	LNode *p=L;
	while(p->next!=NULL){
		p=p->next;
		len++;
	}
	return len;
}
 
//(带头结点)按位序删除
bool ListDelete(LinkList &L,int i,int &e){
	if(i<1){
		return false;
	}
//	LNode *p;
//	int j=0;
//	p = L;
//	while(p!=NULL && j<i-1){
//		p=p->next;
//		j++;
//	}
	LNode *p=GetElem(L,i-1);//找到第i-1个结点 
	if(p==NULL){
		return false;
	}
	if(p->next==NULL){
		return false;
	}
	LNode *q=p->next;
	e=q->data;
	p->next=q->next;
	free(q);
	return true;
} 
 
 //删除指定结点p
bool DeleteNode(LNode *p){
	if(p==NULL){
		return false;
	}
	LNode *q=p->next;//q指向*p的后继节点 
	p->data=p->next->data;//和后继节点交换数据域 
	p->next=q->next;//将*q结点从链中断开 
	free(q);//释放内存 
	return true;
} 
 
//打印输出链表 
void PrintList(LinkList L){
	LNode *p=L->next;//指向第一个结点 
	if(p==NULL){
		printf("这是空链表!\n");
	}
	printf("表长为:%d\n",Length(L)); 
	while(p!=NULL){
		printf("%d\n",p->data);
		p=p->next;
	} 
} 

//打印输出结点
void PrintNode(LNode *s){
	printf("查找的结点为:%d\n",s->data);
} 

int main(){
	int i,e;
	bool flag;
	LNode *s;
	LinkList L1,L2,L3;
	InitList(L1);//初始化链表(带头结点) 
	InitList(L2);//初始化链表(带头结点)
	InitList(L3);//初始化链表(带头结点)
	PrintList(L1);//打印输出链表 
	PrintList(L2);//打印输出链表 
	PrintList(L3);//打印输出链表 
	printf("--------------------------------------------------------\n");
	List_HeadInsert(L1);
	PrintList(L1);//打印输出链表 
	printf("【按位序插入】\n请输入要插入的位序i:");
	scanf("%d",&i);
	printf("请输入要插入的值e:");
	scanf("%d",&e);
	flag=ListInsert1(L1,i,e);//按位序插入,成功true,失败false 
	if(flag){
		printf("插入成功,插入结点后的链表:\n");
		PrintList(L1);
	}else{
		printf("插入失败!\n");
	}
	printf("--------------------------------------------------------\n");
	List_TailInsert(L2);
	PrintList(L2);//打印输出链表
	printf("【按位序删除】\n请输入要删除的位序i:");
	scanf("%d",&i);
	flag=ListDelete(L2,i,e);
	if(flag){
		printf("删除成功,删除的值为:%d\n",e);
		printf("删除结点后的链表:\n");
		PrintList(L2);
	}else{
		printf("删除失败!\n");
	}
	printf("【按值删除】\n请输入要删除的值e:");
	scanf("%d",&e);
	s=LocateElem(L2,e);
	flag=DeleteNode(s);
	if(flag){
		printf("删除成功,删除的值为:%d\n",e);
		printf("删除结点后的链表:\n");
		PrintList(L2);
	}else{
		printf("删除失败!\n");
	}
	printf("--------------------------------------------------------\n");
	List_TailInsert(L3);//尾插构建链表(顺序) 
	PrintList(L3);//打印输出链表 
	printf("【按值查找结点】请输入要查找的值e:");
	scanf("%d",&e);
	s=LocateElem(L3,e);//按值查找,有则返回结点,无则返回NULL
	if(s==NULL){
		printf("查找的结点为NULL!\n");
	}else{
		PrintNode(s);//输出该结点的查找结果 
	}
	printf("【按位序查找结点】请输入位序i:");
	scanf("%d",&i);
	s=GetElem(L3,i); //按位序查找 ,有则返回结点,无则返回NULL
	if(s==NULL){
		printf("查找的结点为NULL!\n");
	}else{
		PrintNode(s);//输出该结点的查找结果 
	}
}

运行结果

这是空链表!
表长为:0
这是空链表!
表长为:0
这是空链表!
表长为:0
--------------------------------------------------------
头插法构建链表:(以空格间隔、9999结束)
5 4 3 2 1 9999
表长为:5
1
2
3
4
5
【按位序插入】
请输入要插入的位序i:3
请输入要插入的值e:55
插入成功,插入结点后的链表:
表长为:6
1
2
55
3
4
5
--------------------------------------------------------
尾插法构建链表:(以空格间隔、9999结束)
1 2 3 4 5 9999
表长为:5
1
2
3
4
5
【按位序删除】
请输入要删除的位序i:4
删除成功,删除的值为:4
删除结点后的链表:
表长为:4
1
2
3
5
【按值删除】
请输入要删除的值e:1
删除成功,删除的值为:1
删除结点后的链表:
表长为:3
2
3
5
--------------------------------------------------------
尾插法构建链表:(以空格间隔、9999结束)
1 2 3 4 5 9999
表长为:5
1
2
3
4
5
【按值查找结点】请输入要查找的值e:2
查找的结点为:2
【按位序查找结点】请输入位序i:6
查找的结点为NULL
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Selcouther

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值