数据结构之单链表(超详解)
一.链表的概念及结构
1.概念
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
2.链表的分类
1.无头单向链表
2.带头双循环链表
二.链表的定义
data为链表的数据域,next是链表的指针域
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
三.链表的结点的创建
在插入操作或者创建链表时,都要先创建一个链表的结点,所以封装一个函数,来创建结点
//创建新节点
SLTNode* CreateNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
return newnode;
}
四.链表的插入操作
1.头插
如果是空表就直接将newnode赋给phead,不是就先把他的next指向head,再把他赋给head,顺序反了,他就自己指向自己了。
//头插法
void ListPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = CreateNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
newnode->next = *pphead;
*pphead = newnode;
}
}
2.尾插
如果是空表就直接将newnode赋给phead,不是就先找到链表的尾结点,然后尾结点指向newnode就行
//尾插法
void ListPushBack(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = CreateNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* cur = *pphead;
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newnode;
}
}
3.任意位置插入
如果链表为空,可以直接调用上面的两个接口,不是利用函数指针调用find函数,找到想找的结点,将newnode的next指向cur的next,cur的nex再指向newnode,顺序不能反。
//任意位置插入
void ListInsert(SLTNode** pphead, SLTNode* (*SListFind)(SLTNode* phead),
SLTDataType x)
{
if (*pphead == NULL)
{
ListPushFront(pphead, x);
}
else
{
SLTNode* cur = SListFind(*pphead);
SLTNode* newnode = CreateNode(x);
newnode->next = cur->next;
cur->next = newnode;
}
}
五.链表的删除操作
1.头删
先将头部的next保存起来,然后把头部的内容用free释放,再把next赋给头指针。
//头删法
void ListPopFront(SLTNode** pphead)
{
assert(*pphead);
SLTNode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
不释放头,会造成内存泄露的问题。
2.尾删
首先判断链表是否为空或者链表是否只有一个结点,不是就找到尾部的前一个结点,用free(cur->next)释放尾结点,再将next置为NULL。
//尾删法
void ListPopBack(SLTNode** pphead)
{
if (*pphead == NULL)
{
printf("链表为空!\n");
}
else if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead == NULL;
}
else
{
SLTNode* cur = *pphead;
while (cur->next->next != NULL)
{
cur = cur->next;
}
free(cur->next);
cur->next = NULL;
}
}
3.任意位置删除
首先判断链表是否为空,不是利用函数指针调用find函数,找到想找的结点,再遍历链表找到该节点的前驱,将前驱的next赋为cur的next,再将cur的内容用free释放。
//任意位置删除
void Listerase(SLTNode** pphead, SLTNode* (*SListFind)(SLTNode* phead))
{
assert(*pphead);
if (*pphead == NULL)
{
printf("链表为空!\n");
}
else
{
SLTNode* cur = SListFind(*pphead);
SLTNode* pre = *pphead;
while (pre->next != cur)
{
pre = pre->next;
}
pre->next = cur->next;
free(cur);
}
}
六.链表元素的查找
找到值为x的结点并返回该结点,找不到就返回空指针。
//查找链表中的元素
SLTNode* SListFind(SLTNode* phead)
{
assert(phead);
SLTDataType x;
printf("请输入你要查找的元素:");
scanf("%d", &x);
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
return [添加链接描述](https://gitee.com/Tang-cmer/c-language-examples/tree/master/Linked%20list/Linked%20list)cur;
cur = cur->next;
}
return NULL;
}
七.链表的销毁
直接将头结点free,再把头结点置为空就行
//链表销毁
void ListDestory(SLTNode** pphead)
{
free(*pphead);
*pphead = NULL;
}
八.链表的源代码
原文地址:https://www.jb51.cc/wenti/3282780.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。