c语言学习---链表的增删查改(瞎子都能看懂)

一.介绍

  1. 格式
    在这里插入图片描述
  • 尾结点为NULL

二.增删查改(风险与机遇并存)

  • 头指针:phead
  • 尾指针:ptail
  • 链表可以只有头指针
    如何"定义"链表?
  1. 定义头指针,尾指针,要插入的值.两个指针表示链表,自己幻想一下
  2. 头指针尾指针要赋值为NULL,要插入的值其实是自己输入的值
  3. 循环输入要插入的值,循环体里是调用的函数
    在这里插入图片描述

1.插入

结构体怎么写:
1.要有值,整型,字符型之类的值
2.要有指向下一结点的指针
3.要定义别名,普通别名,指针类型别名
函数在这里插入图片描述
函数声明怎么写?

  1. 定义头指针,定义尾指针,定义要插入的值
  2. 函数声明中类型必须写,形参可以不写
  3. 头指针和尾指针都是二级指针,通过对二级指针取地址,得到一级指针,也就是结点中值的地址,eg:*头节点=新结点的地址
    在这里插入图片描述
  • 一开始头指针和尾指针都是NULL

1.头插法

插入方法:

  1. 定义一个新结构体结点(火车车厢)
  2. 为该结构体结点申请空间
  3. 将该结构体结点的内存全部清0(让新结点的pNext为空)
  4. 将插入的值传到该结构体结点中对应的值中
  5. 如果链表为空:头结点和尾结点都指向该结点(结构体的变量名,代表该结构体的首地址)
  6. 如果链表不为空:先将原有链表的头指针,赋给新结点的pNext((pNext是结构体里自带的指向下一结点地址的指针,已定义),再将新结点作为链表头
    在这里插入图片描述

2.尾插法

插入方法:

  1. 定义一个新结构体结点(火车车厢)
  2. 为该结构体结点申请空间
  3. 将该结构体结点的内存全部清0(让新结点的pNext为空)
  4. 将插入的值传到该结构体结点中对应的值中
  5. 如果链表为空:头结点和尾结点都指向该结点(结构体的变量名,代表该结构体的首地址)
  6. 如果链表不为空:先将新结点的地址,赋给原有链表的尾指针的pNext,再将新结点作为尾指针

在这里插入图片描述
在这里插入图片描述

3. 有序插入法

插入方法:

  1. 定义一个新结构体结点(火车车厢)

  2. 为该结构体结点申请空间

  3. 将该结构体结点的内存全部清0(让新结点的pNext为空)

  4. 将插入的值传到该结构体结点中对应的值中

  5. 如果链表为空:头结点和尾结点都指向该结点(结构体的变量名,代表该结构体的首地址)

  6. 在这里插入图片描述

  7. 链表不为空:这时有三种情况考虑

  • pcur是当前的结点,ppre是上一个结点,pcur要往下一个结点,前提是ppre=pcur;然后pcur=pcur->pNext
    在这里插入图片描述
  1. 判断插入值是否小于头部数据(第一个数据),若是则插入头部,头插法
    在这里插入图片描述

  2. 若不小于第一个数据,则和下一个结点进行比较,或下下个,直到找到比插入值大的数,然后插在该数的前面.新结点的指针插入该节点前面,前一个结点的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),则退出进行到下一过程
    在这里插入图片描述
  1. 实在找不到比插入值大的,就插到末尾,尾插法

在这里插入图片描述
11. 顺序,逆序插入,自己画图比划一下就行
在这里插入图片描述

2.删除

  • 删除不需要申请空间,需要释放空间
    方法
  1. 先判断链表是否为空,为空的话直接打印链表为空
    在这里插入图片描述

  2. 不为空的话,开始从链表中查找删除值

  3. 先比较链表的第一个结点,是该结点.

  4. 如果该链表只有一个元素,那么删除该链表后,尾指针=NULL.
    在这里插入图片描述

  5. 如果链表有很多元素,将第二个结点赋为头节点,free()第一个结点.

  6. 如果不是第一个结点,而是中间结点,且找到了该结点,那么将该结点的pNext赋给前一结点的pNext,然后free()该结点
    在这里插入图片描述
    在这里插入图片描述

  7. 如果第二个节点不是,则继续遍历,ppre=pcur;pcur=pcur->pNext;

  8. 如果是最后一个节点,则此时:pcur->pNext = NULL; ppre->pNext = pcur->pNext;则ppre->pNext = NULL;,再free()最后一个节点,这时ppre也就成了尾指针
    在这里插入图片描述

  9. 如果在节点中没有找到,此时pcur = pcur->pNext = NULL;就可打印无此节点了

3.查改

函数声明:

在这里插入图片描述
在这里插入图片描述
方法:(修改5号学生的分数)

  1. 假设修改值在链表中,遍历链表

  2. 如果第一个节点的值就是5号,那么直接修改该节点的分数在这里插入图片描述

  3. 如果是中间的节点,则继续遍历下一个,phead = phead->pNext,找到后该值在这里插入图片描述

  4. 当找到倒数第二个的时候,phead = phead->pNext;,这时phead指向最后一个节点,去和5比较,不是的话继续,phead = phead->pNext=NULL;此时phead=NULL在这里插入图片描述

  5. phead=NULL;,即没有找到该结点

4.遍历链表内容,打印

  • 函数声明
    在这里插入图片描述

  • 打印方法

  1. 传入链表首地址
  2. 从链表的头指针开始读,尾指针为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");
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

毕竟是shy哥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值