C语言入门学习——链表(1)

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
在这里插入图片描述
每一个结构体类型都有两个成员,一个用于存储需要的数据,一个负责指向下一个结构体的地址,使他们之间链接起来,这里以无头不循环单链表来学习

在这里插入图片描述

头文件的创建

#ifndef SLIST_H
#define SLIST_H

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int code;						方便更改数据类型
typedef struct SLTNode
{
	code data;
	struct SLTNode* next;

}STL;
#endif SLIST_H

先防重定义,在把可能用到的头文件放到该目录下,之后创建一个结构体类型及其成员,必须要有一个结构体指针用与链接别的结构体

接口函数

下面创建需要的函数
先创建一个申请动态内存的函数

STL* STList_BuyListNodet(int data)
{
	STL* newcur = (STL*)malloc((sizeof(STL)));
	if(newcur == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newcur->data = data;
	newcur->next = NULL;
	return newcur;
}

用于接下来的尾增、头增、随机增

2.尾增

void STList_PushBack(STL** sp,int data)
{
	STL* newList = STList_BuyListNodet(data);
	STL* cur = *sp;
	if(cur == NULL)
	{
		*sp = newList;
	}
	else
	{
		while(cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = newList;
	}
}

在这里插入图片描述

3.尾删

void STList_PushBack(STL** sp)
{
	assert(*sp);
	STL* cur = *sp;
	if(cur->next == NULL)
	{
		free(cur);
		*sp = NULL;
	}
	else
	{
		STL* del = NULL;
		while(cur->next)
		{
			del = cur;
			cur = cur->next;
		}
		free(cur);
		del->next = NULL;
	}
}

在这里插入图片描述

4.打印
方便调试,创建好一个函数就调试一次

void STList_print(STL* sp)
{
	STL* cur = sp;
	while(cur)
	{
		printf("%d -> ",cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

5.头增

void STList_PushFront(STL** sp,int x)
{
	STL* newList = STList_BuyListNodet(data);
	newList->next = *sp;
	*sp = newList;
}

在这里插入图片描述

6.头删

void STList_PopFront(STL** sp)
{
	assert(*sp);
	STL* cur = *sp;
	*sp = cur->next;
	free(cur);
}

在这里插入图片描述

7.查找

STL* STList_find(STL* sp,int data)
{
	STL* cur = sp;
	while(cur)
	{
		if(cur->data == data)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

8.随机增(头)
需要考虑如果是头指针指向的地址该如何处理

void SList_Front(STL** sp,STL* pos,int x)
{
	STL* newList = STList_BuyListNodet(data);
	STL* cur = *sp;
	if(pos == *sp)
	{
		newList->next = *sp;
		*sp = newList;
	}
	else
	{
		while(cur->next != pos)
		{
			cur = cur->next;
		}
		newList->next = pos;
		cur->next = newList;
	}
}

在这里插入图片描述

9.随机增(尾)

void SList_Back(STL** sp,STL* pos,int x)
{
	STL* newList = STList_BuyListNodet(data);
	newList->next = pos->next;
	pos->next = newList;
}

10.指定删
需要考虑如果是删除第一个地址该如何处理

void SList_Pop(STL** sp,STL* pos)
{
	assert(*sp);
	STL* cur = *sp;
	if(pos == *sp)
	{
		*sp = pos->next;
		free(cur);
	}
	else
	{
		while(cur->next != pos)
		{
			cur = cur->next;
		}
		cur->next = pos->next;
		free(pos);
	}
}

在这里插入图片描述

11.全部释放

void SList_Destory(STL** sp)
{
	STL* cur = *sp;
	STL* del = NULL;
	while(cur)
	{
		del = cur;
		cur = cur->next;
		free(del);
	}
	*sp = NULL;
}

一些功能的复用

1.查找+指定删

STL* data;
STL* pos = NULL;
while( pos = STList_find(data,4) )
{
	SList_Pop(data,pos);
}

//STL* STList_find(STL* sp,int data)
//void SList_Pop(STL** sp,STL* pos)

2.头删复用指定删

void STList_PopFront(STL** sp)
{
	assert(*sp);
	
	if(*sp->next == NULL)
	{
		SList_Pop(sp,*sp);
		*sp = NULL;
	}
	else
	{
		SList_Pop(sp,*sp);
	}
	
}

3.头增复用随机增(头)

void STList_PushFront(STL** sp,int x)
{
	SList_Front(STL** sp,*sp,x);
}

完成后的头文件

#ifndef SLIST_H
#define SLIST_H

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int code;
typedef struct SLTNode
{
	code data;
	struct SLTNode* next;

}STL;
//打印
void STList_print(STL* sp);
//尾增
void STList_PushBack(STL** sp,int x);
//尾删
void STList_PopBack(STL** sp);
//头增
void STList_PushFront(STL** sp,int x);
//头删
void STList_PopFront(STL** sp);
//查找
STL* SList_find(STL** sp,int x);
//指定插入(头)
void SList_Front(STL** sp,STL* pos,int x);
//指定删除
void SList_Pop(STL** sp,STL** pos);
//指定插入(尾)
void SList_Back(STL** sp,STL* pos,int x);
//全部释放
void SList_Destory(STL** sp);

#endif SLIST_H

小结:
1.形参是二级指针的意义:
若传递的是一级指针,假如传进来的一级指针是NULL,那么形参是实参的临时拷贝也为NULL,申请的动态内存地址被形参保存,不会改变实参,在函数结束时,临时变量会随机销毁(将在栈区临时开辟的内存返回给栈帧)而动态内存(堆区)的地址并未被释放,内存的入口也没作为返回值返回的话,就会造成内存泄漏
若形参的是二级指针时,传递的是一级指针的地址,当一级指针为NULL,可以通过解引用间接访问到一级指针本身
2.对于尾增需要考虑如果是当前为NULL该怎么处理,尾删则要考虑剩最后一个地址怎么处理
3.通过上面那些函数可以看出,不循环单链表对于尾删尾增都需要遍历到最后位置,尾删还需要一个指针保存前一个位置,比较麻烦;而头增头删很方便,也不需要考虑其他特殊情况

4.在实际编写时,最好是写完一个模块就测试一个模块
5.除非特别熟练,否则应该边画图边编写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值