今天我们主要研究单向无头单链表
先构建一个结点
typedef int DataType;
typedef struct SListNode {
DataType data; // 值
struct ListNod* pNext; // 指向下一个结点
} SListNode;
打印链表
void SListPrint(SListNode *pFirst)
{
SListNode *pCur;
for (pCur = pFirst; pCur != NULL; pCur = pCur->pNext)
{
printf("%d->", pCur->data);
}
printf("\n");
}
1、首先需要初始化单链表
//初始化
void SListInit(SListNode **ppFirst)
{
assert(ppFirst != NULL);
*ppFirst = NULL;
}
2、需要创建新的结点
//创建新结点
SListNode BuyNewNode(DataType data)
{
SListNode* New;
New= (SListNode*)malloc(sizeof(SListNode));
assert(New != NULL);//申请完成后一定要判断是否申请到
New->data = data;
New->pNext = NULL;
return *New;
}
3、尾插操作
尾插分为以下两种情况
// 尾部插入
//1、链表为空
//2、链表不为空
void SListPushBack(SListNode** ppFirst, DataType data)
{
assert(ppFirst != NULL);
SListNode *New, *pNode = ppFirst;
*New = BuyNewNode(data);
assert(New!= NULL);
if (NULL == *ppFirst)//链表为空直接在*ppFirst处插入就好
{
*ppFirst = New;
return;
}
while(pNode->pNext)//尾插的时候需要找到倒数第一个结点,所以循环终止条件设为pNode->pNext!=NULL
{
pNode = pNode->pNext;
}
pNode->pNext = New;
}
4、头插
头插也分为两种情况
// 头部插入
//1、链表为空
//2、链表中有元素
void SListPushFront(SListNode **ppFirst, DataType data)
{
assert(ppFirst != NULL);
SListNode *NewNode = NULL;
NewNode = BuyNewNode(data);
if (NULL == *ppFirst)//链表为空直接在*ppFirst处插入就好
{
*ppFirst = NewNode;
return;
}
NewNode->pNext = *ppFirst;
*ppFirst = NewNode;
}
5、尾删
尾删分三种情况
// 尾部删除
//1、链表为空,直接返回
//2、只有一个结点,直接free后把ppFirst置空
//3、有多个结点,找到倒数第二个结点,free倒数第一个结点,把倒数第二个结点的pNext赋为空
void SListPopBack(SListNode **ppFirst)
{
assert(ppFirst != NULL);
if (NULL == *ppFirst)//情况1
{
return;
}
if (NULL == (*ppFirst)->pNext)//情况2
{
free(*ppFirst);
*ppFirst = NULL;
return;
}
SListNode *pDel, *pCur;
for (pDel = *ppFirst; pDel->pNext->pNext != NULL; pDel = pDel->pNext)
{
}
pCur = pDel;
pDel = pDel->pNext;
pCur->pNext = pDel->pNext;
free(pDel);
}
6、头删
头删也分三种情况
// 头部删除
//1、链表为空,直接返回
//2、只有一个结点,直接free后把ppFirst置空
//3、用pDel保存ppFirst的位置,然后ppFirst指向pNext然后free掉pDel
void SListPopFront(SListNode **ppFirst)
{
assert(ppFirst != NULL);
if (NULL == *ppFirst)//情况1
{
return;
}
if (NULL == (*ppFirst)->pNext)//情况2
{
free(*ppFirst);
*ppFirst = NULL;
return;
}
SListNode *pDel;
pDel = *ppFirst;
*ppFirst = pDel->pNext;
free(pDel);
}
7、给定结点插入,插入到结点前
需要考虑
链表是否存在,pos位置是否为空
当pos位置不空时:如图示
// 给定结点插入,插入到结点前
void SListInsert(SListNode **ppFirst, SListNode *Pos, DataType data)
{
assert(ppFirst);
if (Pos == *ppFirst)
{
SListPushFront(ppFirst,data);
return;
}
SListNode *pNewNode = BuyNewNode(data);
SListNode *pNode ;
pNode = *ppFirst;
while ((pNode) && (pNode->pNext != Pos))
{
pNode = pNode->pNext;
}
if (pNode == NULL)
{
printf("没找到该结点\n");
return;
}
else
{
pNode->pNext = pNewNode;
pNode->pNext->pNext = Pos;
Pos = pNode->pNext;
}
}
8.给定结点删除
有以下几种情况
1、链表为空或者pos位置wei'k,直接返回
1、链表为空或者pos位置wei'k,直接返回
2、如果pos是第一个结点,直接调用头删函数
3、如果不是第一个结点
// 给定结点删除
void SListErase(SListNode **ppFirst, SListNode *Pos)
{
assert(ppFirst);
if ((NULL != ppFirst) && (Pos == NULL))
{
return ;
}
if (Pos == *ppFirst)
{
*ppFirst = Pos->pNext;
free(Pos);
return;
}
SListNode *pNode = *ppFirst;
while (pNode->pNext != Pos)
{
pNode = pNode->pNext;
}
pNode->pNext = Pos->pNext;
free(Pos);
}
9.查找一个值为data的节点,如果存在,返回所在位置,否则,返回NULL
只需要遍历一遍链表即可。
// 按值查找,返回第一个找到的结点指针,如果没找到,返回 NULL
SListNode* SListFind(SListNode *ppFirst, DataType data)
{
assert(ppFirst);
if (NULL != ppFirst)
{
return NULL;
}
SListNode *pCur = ppFirst;
while (pCur){
if (pCur->data = data)
{
return pCur;
}
pCur = pCur->pNext;
}
return NULL;
}
10、// 按值删除,只删遇到的第一个
// 按值删除,只删遇到的第一个
void SListRemove(SListNode **ppFirst, DataType data)
{
assert(ppFirst);
if (*ppFirst == NULL)
{
return;
}
SListNode *pCur;
pCur = *ppFirst;
while (pCur)
{
if (pCur->data = data)
{
SListErase(&ppFirst, pCur);
return;
}
pCur = pCur->pNext;
}
if (pCur == NULL)
{
printf("没有该元素\n");
return;
}
}
11、删除所以值为data的结点
①第一个节点的值是data,因为删除第一个节点需要修改ppFirst的值,所以需要单独处理第一个节点的值是data的时候。
删除第一个节点就是上面所说的头删。
②如果第一个节点的值不是data,直接处理即可。
下面处理第一个值不是data(这里的data为2)的情况:
// 按值删除,删除所有的
void SListRemoveAll(SListNode **ppFirst, DataType _data)
{
assert(ppFirst);
if (NULL == *ppFirst)
{
return;
}
SListNode *pDel = *ppFirst;
if ((*ppFirst)->data == _data)
{
*ppFirst = (*ppFirst)->pNext;
free(pDel);
}
SListNode *pCur = *ppFirst;
SListNode *prev = pCur;
while (pCur)
{
if (pCur->data == _data)
{
prev->pNext = pCur->pNext;
free(pCur);
pCur = prev->pNext;
}
else
{
prev = pCur;
pCur = pCur->pNext;
}
}
}
12、销毁单链表
这个特别注意特别注意特别注意!!!!!!!!!!!!!!
链表中每个结点都要free掉,不可以只free头结点,会造成内存泄漏
void SListDestroy(SListNode **ppFirst)
{
SListNode *pDel,*pCur;
pCur = *ppFirst;
while (pCur!= NULL)
{
pDel = pCur->pNext;
free(pCur);
pCur = pDel;
}
*ppFirst = NULL;
return;
}