如有问题欢迎指正
文章目录
前言
顺序表缺点:头部中间插入数据需要移动数据,效率低下。空间不够需要扩容,扩容有一定消耗且可能会造成空间浪费。
链表:
![](https://i-blog.csdnimg.cn/blog_migrate/ae16eb5ad0aeb37588cd801920a53db0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/927c8acad0b2c3bee4d3607d96962105.png)
一、头文件SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SListDataType;
typedef struct SListNode
{
SListDataType data;
struct SListNode* next;//存的是下一个节点的地址,下一个节点是结构体,所以指针类型是结构体
}SLN;
// 动态申请一个结点
SLN* BuySListNode(SListDataType x);
// 单链表打印
void SListPrint(SLN* plist);
// 单链表尾插
void SListPushBack(SLN** pplist, SListDataType x);
// 单链表的头插
void SListPushFront(SLN** pplist, SListDataType x);
// 单链表的尾删
void SListPopBack(SLN** pplist);
// 单链表头删
void SListPopFront(SLN** pplist);
// 单链表查找
SLN* SListFind(SLN* plist, SListDataType x);
// 单链表在pos位置之后插入x
void SListInsertAfter(SLN* pos, SListDataType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SLN* pos);
二、SList.c
1.动态申请一个结点
代码如下(示例):
#include"SList.h"
// 动态申请一个结点
SLN* BuySListNode(SListDataType x)
{
SLN* tmp = (SLN*)malloc(sizeof(SLN));
if (tmp == NULL)//检查malloc是否成功
{
perror("malloc faild");
exit(-1);
}
tmp->data = x;
tmp->next = NULL;
return tmp;
}
2.单链表打印
代码如下(示例):
void SListPrint(SLN* plist)
{
SLN* cur = plist;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
3.单链表尾插
void SListPushBack(SLN** pplist, SListDataType x)//因为传的是一个指针的地址,所以用二 级指针接收
{
assert(pplist);//判断是否需要断言,先假设可以为空看看合不合理,不合理说明不能为空 需要断言
SLN* newnode = BuySListNode(x);//注意分情况讨论,不要忽视没有数据时的情况
if (*pplist == NULL)
{
*pplist = newnode;
}
else
{
SLN* tail = *pplist;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
4.单链表的头插
void SListPushFront(SLN** pplist, SListDataType x)
{
assert(pplist);SLN* newnode = BuySListNode(x);
//这里写完会发现没有数据时的处理方法和有数据时的一样所以不用分情况
/*if (*pplist == NULL)
{
*pplist = newnode;
}
else
{
newnode->next = *pplist;
*pplist = newnode;
}*/
newnode->next = *pplist;
*pplist = newnode;
}
5.单链表的尾删
void SListPopBack(SLN** pplist)
{
assert(pplist);
assert(*pplist);//当plist为空时,删除则没有意义,所以不能为空
if ((*pplist)->next == NULL)
{
free(*pplist);
*pplist = NULL;
}
else
{
SLN* tail = *pplist;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}//这里必须注意用malloc,realloc申请的空间,不用是必须free释放,否则会造成内存泄漏
6.单链表头删
void SListPopFront(SLN** pplist)
{
assert(pplist);
assert(*pplist);
SLN* phead = *pplist;
*pplist = (*pplist)->next;
free(phead);
phead = NULL;}
7.单链表查找
SLN* SListFind(SLN* plist, SListDataType x)
{
SLN* tail = plist;
while (tail != NULL)
{
if (tail->data == x)
{
return tail;
}
tail = tail->next;
}
return NULL;
}
8.单链表在pos位置之后插入x
void SListInsertAfter(SLN* pos, SListDataType x)
{
assert(pos);//pos不能为空,否则没有意义
SLN* newnode = BuySListNode(x);
SLN* next = pos->next;
pos->next = newnode;
newnode->next = next;
}
9.单链表删除pos位置之后的值
void SListEraseAfter(SLN* pos)
{
assert(pos);
assert(pos->next);//如果为空则不需要删除,属于多此一举,既然调用此函数就是想实现 删除,所以pos->next不能为空
SLN* next = pos->next;
pos->next = next->next;
free(next);
next = NULL;
}