希望你们都能遇到自己的米子哈和大kin库!!!!!!!!!!!!!!!!!!!!!!!
 
目录
1.单链表的简介
1.1结点
结点申请规则
单链表申请空间:
struct SListNode
{
int data;
SListNode*next;
} 
在我们想要存储一个整形数据时,实际先向内存申请一块空间,这个空间不仅要存放当前结点的数据,还存放着下一个结点的地址。(最后的结点存储的地址为NULL)
单链表和顺序表的对比
- 存储结构:
单链表的存储结构是非连续,非顺序的依靠地址的来寻找链表中的下一位数据。
顺序表在物理存储结构上是连续的,内存读取依次访问数据元素。 - 逻辑顺序:
单链表的逻辑顺序是依靠结点相连接的,
顺序标的逻辑顺序和物理顺序一样是紧挨着的。
 - 代码实现:
单链表的实现需要依靠指针,
顺序表可以不用指针,用访问符就能访问到数据。
 - 数据的存储:
在顺序表中,只需要开辟一系列的相邻的一块空间进行数据的存储。
在单链表中,每一个数据的位置都要申请,申请下来的空间叫做“结点”。 
图解

2、单链表的实现及其对应源码:
单链表的实现 :
2.1单链表的创建:
typedef int SLDataType
typedef struct SListNode
{
SLDataType  Data;
struct SListNode*next;
}sL;
 
以上代码是对链表结点结构的声明,该链表结点包括一个类型为SLDataType的整形数据和一个地址。
2.2.链表的申请结点
SL*SLTButNode(SLTDataType x)
{
SL*newnode=(SL*)malloc(sizeof(SL));
if(newnode==NULL)
{
perror("malloc fail");
exit(1);
}
newnode->data=x;
newnode->next=NULLl;
} 
我们用图表示一下:

2.3.单链表的打印
void SLprint(SL*phead)
{
SL*pucr=phead;
while(pcur)
{
printf("%d",pucr->next);
}
printf("NULL/n");
}
 
这下我们用图解:

这里有几个注意的点:
1.*phead一定是该链表中的第一个结点。
2.对pcur解引用拿到下一个结点的指针才能进入下一次循环,不然pcur走不动,打印陷入死循环。
2.4.链表的尾插
void SLTPushBack(SL**pphead,SLTDataType x)
{
assert(pphead);
SL*newnode=SLButNode(x);
if(*pphead==NULL)
{
*pphead=newnode;
}
else
{
 SL*pcur=*pphead;
while(pcur->next)
{
pucr=pucr->next;
}
pcur->next=newnode;
} 
如果*pphead是NULL时,说明该链表的头结点还没有建立,所以如果从对一个没有头节点的链表进行尾插,头节点就是尾插的目标。
当*pphead不是NULL的时,代表要在链表结点之后插入,为了更直观的感受,我们用图解的方式来解释:

2.5. 链表的头插
void SLTPushFront(SL**pphead,SLDataType x)
{
assert(pphead&&*pphead);
SL*newnode=SLBuynode(x);
newnode->next=*pphead;
*pphead=newnode;
}
 
头插相较于尾插简单的多:
只要将先将头结点赋值给新的结点的存储地址,然后在再将新节点newnode当作新的头结点*pphead即可;

2.6.链表的尾删
void SLTpopBack(SL**pphead)
{
//链表为空:不可以删除
assert(pphead && *pphead);
//处理只有一个结点的情况:要删除的就是头结点
if((*pphead)->next=NULL)
{
free(*pphead);
*pphead=NULL;
}
else
{
SL* ptail = *pphead;
SL* prev = NULL;
while (ptail->next)
{
	prev = ptail;
	ptail = ptail->next;
}
prev->next = NULL;
free(ptail);
ptail = NULL;
} 
这里我们还是用图解的方式来讲解:
 
2.7.链表的头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SL* next = (*pphead)->next;
	//*pphead --> next
	free(*pphead);
	*pphead = next;
} 
这里头删就更加简单了,头结点就是要删除的结点,直接将头结点的指向的下一个结点的地址存储到next中,在进行释放头结点空间,最后在对新结点进行操作

2. 8.链表的查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	assert(phead);
	SLTNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	//没有找到
	return NULL;
} 
 

2.9. 链表的指定位置前的结点插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* newnode = SLTBuyNode(x);
		//找prev :pos的前一个结点
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		
		//prev newnode --> pos
		newnode->next = pos;
		prev->next = newnode;
	}
} 
 

2.10. 在指定位置后插入结点
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	//pos newnode --> pos->next
	newnode->next = pos->next;
	pos->next = newnode;
} 
 

2.11.删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	//头删
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//prev pos pos->next
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next);
	//pos pos->next pos->next->next
	SLTNode* del = pos->next;
	pos->next = pos->next->next;
	free(del);
	del = NULL;
} 
 
2.12.销毁链表
void SListDestroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
} 
 
超详细源码:
cpp文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include"Slist.h"
void SLprint(SLTNode*phead)
{
	SLTNode* pcur = phead;
	while (pcur)
	{
		printf("%d", pcur->data);
	}
	printf("NULL/n");
}
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if(newnode==NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	if (pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
	//找尾结点
	SLTNode* pcur = *pphead;
	while (pcur->next)
	{
		pcur = pcur->next;
	}
	//pcur  newnode
	pcur->next = newnode;
n	}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	//newnode *pphead
	newnode->next = *pphead;
	*pphead = newnode;
}
void SLTPopBack(SLTNode** pphead)
{
	//链表为空:不可以删除
	assert(pphead && *pphead);
	//处理只有一个结点的情况:要删除的就是头结点	
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//找 prev ptail
		SLTNode* ptail = *pphead;
		SLTNode* prev = NULL;
		while (ptail->next)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		prev->next = NULL;
		free(ptail);
		ptail = NULL;
	}
}
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* next = (*pphead)->next;
	//*pphead --> next
	free(*pphead);
	*pphead = next;
}
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	assert(phead);
	SLTNode* pcur = phead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	//没有找到
	return NULL;
}
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SLTNode* newnode = SLTBuyNode(x);
		//找prev :pos的前一个结点
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		
		//prev newnode --> pos
		newnode->next = pos;
		prev->next = newnode;
	}
}
//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	//pos newnode --> pos->next
	newnode->next = pos->next;
	pos->next = newnode;
}
//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead && *pphead);
	assert(pos);
	//头删
	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//prev pos pos->next
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos && pos->next);
	//pos pos->next pos->next->next
	SLTNode* del = pos->next;
	pos->next = pos->next->next;
	free(del);
	del = NULL;
}
//销毁链表
void SListDestroy(SLTNode** pphead)
{
	assert(pphead && *pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}
 
.h文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义链表(结点)的结构
typedef int SLTDataType;
typedef struct SListNode {
	SLTDataType data;
	struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead);
//插入
void SLTPushBack(SLTNode** pphead, SLTDataType x);//尾插
void SLTPushFront(SLTNode** pphead, SLTDataType x);//头插
//删除
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDestroy(SLTNode** pphead);
	 
 
结束语:











