【数据结构】:单链表之增删改查求表长(带头结点和不带头结点均有)
对单链表的增删改查求表长、C语言、有图解、带头结点和不带头结点
·
单链表的增删改查
一、带头结点
1️⃣创建
本文代码创建部分使用的是带头结点的尾插法,若想要使用其他的方法,可查看单链表之头插法和尾插法
❗❗ 重点一:以尾插法实现单链表的创建
- 动图解析
- 图解
- 代码
LinkList TailInster(LinkList &L,int n){ int x=1; L= (LinkList)malloc(sizeof(LNode)); LNode *s,*r=L; while(x!=n){ s=(LNode*) malloc(sizeof(LNode)); s->data=x; r->next=s; r=s; x++; } r->next=NULL; return L; }
2️⃣查——查找某个结点
- 查找分为两种方式:
💡按序号查找
💡按值查找 - 基本思想
单链表是的元素是离散的分布
在存储空间,所以不能直接找到表中某个特定的结点,查找时,需要从表头开始遍历
❗❗ 重点二:按序号查找结点(例子:找序号为2的结点)
- 图解
- 代码解析
- 💡
j
的作用 :结束while循环,返回对应结点,j
表示目前指针p
位于第几个结点的位置,用j==i
来结束while循环(j==0
表示,p
指向头结点)
- 💡
p==Null
的情况:不存在该结点,指针p遍历到了链尾,也没有找到对应的序号。
- 代码
/*查找——按序*/ LNode* GetElem(LinkList L,int i){ //i——序号 if (i<1) return NULL; LNode *p; int j=0; p=L; while(p!=NULL&&j<i){ p=p->next; j++; } return p; }
❗❗ 重点三:按值查找结点
图解和解析参考重点二,
与按值查找相比,只是在循环条件中将j<i
改成了p->data!=e
- 代码
/*查找——按值*/ int LocateElem(LinkList L,ElemType e){ int i=0; LNode *p=L->next; while (p!=NULL&&p->data!=e){ p=p->next; i++; } if (i!=0)i++; return i; }
2.部分代码解析
i
的初值为什么设置成0
❓
i
的作用主要是记录结点的位置,当i==0时,就代表该结点不存在
。
3️⃣增——插入结点
插入结点的原理类似于头插法
- 基本思想
找到要插入的位置的前一个位置(i-1)
,插入结点- 图解(4 5 顺序不可以调换呦)
- 代码
/*增加--插入*/ bool ListInster(LinkList &L,int i,ElemType e){ LNode *p= GetElem(L,i-1); //找到i结点的前一个结点 if (p==NULL)return false; LNode *s=(LNode*) malloc(sizeof(LNode)); s->data=e; s->next=p->next; p->next=s; return true; }
4️⃣删——删除结点
删除时,也要找到被删除位置的前一个结点。
- 图解
- 代码
/*删除*/ bool ListDelete(LinkList &L,int i,ElemType &e){ LNode *p= GetElem(L,i-1); if (p==NULL)return false; LNode *q=p->next; e=q->data; p->next=q->next; free(q); return true; }
- 💡
e
的作用:用来记录被删除的结点的值域
5️⃣改——修改结点
只要找到要修改结点的结点,将其值换成要修改的值就可以啦
/*修改*/
bool UpgreatList(LinkList &L,int i,ElemType e){
LNode *p= GetElem(L,i);
if (p==NULL)return false;
p->data=e;
return true;
}
6️⃣求表长
求表长的本质也是一种遍历
- 💡
s
的作用:通过s
从表头遍历到表尾(s==null
),获得表长 - 💡
x
的作用:记录表长
/*求表长*/
int Length(LinkList L){
int x=0;
LNode *s=L->next;//指向首元结点,以免将头结点算在表长中
while (s!=NULL){
x++;
s=s->next;
}
return x;
}
7️⃣完整代码
#include "stdio.h"
#include "stdlib.h"
typedef int ElemType;
typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
/*尾插*/
LinkList CreateTail(LinkList &L,int n){
int x=1;
L= (LinkList)malloc(sizeof(LNode));
LNode *s,*r=L;
while(x<=n){
s=(LNode*) malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
x++;
}
r->next=NULL;
return L;
}
/*查找——按序*/
LNode* GetElem(LinkList L,int i){ //i——序号
if (i<1) return NULL;
LNode *p; //指针p当前扫描到的结点
int j=0; //当前p指向的是第几个结点,0表示头结点
p=L;
while(p!=NULL&&j<i){
p=p->next;
j++;
}
return p;
}
/*查找——按值*/
int LocateElem(LinkList L,ElemType e){
int i=0;
LNode *p=L->next;
while (p!=NULL&&p->data!=e){
p=p->next;
i++;
}
if (i!=0)i++;
return i;
}
/*增加--插入*/
bool ListInster(LinkList &L,int i,ElemType e){
LNode *p= GetElem(L,i-1);
if (p==NULL)return false;
LNode *s=(LNode*) malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return true;
}
/*修改*/
bool UpgreatList(LinkList &L,int i,ElemType e){
LNode *p= GetElem(L,i);
if (p==NULL)return false;
p->data=e;
return true;
}
/*删除*/
bool ListDelete(LinkList &L,int i,ElemType &e){
LNode *p= GetElem(L,i-1);
if (p==NULL)return false;
LNode *q=p->next;
e=q->data;
p->next=q->next;
free(q);
return true;
}
/*求表长*/
int Length(LinkList L){
int x=0;
LNode *s=L->next;
while (s!=NULL){
x++;
s=s->next;
}
return x;
}
/*便利*/
void PrintList(LinkList L){
LNode *s;
s=L->next;
while (s!=NULL) {
printf("%d ",s->data);
s=s->next;
}
}
int main(){
LinkList L;
printf("建立:");
CreateTail(L,10);
printf("\n建立后的链表:");
PrintList(L);
//求表长
printf("\n\n求表长:");
printf("\n表长为:%d",Length(L));
//查找
printf("\n\n求查询:");
LNode *p=GetElem(L,3);
if (p==NULL)printf("所找位置不存在!!");
else printf("\n第三个位置的元素是:%d",p->data);
printf("\n元素为5的结点在第%d个位置", LocateElem(L,5));
//插入
printf("\n\n插入:");
if(ListInster(L,5,11)){
printf("\n插入成功后的链表为:");
PrintList(L);
}else{
printf("\n插入失败");
}
//修改
printf("\n\n修改:");
if(UpgreatList(L,5,5)){
printf("\n修改成功后的链表为:");
PrintList(L);
}else{
printf("\n修改失败");
}
//删除
printf("\n\n删除:");
ElemType e;
if(ListDelete(L,5,e)){
printf("\n修改成功后的链表为:");
PrintList(L);
printf("\n删除的值为:%d",e);
}else{
printf("\n修改失败");
}
}
运行结果
二、不带头结点
只要注意在新建结点(例:s)
时,s
的指向是L(无头结点)
还是L->next(有头结点)
,其他可以参照带头结点的图。
代码
#include "stdio.h"
#include "stdlib.h"
typedef int ElemType;
typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
/*尾插*/
LinkList CreateTail(LinkList &L,int n){
int x=1;
L= (LinkList)malloc(sizeof(LNode));
L->data=x++;
LNode *s,*r=L;
while(x<=n){
s=(LNode*) malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
x++;
}
r->next=NULL;
return L;
}
/*查找——按序*/
LNode* GetElem(LinkList L,int i){ //i——序号
if (i<1) return NULL;
LNode *p; //指针p当前扫描到的结点
int j=1; //当前p指向的是第几个结点,0表示头结点
p=L;
while(p!=NULL&&j<i){
p=p->next;
j++;
}
return p;
}
/*查找——按值*/
int LocateElem(LinkList L,ElemType e){
int i=0;
LNode *p=L;
while (p!=NULL&&p->data!=e){
p=p->next;
i++;
}
if (i!=0)i++;
return i;
}
/*增加--插入*/
bool ListInster(LinkList &L,int i,ElemType e){
LNode *p= GetElem(L,i-1);
if (p==NULL)return false;
LNode *s=(LNode*) malloc(sizeof(LNode));
s->data=e;
s->next=p->next;
p->next=s;
return true;
}
/*修改*/
bool UpgreatList(LinkList &L,int i,ElemType e){
LNode *p= GetElem(L,i-1);
if (p==NULL)return false;
p->next->data=e;
return true;
}
/*删除*/
bool ListDelete(LinkList &L,int i,ElemType &e){
LNode *p= GetElem(L,i-1);
if (p==NULL)return false;
LNode *q=p->next;
e=q->data;
p->next=q->next;
free(q);
return true;
}
/*求表长*/
int Length(LinkList L){
int x=0;
LNode *s=L;
while (s!=NULL){
x++;
s=s->next;
}
return x;
}
/*便利*/
void PrintList(LinkList L){
LNode *s;
s=L;
while (s!=NULL) {
printf("%d ",s->data);
s=s->next;
}
}
int main(){
LinkList L;
CreateTail(L,10);
printf("建立后的链表:");
PrintList(L);
//求表长
printf("\n表长为:%d",Length(L));
//查找
printf("\n第三个位置的元素是:%d",GetElem(L,3)->data);
printf("\n元素为5的结点在第%d个位置", LocateElem(L,5));
//插入
if(ListInster(L,5,11)){
printf("\n插入成功后的链表为:");
PrintList(L);
}else{
printf("\n插入失败");
}
//修改
if(UpgreatList(L,5,5)){
printf("\n修改成功后的链表为:");
PrintList(L);
}else{
printf("\n修改失败");
}
//删除
ElemType e;
if(ListDelete(L,5,e)){
printf("\n修改成功后的链表为:");
PrintList(L);
printf("\n删除的值为:%d",e);
}else{
printf("\n修改失败");
}
}
运行截图
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献2条内容
所有评论(0)