一.定义
1.线性表的链式存储就是单链表,单链表通过一组任意的存储单元来存储线性表的数据元素(逻辑相邻,存储离散),单链表对于每一个链表结点,不但存储自身数据,还开辟了存储一个指向后继结点的指针。
2.单链表相比顺序表:
优点:解决了顺序表需要大量连续存储单元的问题,单链表的数据元素离散的分布在存储空间中。
缺点:需要额外的存储空间存放指针域。
3.建立单链表可以使用头插法和尾插法两种操作,其中头插法创建的单链表数据有逆置效果。
头插法:
尾插法:
4.创建单链表可以使用头结点方便编码,也可以不使用头结点,本代码使用了头结点。
二.代码
1.使用头插法建立单链表
LinkList AddList(LinkList L){//头插法增添元素 L = (LinkList)malloc(sizeof(LNode));//创建头结点L->length = 0;L->next=NULL;LNode *addPoint;int addNum;printf("向链表输入初始值\n");printf("请输入要插入的内容:");scanf("%d",&addNum);//获取插入内容 while(addNum != 99){//当输入99时结束循环 addPoint = (LNode *)malloc(sizeof(LNode));L->length++;addPoint->next = L->next;L->next = addPoint;addPoint->data = addNum;printf("\n请输入要插入的内容(输入99结束):");//继续输入新元素 scanf("%d",&addNum);//获取插入内容 }return L;}
2.遍历展示单链表
void ShowList(LinkList L){LNode *x;//定义一个指针 int num = L->length;//num用于暂存该链表长度 printf("该链表一共有%d个元素\n",num);
// x = (LNode *)malloc(sizeof(LNode)); x = L;//将头结点的信息赋给x x = x->next;//跳过头结点,因为头结点不存储数据 while(num>0){printf("%d\n",x->data);//输出该节点的数据 x = x->next;//移向下一个结点 num--;//遍历总数减一 }
}
3.插入数据元素
bool ListInsert(LinkList L){int inputPosition = 0;//定义记录插入位置并初始化 int inputNum = 0;//定义记录插入数据元素的值并初始化 printf("请输入要插入的位置:");scanf("%d",&inputPosition);//获取插入位置 printf("请输入要插入的内容:");scanf("%d",&inputNum);//获取插入内容 if(inputPosition<1){//插入位置不能小于1 return false;}LNode *AtPresent;// 定义指向当前遍历到的结点的指针 (遍历指针) int record = 0;//记录该节点的位置 AtPresent = L;// 让 遍历指针指向头结点 while(AtPresent!=NULL&&record < inputPosition-1){//遍历条件:1.当前指针不为空 2.当前结点与目标结点位置不匹配 record++;//位置信息累加 AtPresent=AtPresent->next;//遍历指针指向下一个结点 }if(AtPresent==NULL){//若遍历指针为空,则该链表没有目标位置结点 return false;}//找到目标位置后: LNode *s = (LNode *)malloc(sizeof(LNode));//生成一个新结点 s->data = inputNum;//新结点赋值 s->next = AtPresent->next;//新结点的后继指针指向遍历结点的后继结点 AtPresent->next = s;// 遍历结点的后继指针指向新结点 L->length++;//长度+1 return true;
}
4.按位查找(两种方法的区别在于返回值)
代码一:
bool GetElem(LinkList L){//按位查找 int getPos = 0;//定义输入位置变量 printf("请输入要查找的位置:");scanf("%d",&getPos);//获取查找位置 LNode *x;//定义遍历指针 x = L;//将链表头指针位置赋给x x = x->next;//头结点没有取值,因此跳过 if(getPos<1||getPos>L->length){//判断输入是否合法 return false;}for(int curPos = 1;curPos<getPos;curPos++){//遍历位置 x=x->next;}if(x==NULL){//没有找到 return false;}printf("第%d位置元素为%d\n",getPos,x->data);return true;
}
代码二:
LinkList GetNodeElem(LinkList L,int findPos){int record = 1;//记录位置LNode *searchPoint = L->next;//使遍历指针指向第一个结点 if(findPos==0){return L;//返回头结点 } else if(findPos<1){return NULL;}while(searchPoint&&record<findPos){searchPoint = searchPoint->next;record++;}return searchPoint;
}
5.按值查找
代码一:
bool LocateElem(LinkList L){//按值查找int getNum = 0;int accumulation = 0;printf("请输入要查找的值:");scanf("%d",&getNum);//获取要查询的值LNode *x;//定义遍历指针 x = L;x = x->next; for(int record = 1;record<L->length;record++){//遍历链表if(x->data == getNum){printf("第%d个位置存储了%d\n",record,getNum);accumulation++;}x = x->next;}if(accumulation>0){printf("链表中有%d个%d值\n",accumulation,getNum);return true;}else{printf("链表中没有%d\n",getNum);return false;}}
代码二:
LinkList LocateNodeElem(LinkList L,int findNum){//按值查找LNode *searchNumP = L->next;//获取第一个结点的位置int record = 1;while(searchNumP!=NULL&&searchNumP->data!=findNum){searchNumP = searchNumP->next;record++;}printf("值%d的位置是%d",searchNumP->data,record);return searchNumP;}
6.删除操作
void DelList(LinkList L){//删除操作int delPos = 0;//定义删除位置变量 printf("\n请输入要删除的位置:");scanf("%d",&delPos);//获取删除位置 LNode *x,*y;x = GetNodeElem(L,delPos-1);//查找要删除位置的前驱结点 y = x->next;//要删除的结点 x->next = y->next;//将前驱结点的后继改为删除结点的后继 L->length--;//链表长度-1 free(y);//释放被删除元素的空间
}
三.整体代码
//头插法实现单链表
#include <stdio.h>
#include <stdlib.h>typedef struct LNode{int data;//每个结点存放的数据元素 int length;struct LNode *next;//指向的下一个结点
}LNode,*LinkList;//均表示一个指向单链表第一个结点的指针
//LNode 强调第一个结点
//LinkList 强调表示的是一个单链表 LinkList AddList(LinkList L){//头插法增添元素 L = (LinkList)malloc(sizeof(LNode));//创建头结点L->length = 0;L->next=NULL;LNode *addPoint;int addNum;printf("向链表输入初始值\n");printf("请输入要插入的内容:");scanf("%d",&addNum);//获取插入内容 while(addNum != 99){//当输入99时结束循环 addPoint = (LNode *)malloc(sizeof(LNode));L->length++;addPoint->next = L->next;L->next = addPoint;addPoint->data = addNum;printf("\n请输入要插入的内容(输入99结束):");//继续输入新元素 scanf("%d",&addNum);//获取插入内容 }return L;}
bool ListInsert(LinkList L){int inputPosition = 0;//定义记录插入位置并初始化 int inputNum = 0;//定义记录插入数据元素的值并初始化 printf("请输入要插入的位置:");scanf("%d",&inputPosition);//获取插入位置 printf("请输入要插入的内容:");scanf("%d",&inputNum);//获取插入内容 if(inputPosition<1){//插入位置不能小于1 return false;}LNode *AtPresent;// 定义指向当前遍历到的结点的指针 (遍历指针) int record = 0;//记录该节点的位置 AtPresent = L;// 让 遍历指针指向头结点 while(AtPresent!=NULL&&record < inputPosition-1){//遍历条件:1.当前指针不为空 2.当前结点与目标结点位置不匹配 record++;//位置信息累加 AtPresent=AtPresent->next;//遍历指针指向下一个结点 }if(AtPresent==NULL){//若遍历指针为空,则该链表没有目标位置结点 return false;}//找到目标位置后: LNode *s = (LNode *)malloc(sizeof(LNode));//生成一个新结点 s->data = inputNum;//新结点赋值 s->next = AtPresent->next;//新结点的后继指针指向遍历结点的后继结点 AtPresent->next = s;// 遍历结点的后继指针指向新结点 L->length++;//长度+1 return true;
}
void ShowList(LinkList L){LNode *x;//定义一个指针 int num = L->length;//num用于暂存该链表长度 printf("该链表一共有%d个元素\n",num);
// x = (LNode *)malloc(sizeof(LNode)); x = L;//将头结点的信息赋给x x = x->next;//跳过头结点,因为头结点不存储数据 while(num>0){printf("%d\n",x->data);//输出该节点的数据 x = x->next;//移向下一个结点 num--;//遍历总数减一 }
}
bool GetElem(LinkList L){//按位查找 int getPos = 0;//定义输入位置变量 printf("请输入要查找的位置:");scanf("%d",&getPos);//获取查找位置 LNode *x;//定义遍历指针 x = L;//将链表头指针位置赋给x x = x->next;//头结点没有取值,因此跳过 if(getPos<1||getPos>L->length){//判断输入是否合法 return false;}for(int curPos = 1;curPos<getPos;curPos++){//遍历位置 x=x->next;}if(x==NULL){//没有找到 return false;}printf("第%d位置元素为%d\n",getPos,x->data);return true;
}bool LocateElem(LinkList L){//按值查找int getNum = 0;int accumulation = 0;printf("请输入要查找的值:");scanf("%d",&getNum);//获取要查询的值LNode *x;//定义遍历指针 x = L;x = x->next; for(int record = 1;record<L->length;record++){//遍历链表if(x->data == getNum){printf("第%d个位置存储了%d\n",record,getNum);accumulation++;}x = x->next;}if(accumulation>0){printf("链表中有%d个%d值\n",accumulation,getNum);return true;}else{printf("链表中没有%d\n",getNum);return false;}} LinkList GetNodeElem(LinkList L,int findPos){int record = 1;//记录位置LNode *searchPoint = L->next;//使遍历指针指向第一个结点 if(findPos==0){return L;//返回头结点 } else if(findPos<1){return NULL;}while(searchPoint&&record<findPos){searchPoint = searchPoint->next;record++;}return searchPoint;
}
LinkList LocateNodeElem(LinkList L,int findNum){//按值查找LNode *searchNumP = L->next;//获取第一个结点的位置int record = 1;while(searchNumP!=NULL&&searchNumP->data!=findNum){searchNumP = searchNumP->next;record++;}printf("值%d的位置是%d",searchNumP->data,record);return searchNumP;}
void DelList(LinkList L){//删除操作int delPos = 0;//定义删除位置变量 printf("\n请输入要删除的位置:");scanf("%d",&delPos);//获取删除位置 LNode *x,*y;x = GetNodeElem(L,delPos-1);//查找要删除位置的前驱结点 y = x->next;//要删除的结点 x->next = y->next;//将前驱结点的后继改为删除结点的后继 L->length--;//链表长度-1 free(y);//释放被删除元素的空间
}int main(){LinkList L;//声明一个指向单链表的指针
// InitList(L);//初始化链表 L = AddList(L);//批量向链表添加数据 并且完成初始化 ShowList(L);//展示链表 ListInsert(L); //按位插入 ShowList(L);//展示链表//方法一,返回布尔类型 GetElem(L);//按位查找 (方法一)LocateElem(L);//按值查找(方法一)//方法二:返回结点
// int findPos=5;
// int findNum=1;
// LNode *searchPoint;
// LNode *searchNumP;
// searchPoint = GetNodeElem(L,findPos);//按位查找
// if(searchPoint!=NULL){
// printf("%d位置上的元素值为%d\n",findPos,searchPoint->data);
// }
// searchNumP = LocateNodeElem(L,findNum); //按值查找 DelList(L);//删除操作ShowList(L);}