大家好呀!👋这个是付青云同学的博客,是一名大一在校生哦!😁😁
目前一直在学习C语言。🐸
写博客是为了来记录我的学习过程,同时也希望通过博客能够帮助到需要帮助的人。
如果我的博客可以帮助到你,不妨给我一个关注哦😁
前面顺序表说道:
顺序表发现它还是有缺点的:
- 空间不够了需要增容,而增容是要付出代价的;
- 所以避免频繁扩容,满了基本都是扩容两倍,但这样就可能导致一定的空间浪费;
- 顺序表要求数据从开始位置连续存储,那么我们在头部还在中间位置插入删除数据就需要挪动数据,效率不高。
于是为了解决这些问题,就有了单链表
单链表
声明部分
我创建了一个头文件(fu.h)来声明
#pragma once
typedef int SLTDateType;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
typedef struct SListNode
{
SLTDateType date;
struct SListNode* next;
}SLTNode;
//打印
void SListPrint(SLTNode* phead);
//尾插
void SListPushBuck(SLTNode** pphead,SLTDateType x);
//头插
void SListPushFront(SLTNode** pphead, SLTDateType x);
//尾删
void SListPopBack(SLTNode** pphead);
//头删
void SListPopFront(SLTNode** pphead);
//查找一个值为x的地址
SLTNode* SlistFind(SLTNode* phead, SLTDateType x);
//修改
//void SListRevise(SLTNode** pphead, SLTNode* pos, SLTDateType x)
//或者;
void SListRevise(SLTNode** pphead,int pos, SLTDateType x);
//在pos位置之前插入一个节点
//void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);
//或者
void SListInsert(SLTNode** pphead, int pos, SLTDateType x);
//在pos位置之后插入一个节点(简单)
void SListInsertAfter(SLTNode* pos, SLTDateType x);
//在pos位置删除一个节点
void SListEase(SLTNode** pphead, SLTNode* pos);
//在pos位置之后删除一个节点
void SListEaseAfter(SLTNode* pos);
//销毁链表
void SListDestory(SLTNode** pphead);
函数部分
#define _CRT_SECURE_NO_WARNINGS
#include "fu.h"
void SListPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->date);
cur = cur->next;
}
}
//开辟新空间
SLTNode* BuyListNode(SLTDateType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
printf("malloc fil\n");
exit(-1);
}
newnode->date = x;
newnode->next = NULL;
return newnode;
}
void SListPushBuck(SLTNode** pphead, SLTDateType x)//注意是二级指针!
{
assert(pphead != NULL);
//插入
/*SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
newnode->date = x;
newnode->next = NULL;*/
SLTNode* newnode = BuyListNode(x);
//第一个节点不找尾
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* tail = *pphead;
//找到尾节点
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SListPushFront(SLTNode** pphead, SLTDateType x)
{
asssert(pphead);
SLTNode* newnode = BuyListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SListPopBack(SLTNode** pphead)
{
assert(*pphead != NULL);
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;
/* SLTNode* tail = *pphead;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;*/
}
}
void SListPopFront(SLTNode** pphead)
{
assert(*pphead != NULL);
SLTNode* next = *pphead;
(*pphead) = (*pphead)->next;
free(next);
}
SLTNode* SlistFind(SLTNode* phead, SLTDateType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->date == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
void SListRevise(SLTNode** pphead,int pos, SLTDateType x)
{
SLTNode* cur = SlistFind(*pphead, pos);
if (cur)
{
cur->date = x;
}
}
//在pos之后插入一个节点(简单)
void SListInsertAfter(SLTNode* pos, SLTDateType x)
{
SLTNode* newnode = BuyListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
void SListEase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
if (*pphead == pos)
{
/**pphead = pos->next;
free(pos);*/
SListPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
void SListEaseAfter(SLTNode* pos)
{
assert(pos->next != NULL);
SLTNode* next = pos;
pos->next = next->next;
free(next);
//next = NULL;
}
void SListDestory(SLTNode** pphead)
{
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
void SListInsert(SLTNode** pphead, int pos, SLTDateType x)
{
SLTNode* newnode = BuyListNode(x);
SLTNode* cur = SlistFind(*pphead, pos);
if (*pphead == cur)
{
newnode->next = *pphead;
*pphead = newnode;
}
else
{
//找到pos的前一个位置
SLTNode* posPrev = *pphead;
while (posPrev->next != cur)
{
posPrev = posPrev->next;
}
posPrev->next = newnode;
newnode->next = cur;
}
}
之后可以自行调用函数来测试顺序表。
总结
写完这个单链表发现它也是有缺点的:
- 储存空间不连续,这意味着不能使用像冒泡排序快速排序等算法
- 每一个数据,都要存一个指针去链接后面数据节点
- 要访问特定的元素,都只能从表头开始,造成资源浪费
当然,单链表也不是一无是处的,前面说了,它解决了顺序表的很多缺点。