数据结构——单链表
一个结构体中包含两个成员。一个是存储数据,一个存放下一个结点的地址(当下一个节点为空时保存的地址为NULL)//将int类型命名为SLTDataType,便于后续更改//存储数据//存储下一个节点地址}SListNode;
·
前言
1. 什么是链表
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。与顺序表不同,链表的存储数据在内存是随机分布的。
2. 链表的分类
链表的种类多种多样,其中最常见的有八种,它们大致可以分为三类:
1 单向和双向

2 带头和不带头

3 循环和不循环

本章将对单向不带头不循环链表进行详细讲解
单向不带头不循环链表

1. 单链表的功能
单链表的主要功能有以下几个:
1. 打印单链表
2. 头插
3. 头删
4. 尾插
5. 尾删
6. 查找7. 在指定节点之前插入数据
8. 在指定节点之后插入数据
9. 删除指定节点数据
10. 删除指定节点之后的数据
11. 销毁单链表
2. 单链表的定义
一个结构体中包含两个成员。一个是存储数据,一个存放下一个结点的地址(当下一个节点为空时保存的地址为NULL)
typedef int SLTDataType;//将int类型命名为SLTDataType,便于后续更改
typedef struct SListNode
{
SLTDataType data; //存储数据
struct SListNode* next; //存储下一个节点地址
}SListNode;
3. 单链表功能实现
创建新节点
缩减代码,避免代码冗余
SLTNode* BuyNode(SLTDataType x) {
SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
//如果创建失败
if (node == NULL) {
perror("malloc fail!\n");
exit(1);
}
node->data = x;
node->next = NULL;
return node;//返回该节点
}
1. 打印单链表
void SLTPrint(SLTNode* phead) {
SLTNode* cur = phead;
while (cur) {
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
2. 头插
void SLTPushFront(SLTNode** pphead, SLTDataType x) {
assert(pphead);
SLTNode* node = BuyNode(x);//创建新节点
node->next = *pphead;//头插
*pphead = node;//将头插进来的节点作为头节点
}
3. 头删
void SLTPopFront(SLTNode** pphead) {
assert(pphead);
assert(*pphead);//链表不为空
SLTNode* first = *pphead;
*pphead = (*pphead)->next;//头删
free(first);//释放头节点
first = NULL;
}
4. 尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
assert(pphead);//pphead不为空
SLTNode* node = BuyNode(x);//创建新节点
//如果链表为空
if (*pphead == NULL) {
*pphead = node;//新节点为头节点
return;
}
//找尾
SLTNode* cur = *pphead;
while (cur->next) {
cur = cur->next;
}
cur->next = node;//将新节点进行尾插
}
5. 尾删
void SLTPopBack(SLTNode** pphead) {
assert(pphead);
assert(*pphead);//链表不为空
//如果链表只有一个节点
if ((*pphead)->next == NULL) {
free(*pphead);//释放头节点
*pphead = NULL;//将头节点位置置为空
return;
}
//找尾
// SLTNode *cur = *pphead;
// SLTNode *prev = NULL;
// while(cur->next){
// prev = cur;
// cur = cur->next;
// }
// prev->next = NULL;
// free(cur);
// cur = NULL;
SLTNode* tail = *pphead;
//寻找尾节点的前一个节点
while (tail->next->next) {
tail = tail->next;
}
free(tail->next);//释放尾节点
tail->next = NULL;
}
6. 查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x) {
assert(phead);
SLTNode* cur = phead;
while (cur) {
//如果找到该节点,返回该节点
if (cur->data == x) {
return cur;
}
cur = cur->next;
}
return NULL;//否则返回空
}
7. 在指定节点之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {
assert(pphead);
assert(pos);//检测pos节点不为空,如果pos节点不为空,那么该链表也不为空
SLTNode* node = BuyNode(x);
//如果pos==头节点
if (*pphead == pos) {
// node->next = pos;
// *pphead = node;
SLTPushFront(pphead, x);//头插
return;
}
//找pos的前一个节点
SLTNode* prev = *pphead;
while (prev->next) {
if (prev->next == pos) {
break;
}
prev = prev->next;
}
//插入pos节点之前
node->next = pos;
prev->next = node;
}
8. 在指定节点之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
assert(pos);
SLTNode* node = BuyNode(x);//创建新节点
//插入pos节点之后
node->next = pos->next;
pos->next = node;
}
9. 删除指定节点数据
void SLTErase(SLTNode** pphead, SLTNode* pos) {
assert(pphead);
assert(pos);//检测pos节点不为空,如果pos节点不为空,那么该链表也不为空
//如果pos==头节点
if (*pphead == pos) {
// SLTNode *del = *pphead;
// *pphead = (*pphead)->next;
// free(del);
// del = NULL;
SLTPopFront(pphead);//头删
return;
}
//找pos的前一个节点
SLTNode* prev = *pphead;
while (prev->next) {
if (prev->next == pos) {
break;
}
prev = prev->next;
}
prev->next = pos->next;//删除pos节点
free(pos);//释放pos节点
// pos = NULL;//没有存在的必要
}
10. 删除指定节点之后的数据
void SLTEraseAfter(SLTNode* pos) {
assert(pos);
assert(pos->next);
//删除pos之后的节点
SLTNode* del = pos->next;
pos->next = del->next;
free(del);//释放该节点
del = NULL;
}
11. 销毁单链表
void SListDesTroy(SLTNode** pphead) {
SLTNode* pointer = NULL;
while (*pphead) {
pointer = *pphead;
*pphead = (*pphead)->next;
free(pointer);
pointer = NULL;
}
}
4. 完整代码
1. SList.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType val;
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);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);
2. SList.c
#include "SList.h"
//创建节点
SLTNode* BuyNode(SLTDataType x) {
SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
//如果创建失败
if (node == NULL) {
perror("malloc fail!\n");
exit(1);
}
node->data = x;
node->next = NULL;
return node;//返回该节点
}
//打印链表
void SLTPrint(SLTNode* phead) {
SLTNode* cur = phead;
while (cur) {
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x) {
assert(pphead);//pphead不为空
SLTNode* node = BuyNode(x);//创建新节点
//如果链表为空
if (*pphead == NULL) {
*pphead = node;//新节点为头节点
return;
}
//找尾
SLTNode* cur = *pphead;
while (cur->next) {
cur = cur->next;
}
cur->next = node;//将新节点进行尾插
}
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x) {
assert(pphead);
SLTNode* node = BuyNode(x);//创建新节点
node->next = *pphead;//头插
*pphead = node;//将头插进来的节点作为头节点
}
//尾删
void SLTPopBack(SLTNode** pphead) {
assert(pphead);
assert(*pphead);//链表不为空
//如果链表只有一个节点
if ((*pphead)->next == NULL) {
free(*pphead);//释放头节点
*pphead = NULL;//将头节点位置置为空
return;
}
//找尾
// SLTNode *cur = *pphead;
// SLTNode *prev = NULL;
// while(cur->next){
// prev = cur;
// cur = cur->next;
// }
// prev->next = NULL;
// free(cur);
// cur = NULL;
SLTNode* tail = *pphead;
//寻找尾节点的前一个节点
while (tail->next->next) {
tail = tail->next;
}
free(tail->next);//释放尾节点
tail->next = NULL;
}
//头删
void SLTPopFront(SLTNode** pphead) {
assert(pphead);
assert(*pphead);//链表不为空
SLTNode* first = *pphead;
*pphead = (*pphead)->next;//头删
free(first);//释放头节点
first = NULL;
}
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x) {
assert(phead);
SLTNode* cur = phead;
while (cur) {
//如果找到该节点,返回该节点
if (cur->data == x) {
return cur;
}
cur = cur->next;
}
return NULL;//否则返回空
}
/*
* 在pos之前插入
*/
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x) {
assert(pphead);
assert(pos);//检测pos节点不为空,如果pos节点不为空,那么该链表也不为空
SLTNode* node = BuyNode(x);
//如果pos==头节点
if (*pphead == pos) {
// node->next = pos;
// *pphead = node;
SLTPushFront(pphead, x);//头插
return;
}
//找pos的前一个节点
SLTNode* prev = *pphead;
while (prev->next) {
if (prev->next == pos) {
break;
}
prev = prev->next;
}
//插入pos节点之前
node->next = pos;
prev->next = node;
}
/*
* 删除pos
*/
void SLTErase(SLTNode** pphead, SLTNode* pos) {
assert(pphead);
assert(pos);//检测pos节点不为空,如果pos节点不为空,那么该链表也不为空
//如果pos==头节点
if (*pphead == pos) {
// SLTNode *del = *pphead;
// *pphead = (*pphead)->next;
// free(del);
// del = NULL;
SLTPopFront(pphead);//头删
return;
}
//找pos的前一个节点
SLTNode* prev = *pphead;
while (prev->next) {
if (prev->next == pos) {
break;
}
prev = prev->next;
}
prev->next = pos->next;//删除pos节点
free(pos);//释放pos节点
// pos = NULL;//没有存在的必要
}
//插入pos节点之后
void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
assert(pos);
SLTNode* node = BuyNode(x);//创建新节点
//插入pos节点之后
node->next = pos->next;
pos->next = node;
}
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos) {
assert(pos);
assert(pos->next);
//删除pos之后的节点
SLTNode* del = pos->next;
pos->next = del->next;
free(del);//释放该节点
del = NULL;
}
//销毁链表
void SListDesTroy(SLTNode** pphead) {
SLTNode* pointer = NULL;
while (*pphead) {
pointer = *pphead;
*pphead = (*pphead)->next;
free(pointer);
pointer = NULL;
}
}
3. text.c
#include "SList.h"
void Relization(void) {
SLTNode* phead = NULL;
SLTPushBack(&phead, 5);
SLTPushBack(&phead, 2);
SLTPushFront(&phead, 3);
SLTPushFront(&phead, 4);
SLTPopBack(&phead);
SLTPopFront(&phead);
SLTNode* node = SLTFind(phead, 3);
if(node) {
printf("找到了\n");
}
else {
printf("没找到\n");
}
SLTInsert(&phead, phead->next, 7);
SLTInsertAfter(phead->next, 6);
SLTErase(&phead, NULL);
SLTEraseAfter(phead->next->next->next);
SLTPrint(phead);
SListDesTroy(&phead);
SLTPrint(phead);
}
int main() {
Relization();
return 0;
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)