目录
1.链表的概念
2.链表的雏形
3.链表的组成
4.链表代码
创建准备;
- SListNode.h文件
- SListNode.c文件
- text.c文件
4.1创建节点
数据+指向下一个节点的指针
// 首先定义数据的类型,方便后续更改
typedef int SLTNodeDataType;
// 创建节点
typedef struct SListNode
{
SLTNodeDataType data; // 存储数据
struct SListNode* next;// 指向下一个节点的指针
}SLTNode;
4.2链表的打印
头文件声明:
void SLTPrint(SLTNode* phead);
执行文件代码实现:
// 链表的打印
void SLTPrint(SLTNode* phead)
{
SLTNode* pcur = phead;// 保证phead指向的位置是收节点,方便后续再次遍历
while (pcur)// 等价于 pcur != NULL;
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("NULL\n");
}
4.3链表的尾插
头文件声明:
void SLTPushBack(SLTNode** pphead, SLTNodeDataType x);
// 创建新的节点
SLTNode* SLTBuyNode(SLTNodeDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (NULL == newnode)
{
perror("SLTBuyNode malloc err!");
exit(1);
}
// 创建节点成功
newnode->data = x;
newnode->next = NULL;
// 返回
return newnode;
}
执行文件代码实现:
// 链表的尾插
void SLTPushBack(SLTNode** pphead, SLTNodeDataType x)
{
// 传参不可为空
assert(pphead);
// 创建一个新的节点
SLTNode* newnode = SLTBuyNode(x);
// 空链表和非空链表
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
// 找尾巴
SLTNode* ptail = *pphead;
while (ptail->next) // 等价于ptail->next !=NULL;
{
ptail = ptail->next;
}
// 找到尾巴,开始连接
ptail->next = newnode;
}
}
4.4链表的头插
头文件声明:
// 链表的头插
void SLTPushFront(SLTNode** pphead, SLTNodeDataType x);
执行文件代码实现:
// 链表的头插
void SLTPushFront(SLTNode** pphead, SLTNodeDataType x)
{
// 传参不可为空
assert(pphead);
// 创建一个新的节点
SLTNode* newnode = SLTBuyNode(x);
// 头插
newnode->next = *pphead;
*pphead = newnode;
}
头插就很简单了, 只需要创建新的节点放到链表的头部,不论是空链表和非空链表,情况都是一样的,连接好后,将头指针改指向,指向新头插的节点。
4.5链表的尾删
头文件声明:
void SLTPopBack(SLTNode** pphead);
执行文件代码实现:
// 链表的尾删
void SLTPopBack(SLTNode** pphead)
{
// 链表不可以为空,传参不可为空
assert(pphead && *pphead);
// 链表有一个节点和多个节点
// 一个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else //多个节点
{
// 找尾
SLTNode* prev = *pphead;
SLTNode* ptail = *pphead;
while (ptail->next)
{
prev = ptail;
ptail = ptail->next;
}
free(ptail); // 释放空间
ptail = NULL;// 防止野指针
prev->next = NULL;
}
}
尾删除需要影响原链表,所以传二级指针,同时尾删时我们需要注意是否节点是一个,如果是一个,删除后链表为空,申请的空间需要释放,防止造成空间浪费。如果是多个节点,我们需要找尾巴ptail,并且记录前一个节点prev,删除尾节点并且释放,置为空,将prev->next=NULL。
4.6链表的头删
头文件声明:
void SLTPopFront(SLTNode** pphead);
执行文件代码实现:
// 链表的头删
void SLTPopFront(SLTNode** pphead)
{
assert(pphead && *pphead);
SLTNode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
删除前断言所传的指针是否为空,链表是否为空,头删除前记录下一个节点,删除头节点后,将头置后。
4.7链表的查找
头文件声明:
SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x);
执行文件代码实现:
// 链表的查找
SLTNode* SLTFind(SLTNode* phead, SLTNodeDataType x)
{
SLTNode* prev = phead;
while (prev)// 等价于 prev != NULL;
{
if (prev->data == x)
{
return prev;
}
prev = prev->next;
}
// 遍历完毕没有找到,返回空。
return NULL;
}
4.8链表在指定位置之前插⼊数据
头文件声明:
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x);
执行文件代码实现:
// 链表在指定位置之前插⼊数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTNodeDataType x)
{
// 不可以传入NULL
assert(pphead && *pphead);
assert(pos);
// 创建一个新的节点
SLTNode* newnode = SLTBuyNode(x);
// 如果节点只有一个,就是头插
if (pos == *pphead)
{
SLTPushFront(pphead, x);
}
else
{
SLTNode* pcur = *pphead;
// pcur所指向的节点不为pos前一个节点
while (pcur->next != pos)
{
pcur = pcur->next;
}
// pcur所指向的节点为pos前一个节点
newnode->next = pos;
pcur->next = newnode;
}
}
4.9链表在指定位置之后插⼊数据
头文件声明:
void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x);
执行文件代码实现:
// 链表在指定位置之后插⼊数据
void SLTInsertAfter(SLTNode* pos, SLTNodeDataType x)
{
assert(pos);
// 创建要插入的节点
SLTNode* newnode = SLTBuyNode(x);
// 开始插入
newnode->next = pos->next;
pos->next = newnode;
}
4.9-1删除pos节点
头文件声明:
void SLTErase(SLTNode** pphead, SLTNode* pos);
执行文件代码实现:
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead && *pphead);
assert(pos);
if (*pphead == pos)
{
SLTPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
// prev所指向的就是pos前一个节点
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
4.9-2删除pos之后的节点
头文件声明:
void SLTEraseAfter(SLTNode* pos);
执行文件代码实现:
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
assert(pos && pos->next); // 传过来的参数不可以为空,pos下一个的参数也不可以是NULL
SLTNode* del = pos->next;
pos->next = del->next;
free(del);
del = NULL;
}
4.9-3销毁链表
文件声明:
void SListDesTroy(SLTNode** pphead);
执行文件代码实现:
//销毁链表
void SListDesTroy(SLTNode** pphead)
{
assert(pphead && *pphead);
SLTNode* pcur = *pphead;
while (pcur)
{
SLTNode* next = pcur->next;
free(pcur);
pcur = next;
}
// 全部销毁完后,置为空NULL;
*pphead = NULL;
}
补充:测试文件:
//void SListNodeText01()
//{
// // 创建节点
// SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
// node1->data = 1;
//
// SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
// node2->data = 2;
//
// SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
// node3->data = 3;
//
// SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
// node4->data = 4;
//
// // 将四个节点连接起来
// node1->next = node2;
// node2->next = node3;
// node3->next = node4;
// node4->next = NULL;
//
// // 打印
// SLTPrint(node1);
//}
void SLTNodeText02()
{
//SLTNode* plist = NULL;
// 测试尾插
//SLTPushBack(&plist, 1);
//SLTPushBack(&plist, 2);
//SLTPushBack(&plist, 3);
//SLTPushBack(&plist, 4);
/*SLTPrint(plist);*/// 1->2->3->4->NULL;
// 测试头插
/*SLTPushFront(&plist, 5);
SLTPrint(plist);
SLTPushFront(&plist, 6);
SLTPrint(plist);
SLTPushFront(&plist, 7);
SLTPrint(plist);
SLTPushFront(&plist, 8);
SLTPrint(plist);*/
// 测试尾删
//SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPrint(plist);
//SLTPopBack(&plist);
//SLTPrint(plist);
// 测试头删
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
// 报错
//SLTPopFront(&plist);
//SLTPrint(plist);
// 测试查找
//SLTNode* find = SLTFind(plist, NULL);
//if (find == NULL)
//{
// printf("没有找到!\n");
//}
//else
//{
// printf("找到了!\n");
//}
// 测试在pos位置之前插⼊数据
//SLTNode* find = SLTFind(plist, 1);
//SLTInsert(&plist, find, 11);
//SLTPrint(plist);
// 测试链表在指定位置之后插⼊数据
/*SLTNode* find = SLTFind(plist, 4);
SLTInsertAfter(find, 11);
SLTPrint(plist);*/
// 测试删除pos之后的节点
/*SLTNode* find = SLTFind(plist, 1);
SLTEraseAfter(find);
SLTPrint(plist);*/
// 测试销毁
SListDesTroy(&plist);
}
int main()
{
//SListNodeText01();
SLTNodeText02();
return 0;
}