什么是单向链表?
链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。
而单向链表的指针只指向下一个节点,如图
单向链表相对于顺序表的优点
笔者写过一篇关于顺序表的文章说过顺序表的缺点
不知道的读者可以点击此处查看
相对于顺序表有以下优点
- 不会造成空间浪费
- 可以在节点删除插入,不需要挪动数据,只要更改指针
具体代码实现
单向链表功能
- 头插
- 头删
- 在指针为pos的位置前插入
- 尾插
- 尾删
- 删除指针为pos的位置
- 遍历打印链表
- 查找
具体代码
创建一个节点
SLN* buy_SLN()
{
SLN* tmp = (SLN*)malloc(sizeof(SLN));
if (tmp == NULL)
{
perror("malloc fail");
}
tmp->next = NULL;
return tmp;
}
头插
void pushfront(SLN** s1, NodeData x)
{
assert(s1);
SLN* tmp = buy_SLN();//获取空间
tmp->a = x;
tmp->next = *s1;
*s1 = tmp;
}
如图
尾插
void pushback(SLN** s1, NodeData x)
{
assert(s1);
SLN* tmp = buy_SLN();
if (*s1 == NULL)//空链表情况
{
tmp->a = x;
tmp->next = NULL;
*s1 = tmp;
}
else//非空链表情况
{
SLN* cut = *s1;
while (cut->next != NULL)
{
cut = cut->next;
}
tmp->a = x;
tmp->next = NULL;
cut->next = tmp;
}
}
分为两种情况,空链表情况单独处理
如图
头删
void popfront(SLN** s1)
{
assert(s1);
assert(*s1);
SLN* tmp = *s1;
*s1 = tmp->next;
free(tmp);
tmp = NULL;
}
注意断言!此处对*s1断言,保证链表不为空,有东西可删,下面的尾删同理
尾删
void popback(SLN** s1)
{
assert(*s1);
SLN* tmp = *s1;
if ((*s1)->next == NULL)
{
free(*s1);
*s1 = NULL;
}
else
{
while (tmp->next->next != NULL)
{
tmp = tmp->next;
}
free(tmp->next);
tmp->next = NULL;
}
}
分两种情况,链表只有一个数据,和有两个及以上
只有一个数据,直接将数据释放,将链表置空
遍历打印链表
void SLNprinf(SLN* s1)
{
assert(s1);
SLN* p = s1;
while (p)//最后一个为空
{
printf("%d->", p->a);
p = p->next;
}
printf("\n");
}
查找某数据
SLN* STFind(SLN* s1, NodeData x)
{
SLN* tmp = s1;
while (tmp)
{
if (tmp->a == x)
{
return tmp;
}
tmp = tmp->next;//去下一个节点
}
return NULL;
}
这里返找到数据的地址
在指针为pos的位置前插入
void SLInsert(SLN** s1, SLN* pos, NodeData x)
{
assert(s1);
assert(pos);
SLN* cur = *s1;
SLN* tmp = buy_SLN();
tmp->a = x;
if (*s1==pos)
{
pushfront(s1, x);
}
else
{
while (cur->next != pos)
{
cur = cur->next;
}
tmp->next = cur->next;
cur->next = tmp;
}
}
如果插入位置是链表的第一个位置则直接调用头插函数
其他位置,如图
删除指针为pos的位置
void SLErase(SLN** s1, SLN* pos)
{
assert(s1);
assert(pos);
SLN* tmp = *s1;
if (*s1 == pos)
{
popfront(s1);
}
else
{
while (tmp->next!=pos)
{
tmp = tmp->next;
}
tmp->next = pos->next;
free(pos);
}
}
如果只有一个数据则调用头删
其他情况如图
以下是完整代码以及测试
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int NodeData;
typedef struct SListNode
{
NodeData a;
struct SListNode* next;
}SLN;
SLN* buy_SLN();
void pushback(SLN** s1, NodeData x);//尾插
void pushfront(SLN** s1, NodeData x);//头插
void SLNprinf(SLN* s1);//打印
void popfront(SLN** s1);//头删
void popback(SLN** s1);//尾删
SLN* STFind(SLN* s1, NodeData x);//查找
void SLInsert(SLN**s1, SLN* pos, NodeData x);//在地址为pos前位置添加
void SLInsertAfte(SLN* pos, NodeData x);//在地址为pos后的位置添加
void SLErase(SLN** s1, SLN* pos);//删除pos位置
void SLEraseAfter(SLN* pos);//删除pos后的位置
#include"lianbiao.h"
SLN* buy_SLN()
{
SLN* tmp = (SLN*)malloc(sizeof(SLN));
if (tmp == NULL)
{
perror("malloc fail");
}
tmp->next = NULL;
return tmp;
}
void pushback(SLN** s1, NodeData x)
{
assert(s1);
SLN* tmp = buy_SLN();
if (*s1 == NULL)//空链表情况
{
tmp->a = x;
tmp->next = NULL;
*s1 = tmp;
}
else//非空链表情况
{
SLN* cut = *s1;
while (cut->next != NULL)
{
cut = cut->next;
}
tmp->a = x;
tmp->next = NULL;
cut->next = tmp;
}
}
void pushfront(SLN** s1, NodeData x)
{
assert(s1);
SLN* tmp = buy_SLN();//获取空间
tmp->a = x;
tmp->next = *s1;
*s1 = tmp;
}
void SLNprinf(SLN* s1)
{
assert(s1);
SLN* p = s1;
while (p)
{
printf("%d->", p->a);
p = p->next;
}
printf("\n");
}
void popfront(SLN** s1)
{
assert(s1);
assert(*s1);
SLN* tmp = *s1;
*s1 = tmp->next;
free(tmp);
tmp = NULL;
}
void popback(SLN** s1)
{
assert(*s1);
SLN* tmp = *s1;
if ((*s1)->next == NULL)
{
free(*s1);
*s1 = NULL;
}
else
{
while (tmp->next->next != NULL)
{
tmp = tmp->next;
}
free(tmp->next);
tmp->next = NULL;
}
}
SLN* STFind(SLN* s1, NodeData x)
{
SLN* tmp = s1;
while (tmp)
{
if (tmp->a == x)
{
return tmp;
}
tmp = tmp->next;
}
return NULL;
}
void SLInsert(SLN** s1, SLN* pos, NodeData x)
{
assert(s1);
assert(pos);
SLN* cur = *s1;
SLN* tmp = buy_SLN();
tmp->a = x;
if (*s1==pos)
{
pushfront(s1, x);
}
else
{
while (cur->next != pos)
{
cur = cur->next;
}
tmp->next = cur->next;
cur->next = tmp;
}
}
void SLInsertAfte(SLN* pos, NodeData x)
{
assert(pos);
SLN* cur=pos;
SLN* tmp = buy_SLN();
tmp->a = x;
tmp->next = cur->next;
cur->next = tmp;
}
void SLErase(SLN** s1, SLN* pos)
{
assert(s1);
assert(pos);
SLN* tmp = *s1;
if (*s1 == pos)
{
popfront(s1);
}
else
{
while (tmp->next!=pos)
{
tmp = tmp->next;
}
tmp->next = pos->next;
free(pos);
}
}
void SLEraseAfter(SLN* pos)
{
assert(pos);
assert(pos->next);
SLN* tmp = pos->next;
pos->next = tmp->next;
free(tmp);
}
#include"lianbiao.h"
int main()
{
SLN* phead = NULL;
pushback(&phead, 7);
pushback(&phead, 1);
pushback(&phead, 1);
SLNprinf(phead);
pushfront(&phead, 5);
pushfront(&phead, 2);
pushfront(&phead, 2);
SLNprinf(phead);
popfront(&phead);
popback(&phead);
popback(&phead);
SLNprinf(phead);
SLN*tmp=STFind(phead,5);
printf("%d\n", tmp->a);
SLInsert(&phead, tmp, 9);
printf("%d\n", tmp->a);
SLNprinf(phead);
SLInsertAfte(tmp, 8);
SLNprinf(phead);
SLErase(&phead, tmp);
SLNprinf(phead);
SLN* tm = STFind(phead, 9);
SLEraseAfter(tm);
SLNprinf(phead);
}
单向链表的分享到这里就结束嘞!
希望大家多多三连,若有错误之处,还请不吝赐教!