前面已经介绍顺序表,顺序表存在一定的局限性,空间管理上存在一定的缺陷,今天介绍新的存储结构单链表。
前言:
单链表是一种基本的数据结构,它由一系列节点组成,每个节点包含数据部分和一个指向下一个节点的指针。在单链表中,每个节点的地址不一定是连续的,而是通过指针相互链接起来。单链表的特点是存储灵活,可以动态地添加或删除节点,不需要预先分配固定大小的存储空间。
一、单链表基本介绍
单链表创建
1.定义节点结构体:首先需要定义一个结构体来表示链表的节点,通常包括数据域和指针域。
2.动态创建节点:使用malloc函数为每个节点分配内存空间,并初始化数据域和指针域。
3.插入节点:根据需要将新节点插入到链表的适当位置。插入操作可以是头插法或尾插法。
4.遍历链表:通过遍历链表,可以访问链表中的每个节点,通常用于打印或搜索特定数据。
单链表的操作
单链表的常见操作包括插入、删除、查找和遍历。这些操作通常涉及到对链表节点的指针进行操作,以实现数据的动态管理。
单链表的理解
链表同名字一样,像一个链子一样,有一个一个节点相连接。
二、单链表的实现
2.1 单链表的功能
分装成函数,有助于我们一一管理。
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos);
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos);
///删除pos前面的值
void SListEraseFront(SListNode* pos);
//单链表的销毁
void SLTDestory(SListNode** pphead);
2.2 定义节点结构体
数域 和 指针域
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
2.3 动态创建节点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* newcode = (SLTDateType*)malloc(sizeof(SListNode));
if (newcode == NULL)
{
perror("malloc fail");
return NULL;
}
newcode->data = x;
newcode->next = NULL;
return newcode;
}
2.3 单链表便历
注意:链表和顺序表的区别顺序表内存是连续的,链表是由一个一个节点连接的,‘cur’ 指向的下一个节点赋值给‘cur’cur = cur->next;
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
2.4 单链表的尾插
断言 pplist 避免传参时候造成不必要的麻烦
//单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
assert(pplist);
SListNode* newcode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = newcode;
}
else
{
//找尾
SListNode* tail = *pplist;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newcode;
}
}
2.5 单链表的尾删除
//单链表尾删
void SListPopBack(SListNode** pplist)
{
//节点断言
assert(pplist);
assert(*pplist);
//存在节点 1.存在一个节点 2.存在两个节点
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
//找尾
//SListNode* tail = *pplist;
//while (tail->next->next != NULL)
//{
// tail = tail->next;
//}
//free(tail->next);
//tail->next = NULL;
SListNode* prv = NULL;
SListNode* tail = *pplist;
while (tail->next != NULL)
{
prv = tail;
tail = tail->next;
}
free(tail);
prv->next = NULL;
}
}
2.6 单链表的头插
这个相对简单
//单链表头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
SListNode* newcode = BuySListNode(x);
newcode->next = *pplist;
*pplist = newcode;
}
2.6 单链表的头删
//单链表头删
void SListPopFront(SListNode** pplist)
{
//节点断言
assert(*pplist);
SListNode* first = *pplist;
*pplist = first->next;
free(first);
first = NULL;
}
2.7 单链表的查找
//单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
SListNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
2.8 单链表在指定位置(pos)的插入
2.8.1 在pos后面
// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* newcode = BuySListNode(x);
newcode->next = pos->next;
pos->next = newcode;
}
2.8.2 在pos前面插入
// 在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x)
{
assert(pplist);
assert(*pplist);
SListNode* newcode = BuySListNode(x);
if (pos == *pplist)
{
SListPushFront(pplist,x);
}
else
{
SListNode* cur = *pplist;
while (cur->next != pos)
{
cur = cur->next;
}
newcode->next = pos;
cur->next = newcode;
}
}
2.8.3 在pos后面插入
// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* newcode = BuySListNode(x);
newcode->next = pos->next;
pos->next = newcode;
}
2.9 在指定位置(pos)删除
2.9.1 删除在pos位置前面
// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
SListNode* del = pos->next;
pos->next = pos->next->next;
free(del);
del = NULL;
}
2.9.2 删除 pos 本位上的值
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos)
{
assert(pplist);
assert(*pplist);
SListNode* tail = *pplist;
while (tail->next != pos)
{
tail = tail->next;
}
tail->next = pos->next;
free(pos);
pos = NULL;
}
2.9.3 删除pos位置后面的值
//删除pos前面的值
void SListEraseFront(SListNode** pplist,SListNode* pos)
{
assert(pplist);
assert(*pplist);
SListNode* tail = *pplist;
while (tail->next->next != pos)
{
tail = tail->next;
}
SListNode* del = tail->next;
tail->next = pos;
free(del);
del = NULL;
}
2.10 单链表的销毁
不可以直接销毁*pplist,内存存贮不是连续的需要一个一个销毁。
//销毁链表
void SLTDestory(SListNode** pplist)
{
assert(pphead);
SListNode* cur = *pphead;
while (cur)
{
SListNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
源码
SLT.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos);
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos);
///删除pos前面的值
void SListEraseFront(SListNode* pos);
//单链表的销毁
void SLTDestory(SListNode** pplist);
SLT.c
#define _CRT_SECURE_NO_WARNINGS
#include"SLT.h"
//动态申请一个节点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* newcode = (SLTDateType*)malloc(sizeof(SListNode));
if (newcode == NULL)
{
perror("malloc fail");
return NULL;
}
newcode->data = x;
newcode->next = NULL;
return newcode;
}
//打印单链表
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
//单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
SListNode* newcode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = newcode;
}
else
{
//找尾
SListNode* tail = *pplist;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newcode;
}
}
//单链表尾删
void SListPopBack(SListNode** pplist)
{
//节点断言
assert(*pplist);
//if((*pplist)==NULL)
// return ;
//存在节点 1.存在一个节点 2.存在两个节点
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
//找尾
//SListNode* tail = *pplist;
//while (tail->next->next != NULL)
//{
// tail = tail->next;
//}
//free(tail->next);
//tail->next = NULL;
SListNode* prv = NULL;
SListNode* tail = *pplist;
while (tail->next != NULL)
{
prv = tail;
tail = tail->next;
}
free(tail);
prv->next = NULL;
}
}
//单链表头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
SListNode* newcode = BuySListNode(x);
newcode->next = *pplist;
*pplist = newcode;
}
//单链表头删
void SListPopFront(SListNode** pplist)
{
//节点断言
assert(*pplist);
SListNode* first = *pplist;
*pplist = first->next;
free(first);
first = NULL;
}
//单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
SListNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
// 单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* newcode = BuySListNode(x);
newcode->next = pos->next;
pos->next = newcode;
}
// 在pos的前面插入
void SLTInsert(SListNode** pplist, SListNode* pos, SLTDateType x)
{
assert(pplist);
assert(*pplist);
SListNode* newcode = BuySListNode(x);
if (pos == *pplist)
{
SListPushFront(pplist,x);
}
else
{
SListNode* cur = *pplist;
while (cur->next != pos)
{
cur = cur->next;
}
newcode->next = pos;
cur->next = newcode;
}
}
// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
SListNode* del = pos->next;
pos->next = pos->next->next;
free(del);
del = NULL;
}
// 删除pos位置
void SLTErase(SListNode** pplist, SListNode* pos)
{
assert(pplist);
assert(*pplist);
SListNode* tail = *pplist;
while (tail->next != pos)
{
tail = tail->next;
}
tail->next = pos->next;
free(pos);
pos = NULL;
}
//删除pos前面的值
void SListEraseFront(SListNode** pplist,SListNode* pos)
{
assert(pplist);
assert(*pplist);
SListNode* tail = *pplist;
while (tail->next->next != pos)
{
tail = tail->next;
}
SListNode* del = tail->next;
tail->next = pos;
free(del);
del = NULL;
}
//销毁链表
void SLTDestory(SListNode** pplist)
{
assert(pplist);
SListNode* cur = *pplist;
while (cur)
{
SListNode* next = cur->next;
free(cur);
cur = next;
}
*pplist = NULL;
Test.c
#define _CRT_SECURE_NO_WARNINGS
#include "SLT.h"
void testSList1()
{
SListNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListNode* ret = SListFind(plist, 2);
//ret->data = (ret->data) * 3;
//SListInsertAfter(ret, 66);
SLTInsert(&plist, ret, 77);
//SListEraseAfter(ret);
//SLTErase(&plist, ret);
SListEraseFront(&plist, ret);
SListPrint(plist);
}
void testSList2()
{
SListNode* plist = NULL;
SListPushFront(&plist, 1);
SListPushFront(&plist, 2);
SListPushFront(&plist, 3);
SListPushFront(&plist, 4);
SListPopFront(&plist);
SListPopFront(&plist);
SListPrint(plist);
}
int main()
{
testSList1();
//testSList2();
return 0;
}