前言
上一章,我们讲了数据结构--动态顺序表,我们会发现有以下问题:
下面我们来看看单链表这种线性结构;
链表
概念与结构
链表是一种常见的数据结构,用于存储和组织数据。它由一系列节点组成,每个节点包含两部分:数据和指向下一个节点的指针。
链表中的节点在内存中可以分布在任意位置,不像数组那样需要连续的存储空间。每个节点都包含了存储的数据以及指向下一个节点的指针。通过这种方式,链表可以灵活地分配和管理内存空间。就像一节节连动的火车车厢;
在数据结构中,呈现:
逻辑图中,呈现:
在逻辑图中,链式结构是连续性的,但实际上不一样连续;从数据结构中看出,链表是通过地址来联系在一起的,不需要地址的连续性;在我们要解决链表相关问题时,只需要画出逻辑图即可;
链表的分类
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
1. 单向或者双向
2. 带头或者不带头
3. 循环或者非循环
可以通过一定的组合达成不同种类的链表;
这里我们比较常用的是有两种结构:
在这里,我们将先实现无头单向非循环链表,这是链表中结构最为简单的;简称单链表。
单链表的接口实现
先写一下它的结构:
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDataType;
typedef struct SLTNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
单链表打印
void SLTrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
增加链表结点
SLTNode* BuySListNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("mallco fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
尾插
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuySListNode(x);
if (* pphead == NULL)
{
* pphead = newnode;
}
else
{
SLTNode* tail = * pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
验证:
void Test3()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLTrint(plist);
}
int main()
{
Test3();
return 0;
}
尾删
void SLPopBack(SLTNode** pphead)
{
assert(pphead);
//判空
assert(*pphead);
//一个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
//其他
else
{
SLTNode* tailPrev = NULL;
SLTNode* tail = *pphead;
while (tail->next)
{
tailPrev = tail;
tail = tail->next;
}
free(tail);
tailPrev->next = NULL;
}
}
验证:
void Test3()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLTrint(plist);
SLPopBack(&plist);
SLTrint(plist);
}
int main()
{
Test3();
return 0;
}
头插头删
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuySListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SLPopFront(SLTNode** pphead)
{
assert(pphead);
//判空
assert(*pphead);
//其他
SLTNode* newhead = (*pphead)->next;
free(*pphead);
*pphead = newhead;
}
验证:
void Test2()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLPushBack(&plist, 5);
SLTrint(plist);
SLPushFront(&plist, 6);
SLPushFront(&plist, 7);
SLPushFront(&plist, 8);
SLPushFront(&plist, 9);
SLTrint(plist);
SLPopFront(&plist);
SLTrint(plist);
}
int main()
{
Test2();
return 0;
}
查找与插入
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
//判空
assert(phead);
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
验证:
void Test3()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLTrint(plist);
SLTNode* pos = SLFind(plist, 3);
SLTInsertAfter(pos, 88);
SLTrint(plist);
}
int main()
{
Test3();
return 0;
}
删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pos);
if (pos == *pphead)
{
SLPopFront(pphead);
}
else
{
SLTNode* perv = *pphead;
while (perv->next != pos)
{
perv = perv->next;
}
perv->next = pos->next;
free(pos);
}
}
void SLTEraseAfter(SLTNode* pos)
{
assert(pos);
//检查尾节点
assert(pos->next);
SLTNode* posNext = pos->next;
pos->next = posNext->next;
free(posNext);
}
验证:
void Test3()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLTrint(plist);
SLTNode* pos = SLFind(plist, 3);
SLTInsertAfter(pos, 88);
SLTrint(plist);
SLTErase(&plist, pos);
SLTrint(plist);
}
int main()
{
Test3();
return 0;
}
void Test3()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLTrint(plist);
SLTNode* pos = SLFind(plist, 3);
SLTInsertAfter(pos, 88);
SLTrint(plist);
SLTEraseAfter(pos);
SLTrint(plist);
}
int main()
{
Test3();
return 0;
}
摧毁
void SLTDestroy(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* prev = cur;
cur = cur->next;
free(prev);
}
*pphead = NULL;
}
验证:
void Test3()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLTrint(plist);
SLTNode* pos = SLFind(plist, 3);
SLTInsertAfter(pos, 88);
SLTrint(plist);
SLTDestroy(&plist);
SLTrint(plist);
}
int main()
{
Test3();
return 0;
}
完整代码
slist.h
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDataType;
typedef struct SLTNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
void SLTrint(SLTNode* phead);
SLTNode* BuySListNode(SLTDataType x);
void SLPushBack(SLTNode** pphead, SLTDataType x);
void SLPushFront(SLTNode** pphead, SLTDataType x);
void SLPopBack(SLTNode** pphead);
void SLPopFront(SLTNode** pphead);
SLTNode* SLFind(SLTNode* phead, SLTDataType x);
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
void SLTErase(SLTNode** pphead, SLTNode* pos);
void SLTEraseAfter(SLTNode* pos);
void SLTDestroy(SLTNode** phead);
slist.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Slist.h"
void SLTrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
SLTNode* BuySListNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("mallco fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuySListNode(x);
if (* pphead == NULL)
{
* pphead = newnode;
}
else
{
SLTNode* tail = * pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuySListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SLPopBack(SLTNode** pphead)
{
assert(pphead);
//判空
assert(*pphead);
//一个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
//其他
else
{
SLTNode* tailPrev = NULL;
SLTNode* tail = *pphead;
while (tail->next)
{
tailPrev = tail;
tail = tail->next;
}
free(tail);
tailPrev->next = NULL;
}
}
void SLPopFront(SLTNode** pphead)
{
assert(pphead);
//判空
assert(*pphead);
//其他
SLTNode* newhead = (*pphead)->next;
free(*pphead);
*pphead = newhead;
}
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
//判空
assert(phead);
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuySListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pos);
if (pos == *pphead)
{
SLPopFront(pphead);
}
else
{
SLTNode* perv = *pphead;
while (perv->next != pos)
{
perv = perv->next;
}
perv->next = pos->next;
free(pos);
}
}
void SLTEraseAfter(SLTNode* pos)
{
assert(pos);
//检查尾节点
assert(pos->next);
SLTNode* posNext = pos->next;
pos->next = posNext->next;
free(posNext);
}
void SLTDestroy(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* prev = cur;
cur = cur->next;
free(prev);
}
*pphead = NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Slist.h"
void Test1()
{
int n;
SLTNode* plist = NULL;
printf("请输入链表长度");
scanf("%d", &n);
printf("请输入值");
for (int i = 0; i < n; i++)
{
int val;
scanf("%d", &val);
SLTNode* newnode = BuySListNode(val);
newnode->next = plist;
plist = newnode;
}
SLTrint(plist);
}
void Test2()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLPushBack(&plist, 5);
SLTrint(plist);
SLPushFront(&plist, 6);
SLPushFront(&plist, 7);
SLPushFront(&plist, 8);
SLPushFront(&plist, 9);
SLTrint(plist);
SLPopFront(&plist);
SLTrint(plist);
}
void Test3()
{
SLTNode* plist = NULL;
SLPushBack(&plist, 1);
SLPushBack(&plist, 2);
SLPushBack(&plist, 3);
SLPushBack(&plist, 4);
SLTrint(plist);
SLTNode* pos = SLFind(plist, 3);
SLTInsertAfter(pos, 88);
SLTrint(plist);
SLTDestroy(&plist);
SLTrint(plist);
}
int main()
{
Test3();
return 0;
}