一.介绍
- 格式
- 尾结点为NULL
二.增删查改(风险与机遇并存)
- 头指针:phead
- 尾指针:ptail
- 链表可以只有头指针
如何"定义"链表?
- 定义头指针,尾指针,要插入的值.两个指针表示链表,自己幻想一下
- 头指针尾指针要赋值为NULL,要插入的值其实是自己输入的值
- 循环输入要插入的值,循环体里是调用的函数
1.插入
结构体怎么写:
1.要有值,整型,字符型之类的值
2.要有指向下一结点的指针
3.要定义别名,普通别名,指针类型别名
函数
函数声明怎么写?
- 定义头指针,定义尾指针,定义要插入的值
- 函数声明中类型必须写,形参可以不写
- 头指针和尾指针都是二级指针,通过对二级指针取地址,得到一级指针,也就是结点中值的地址,eg:*头节点=新结点的地址
- 一开始头指针和尾指针都是NULL
1.头插法
插入方法:
- 定义一个新结构体结点(火车车厢)
- 为该结构体结点申请空间
- 将该结构体结点的内存全部清0(让新结点的pNext为空)
- 将插入的值传到该结构体结点中对应的值中
- 如果链表为空:头结点和尾结点都指向该结点(结构体的变量名,代表该结构体的首地址)
- 如果链表不为空:先将原有链表的头指针,赋给新结点的pNext((pNext是结构体里自带的指向下一结点地址的指针,已定义),再将新结点作为链表头
2.尾插法
插入方法:
- 定义一个新结构体结点(火车车厢)
- 为该结构体结点申请空间
- 将该结构体结点的内存全部清0(让新结点的pNext为空)
- 将插入的值传到该结构体结点中对应的值中
- 如果链表为空:头结点和尾结点都指向该结点(结构体的变量名,代表该结构体的首地址)
- 如果链表不为空:先将新结点的地址,赋给原有链表的尾指针的pNext,再将新结点作为尾指针
3. 有序插入法
插入方法:
-
定义一个新结构体结点(火车车厢)
-
为该结构体结点申请空间
-
将该结构体结点的内存全部清0(让新结点的pNext为空)
-
将插入的值传到该结构体结点中对应的值中
-
如果链表为空:头结点和尾结点都指向该结点(结构体的变量名,代表该结构体的首地址)
-
链表不为空:这时有三种情况考虑
- pcur是当前的结点,ppre是上一个结点,pcur要往下一个结点,前提是ppre=pcur;然后pcur=pcur->pNext
-
判断插入值是否小于头部数据(第一个数据),若是则插入头部,头插法
-
若不小于第一个数据,则和下一个结点进行比较,或下下个,直到找到比插入值大的数,然后插在该数的前面.新结点的指针插入该节点前面,前一个结点的pNext指向新结点
- 这里为什么是while(pCur)呢?(2,5,8)
- 不为空时,先和第一个结点比较,此时发现比第一个结点大,然后和下一个结点比较,假如插入值时6.此时pcur还是指向第一个结点,6比2大,然后和下一个比较,这时pcur进入while,此时if(6<2),不进入if语句,然后执行下面语句,目前pcur和ppre指向的都是头指针,但还是多运行了一次ppre的赋值,然后pcur指向下一个结点,再次进入while,if(6<5),不进入if,此时ppre指向5,然后pcur指向8,然后再进入while,然后if(6<8),此时pnew插入在ppre和pcur之间.然后break.
- 如果插入10,则if(10<8),此时ppre指向尾结点,pcur->pNext为NULL,也就是此时pcur=NULL,再次进入whil(NULL),则退出进行到下一过程
- 实在找不到比插入值大的,就插到末尾,尾插法
11. 顺序,逆序插入,自己画图比划一下就行
2.删除
- 删除不需要申请空间,需要释放空间
方法
-
先判断链表是否为空,为空的话直接打印链表为空
-
不为空的话,开始从链表中查找删除值
-
先比较链表的第一个结点,是该结点.
-
如果该链表只有一个元素,那么删除该链表后,尾指针=NULL.
-
如果链表有很多元素,将第二个结点赋为头节点,free()第一个结点.
-
如果不是第一个结点,而是中间结点,且找到了该结点,那么将该结点的pNext赋给前一结点的pNext,然后free()该结点
-
如果第二个节点不是,则继续遍历,ppre=pcur;pcur=pcur->pNext;
-
如果是最后一个节点,则此时:pcur->pNext = NULL; ppre->pNext = pcur->pNext;则ppre->pNext = NULL;,再free()最后一个节点,这时ppre也就成了尾指针
-
如果在节点中没有找到,此时pcur = pcur->pNext = NULL;就可打印无此节点了
3.查改
函数声明:
方法:(修改5号学生的分数)
-
假设修改值在链表中,遍历链表
-
如果第一个节点的值就是5号,那么直接修改该节点的分数
-
如果是中间的节点,则继续遍历下一个,phead = phead->pNext,找到后该值
-
当找到倒数第二个的时候,phead = phead->pNext;,这时phead指向最后一个节点,去和5比较,不是的话继续,phead = phead->pNext=NULL;此时phead=NULL
-
phead=NULL;,即没有找到该结点
4.遍历链表内容,打印
-
函数声明
-
打印方法
- 传入链表首地址
- 从链表的头指针开始读,尾指针为NULL,读完这个头指针,就把pNext作为头指针,知道尾指针
三.总代码部分
1.定义func.h
#include<stdio.h>
#include<stdlib.h>
typedef struct student{
int num;
float score;
struct student *pNext;
}Student_t,*pStudent_t;
void listHeadInsert(pStudent_t *,Student_t **,int val);
void listTailInsert(pStudent_t *,Student_t **,int val);
void listSortInsert(pStudent_t *,Student_t **,int val);
void listDelete(pStudent_t *,Student_t **,int val);
void listModify(pStudent_t ,int, float);
void listPrint(pStudent_t);
2.list.c
#include"list.h"
//链表头插法
void listHeadInsert(pStudent_t *ppHead,Student_t **ppTail,int val)
{
pStudent_t pNew=(pStudent_t)calloc(1,sizeof(Student_t));//calloc可以全部置零
pNew->num=val;
if(NULL==*ppHead)//判断链表是否为空
{
*ppHead=pNew;
*ppTail=pNew;
}else{
pNew->pNext=*ppHead;
*ppHead=pNew;
}
}
//链表打印
void listPrint(pStudent_t pHead)
{
while(pHead)
{
printf("%3d %5.2f\n",pHead->num,pHead->score);
pHead=pHead->pNext;
}
printf("\n");
}
//链表尾插法
void listTailInsert(pStudent_t *ppHead,Student_t **ppTail,int val)
{
pStudent_t pNew=(pStudent_t)calloc(1,sizeof(Student_t));//calloc可以全部置零
pNew->num=val;
if(NULL==*ppTail)//判断链表是否为空
{
*ppHead=pNew;
*ppTail=pNew;
}else{
(*ppTail)->pNext=pNew;
*ppTail=pNew;
}
}
//链表有序插入
void listSortInsert(pStudent_t *ppHead,Student_t **ppTail,int val)
{
pStudent_t pNew=(pStudent_t)calloc(1,sizeof(Student_t));//calloc可以全部置零
pStudent_t pCur,pPre;
pCur=pPre=*ppHead;
pNew->num=val;
if(NULL==pCur)//判断链表是否为空
{
*ppHead=pNew;
*ppTail=pNew;
}else if (val<pCur->num)//头插法
{
pNew->pNext=pCur;
*ppHead=pNew;
}else
{
while(pCur)//插入到中间
{
if(pCur->num>val)
{
pPre->pNext=pNew;
pNew->pNext=pCur;
break;
}
pPre=pCur;
pCur=pCur->pNext;
}
if(NULL==pCur)//这时插入到尾部
{
pPre->pNext=pNew;
*ppTail=pNew;
}
}
}
//链表的删除
void listDelete(pStudent_t *ppHead,Student_t **ppTail,int deleteNum)
{
pStudent_t pCur=*ppHead,pPre;
pPre=pCur;
if(NULL==pCur){
printf("List is empty\n");
return;
}else if(pCur->num==deleteNum){//删除的是头部
*ppHead=pCur->pNext;
if(NULL==*ppHead){
*ppTail=NULL;
}
}else{
while(pCur){//删除的之间或尾部
if(pCur->num==deleteNum){
pPre->pNext=pCur->pNext;
break;
}
pPre=pCur;
pCur=pCur->pNext;
}
if(NULL==pCur){ //没有找到对应结点
printf("Don't find this deleteNum\n");
return;
}
if(pCur==*ppTail){
*ppTail=pPre;
}
}
free(pCur);
pCur=NULL;
}
void listModify(pStudent_t pHead,int num, float score)
{
while(pHead)
{
if(pHead->num==num){
pHead->score=score;
break;
}
pHead=pHead->pNext;
}
if(NULL==pHead){
printf("Don't find modify num\n");
}
}
3.main.c
#include"list.h"
int main()
{
pStudent_t phead=NULL,ptail=NULL;
int num;
float score;
while(scanf("%d",&num)!=EOF)
{
//listHeadInsert(&phead,&ptail,num);
//listTailInsert(&phead,&ptail,num);
listSortInsert(&phead,&ptail,num);
}
listPrint(phead);
//fflush(stdout);//刷新标准输出
//while(printf("please input delete num:"),fflush(stdout),scanf("%d",&num)!=EOF){
// listDelete(&phead,&ptail,num);
// listPrint(phead);
//}
while(printf("please input modify num and score:"),fflush(stdout),scanf("%d%f",&num,&score)!=EOF){
listModify(phead,num,score);
listPrint(phead);
}
system("pause");
}