1.链表的概念及结构
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
![](https://img-blog.csdnimg.cn/img_convert/4c64667154f90a08fb4ed1a2d257b8d3.png)
2.单链表的实现
2.1创建一个链表的结构
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
其中我们可以定义储存的数据类型,然后创建一个结构体,包含下一个节点的指针。
2.2增加一个节点
SLTNode* BuySLTNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail");
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
我们创建一个节点,存入需要的存放的值。这个函数被调用时就可以增加一个节点。比如在尾部插入一个节点或则在头部插入一个节点都需要这个函数,比较方便。
2.3在尾部插入一个节点(尾插)
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuySLTNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
注意我们在接下来需要改变链表头的指向的话就需要传入二级指针,这样可以通过解引用改变其指向。
如果该链表是空的,我们就将链表头指向创建的节点。
![](https://img-blog.csdnimg.cn/img_convert/06df809ac7762fbd8d0b51c1337c6363.png)
SLTNode* tail = *pphead;//找到链表的尾部
while (tail->next != NULL)
{
tail = tail->next;
}
2.4在头部插入一个节点(头插)
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuySLTNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
newnode->next = *pphead;
*pphead = newnode;
}
}
![](https://img-blog.csdnimg.cn/img_convert/8070a08a4c11b1cba68d59df629704d3.png)
2.5在尾部删除一个节点(尾删)
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead=NULL;
}
else
{
SLTNode* prev = NULL;
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
prev->next = NULL;
}
}
![](https://img-blog.csdnimg.cn/img_convert/bf4fb3ce3f3741e76e63b790f0a774f4.png)
在删除尾部节点时,使用了一个非常巧妙的方法,就是将prev比tail的走的少一布,这样释放掉tail指向的节点。
2.6在头部删除一个节点(头删)
void SLTPopFront(SLTNode** pphead)
{
if (*pphead ==NULL)
{
return;
}
else
{
SLTNode* first = *pphead;
*pphead = first->next;
free(first);
first = NULL;
}
}
2.7在链表中寻找一个节点
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
SLTNode* find = phead;
while (find != NULL)
{
if (find->data == x)
{
return find;
}
find = find->next;
}
return NULL;
}
这里注意我们要注意不要改变链表头的指向,我们就不需要使用二级指针。
2.8删除一个节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
//头删
//非头删
assert(pos);
assert(pphead);
if (*pphead == pos)
{
SLTNode* first = *pphead;
*pphead = first->next;
free(first);
first = NULL;
}
else
{
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
assert(cur);
}
cur->next = pos->next;
free(pos);
}
}
这里就需要分为头删和非头删,分别实现两个功能即可。
2.9修改一个节点的内容
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x)
{
SLTNode* cur = phead;
while (cur != pos)
{
cur = cur->next;
assert(cur);
}
cur->data = x;
}
就是找到该位置,将data改变。
2.10在一个节点之前插入一个节点
void SLTInsertFront(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
SLTNode* newnode = BuySLTNode(x);
if (*pphead == pos)
{
newnode->next = *pphead;
*pphead = newnode;
}
else
{
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
assert(cur);
}
cur->next = newnode;
newnode->next = pos;
}
}
2.11在一个节点之后插入一个节点
void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pos);
assert(pphead);
SLTNode* newnode = BuySLTNode(x);
SLTNode* cur = *pphead;
while (cur != pos)
{
cur = cur->next;
assert(cur);
}
newnode->next = pos->next;
pos->next = newnode;
}
2.12销毁链表
在销毁时我们要知道节点必须要一个一个销毁
void SLTDestroy(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
3.总代码
3.1 SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur!=NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
SLTNode* BuySLTNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail");
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuySLTNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuySLTNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
newnode->next = *pphead;
*pphead = newnode;
}
}
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* prev = NULL;
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
prev->next = NULL;
}
}
void SLTPopFront(SLTNode** pphead)
{
if (*pphead == NULL)
{
return;
}
else
{
SLTNode* first = *pphead;
*pphead = first->next;
free(first);
first = NULL;
}
}
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
SLTNode* find = phead;
while (find != NULL)
{
if (find->data == x)
{
return find;
}
find = find->next;
}
return NULL;
}
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
//头删
//非头删
assert(pos);
assert(pphead);
if (*pphead == pos)
{
SLTNode* first = *pphead;
*pphead = first->next;
free(first);
first = NULL;
}
else
{
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
assert(cur);
}
cur->next = pos->next;
free(pos);
}
}
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x)
{
SLTNode* cur = phead;
while (cur != pos)
{
cur = cur->next;
assert(cur);
}
cur->data = x;
}
void SLTInsertFront(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
SLTNode* newnode = BuySLTNode(x);
if (*pphead == pos)
{
newnode->next = *pphead;
*pphead = newnode;
}
else
{
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
assert(cur);
}
cur->next = newnode;
newnode->next = pos;
}
}
void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pos);
assert(pphead);
SLTNode* newnode = BuySLTNode(x);
SLTNode* cur = *pphead;
while (cur != pos)
{
cur = cur->next;
assert(cur);
}
newnode->next = pos->next;
pos->next = newnode;
}
void SLTDestroy(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
3.2 SList.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#pragma once
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 SLTErase(SLTNode** pphead, SLTNode*pos);
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x);
void SLTInsertFront(SLTNode** pphead, SLTNode* pos, SLTDataType x);
void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDataType x);
void SLTDestroy(SLTNode** pphead);