链表
链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。其实链表可以想象为小火车,链表比顺序表具有更好的灵活性,只需要通过指针的改变就可以实现增删查改。
代码构造:
struct SListNode
{
int data; //结点数据
struct SListNode* next; //指针变量⽤保存下⼀个结点的地址
};
节点
与顺序表不同的是,链表⾥的每节"⻋厢"都是独⽴申请下来的空间,我们称之为“结点/结点”结点的组成主要有两个部分:当前结点要保存的数据和保存下⼀个结点的地址(指针变量)。链表中每个结点都是独⽴申请的(即需要插⼊数据时才去申请⼀块结点的空间),我们需要通过指针变量来保存下⼀个结点位置才能从当前结点找到下⼀个结点。
具体分析
实现链表功能的几个步骤:申请新的节点,头插或者尾插,头删尾删,找到指定的节点,插入到指定位置的前一个或者后一个,最后销毁链表。
此处我们代码中会出现形参实参的传地址的调用,为了便于理解特意附了一个图片进行理解
申请节点:
slist* slistnewnode(typedata x)
{
slist* node = (slist*)malloc(sizeof(slist));
if (node == NULL)
{
perror("fail!!!");
exit(1);
}
node->data = x;
node->next = NULL;
return node;
}
头插尾插:
//头插
void slistfrondpush(slist** s1, typedata x)
{
//sl不能为空如果为空*s1无法解引用
assert(s1);
slist *newnode=slistnewnode(x);
newnode->next = *s1;
*s1 = newnode;
}
//尾插
void slistbackpush(slist** s1, typedata x)
{
//尾插要考虑是这个链表是否为空
//不为空要找到末尾元素
assert(s1);
slist* newnode = slistnewnode(x);
if (*s1 == NULL)
{
*s1 = newnode;
}
else
{
slist* pcur = *s1;
while (pcur->next)
{
pcur = pcur->next;
}
pcur->next = newnode;
}
}
尾插:要注意一点传入时,节点为空那就是尾插,不为空时寻找尾节点就行,然后进行插入。
头删尾删:
//尾删除
void slistbackpop(slist** sl)
{
assert(sl && *sl);
//当只有一个节点时的情况,第二种就是找到末尾的前一个位置
slist* pcur=NULL;
slist* next = *sl;
if ((*sl)->next == NULL)
{
free(*sl);
*sl = NULL;
}
else
{
while (next->next)
{
pcur = next;
next = next->next;
}
pcur->next = NULL;
free(next);
next = NULL;
}
}
找到指定的节点:
slist* slistfind(slist* sl, typedata x)
{
assert(sl);
slist* pcur = sl;
while (pcur)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
指定位置之前,之后插入
//在指定位置之前插入
void slistInter(slist** s1, slist* pos, typedata x)
{
assert(s1);
assert(pos);
//当只有一个节点的时候此时在指定位置之前插入其实就是头插
if (*s1 == pos)
{
slistfrondpush(s1, x);
}
else
{
slist* newnode = slistnewnode(x);
slist* prev = *s1;
while (prev->next != pos)
{
prev = prev->next;
}
newnode->next = pos;
prev->next = newnode;
}
}
//指定位置后插入元素
void slistInterafter(slist* pos, typedata x)
{
assert(pos);
slist* newnode = slistnewnode(x);
newnode->next = pos->next;
pos->next = newnode;
}
删除pos后的节点
void slistEraseAfter(slist * pos)
{
assert(pos && pos->next);
slist* del = pos->next;
pos->next = pos->next->next;
free(del);
del = NULL;
}
销毁链表:
void slistDestory(slist** s1)
{
assert(s1 && *s1);
slist* pcur = *s1;
while (pcur)
{
slist* next = pcur->next;
free(pcur);
pcur = next;
}
*s1 = NULL;
}
代码展示
slist.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int typedata;
typedef struct slist
{
typedata data;
struct slist* next;
}slist;
//链表打印
void slistPrint(slist*sl);
//此处传参是用的二级指针;传值调用形参的改变不会影响实参
// s1-->&s
// *s1-->s
//链表的销毁
void slistDestory(slist** s1);
//节点的申请
slist * slistnewnode(typedata x);
//插入,尾插头插
void slistfrondpush(slist** s1, typedata x);
void slistbackpush(slist** s1, typedata x);
//删除,头删尾删
void slistfrondpop(slist** sl);
void slistbackdpop(slist** sl);
//查找元素
slist* slistfind(slist* sl, typedata x);
//指定位置前插入元素
void slistInter(slist** s1, slist* pos, typedata x);
//指定位置后插入元素
void slistInterafter(slist** s1, slist* pos, typedata x);
//删除pos节点
void slistErase(slist** sl, slist* pos);
//删除pos之后的节点
//void slistEraseAfter( slist* pos);
slist.c
#include"Slist.h"
void slistPrint(slist* sl)
{
slist* pcur = sl;
while (pcur)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("NULL\n");
}
//
void slistDestory(slist** s1)
{
assert(s1 && *s1);
slist* pcur = *s1;
while (pcur)
{
slist* next = pcur->next;
free(pcur);
pcur = next;
}
*s1 = NULL;
}
//实现插入的时候首先要申请一个节点
slist* slistnewnode(typedata x)
{
slist* node = (slist*)malloc(sizeof(slist));
if (node == NULL)
{
perror("fail!!!");
exit(1);
}
node->data = x;
node->next = NULL;
return node;
}
void slistfrondpush(slist** s1, typedata x)
{
//sl不能为空如果为空*s1无法解引用
assert(s1);
slist *newnode=slistnewnode(x);
newnode->next = *s1;
*s1 = newnode;
}
void slistbackpush(slist** s1, typedata x)
{
//尾插要考虑是这个链表是否为空
//不为空要找到末尾元素
assert(s1);
slist* newnode = slistnewnode(x);
if (*s1 == NULL)
{
*s1 = newnode;
}
else
{
slist* pcur = *s1;
while (pcur->next)
{
pcur = pcur->next;
}
pcur->next = newnode;
}
}
//头删,要考虑只有一个节点是的情况
void slistfrondpop(slist** sl)
{
//头删要保证不能是一个空链表
assert(sl && *sl);
slist* next = (*sl)->next;
free(*sl);
*sl = next;
}
//尾删除
void slistbackpop(slist** sl)
{
assert(sl && *sl);
//当只有一个节点时的情况,第二种就是找到末尾的前一个位置
slist* pcur=NULL;
slist* next = *sl;
if ((*sl)->next == NULL)
{
free(*sl);
*sl = NULL;
}
else
{
while (next->next)
{
pcur = next;
next = next->next;
}
pcur->next = NULL;
free(next);
next = NULL;
}
}
//查找元素
slist* slistfind(slist* sl, typedata x)
{
assert(sl);
slist* pcur = sl;
while (pcur)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
//在指定位置之前插入
void slistInter(slist** s1, slist* pos, typedata x)
{
assert(s1);
assert(pos);
//当只有一个节点的时候此时在指定位置之前插入其实就是头插
if (*s1 == pos)
{
slistfrondpush(s1, x);
}
else
{
slist* newnode = slistnewnode(x);
slist* prev = *s1;
while (prev->next != pos)
{
prev = prev->next;
}
newnode->next = pos;
prev->next = newnode;
}
}
//指定位置后插入元素
void slistInterafter(slist** s1, slist* pos, typedata x)
{
assert(s1);
assert(pos);
//当只有一个节点的时候此时在指定位置之前插入其实就是头插
if (*s1 == pos)
{
slistbackpush(s1, x);
}
else
{
slist* newnode = slistnewnode(x);
slist* prev = *s1;
while (prev!= pos)
{
prev = prev->next;
}
newnode->next = pos->next;
prev->next = newnode;
}
}
//删除pos节点
void slistErase(slist** sl, slist* pos)
{
assert(sl && *sl);
assert(pos);
if (pos == *sl)
{
slistfrondpop(sl);
}
else
{
slist* prev = *sl;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
//删除pos之后的节点
void slistEraseAfter(slist * pos)
{
assert(pos && pos->next);
slist* dl = pos->next;
pos->next = pos->next->next;
free(dl);
dl = NULL;
}
test.c
#include"Slist.h"
void test01()
{
slist *s=NULL;
//*s第一个节点
//s指向第一个节点的指针
//&s指向第一个节点的指针的地址
slistfrondpush(&s, 1);
slistbackpush(&s, 2);
slistbackpush(&s, 3);
slistbackpush(&s, 4);
slistbackpush(&s, 5);
slistfrondpop(&s);
slistbackpop(&s);
slist *find=slistfind(s, 4);
if (find == NULL)
{
printf("未找到!\n");
}
else
{
printf("找到了!\n");
}
slistInter(&s, find, 6);
slistInterafter(&s, find, 6);
slistPrint(s);
slistErase(&s, find);
//删除pos之后的节点
slistEraseAfter(find);
slistPrint(s);
slistDestory(&s);
}
int main()
{
test01();
return 0;
}
总结
以上就是单链表所实现的功能,如有不全期待各位大佬的积极指正,最后期待各位大佬能留下一个三连支持博主一下。