本文代码为学习总结,如果错误敬请指正!感谢各位大佬 😃
文章目录
带头结点的单链表
结点定义
/*使用 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!