目录
一、单链表
1.链表的介绍
介绍一下链表的种类 今天学习的是单向 无头 非循环 链表
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
1. 单向、双向
2. 带头、不带头
3. 循环、非循环
![](https://i-blog.csdnimg.cn/blog_migrate/dbfaf9184b371c1ffe6e89bef4dccee0.png)
其中最常用的是
![](https://i-blog.csdnimg.cn/blog_migrate/ff5a6aaefd623c6b8a30aaa26bc568b9.png)
2.单链表的学习思维导图
3.顺序表和单链表的优缺点(重要)
4.单链表的头指针与头结点的区别(重要)
5.链表的实现(双指针法 & 返回值法)
以下是双指针法实现 这里把头插、尾插、头删、尾删放在前面
·头插法(双指针 & 返回值)
SListNode* SListPushFront(SListNode** pplist, SLTDataType x)//头插
{
/* 1.空
2.非空 */
SListNode* newnode = BuySListNode(x);
if (*pplist != NULL)
{
newnode->_next = *pplist;
*pplist = newnode;
}
else
{
*pplist = newnode;
}
}
SListNode* SListPushFront(SListNode* head, SLTDataType x)
{
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
newnode->_data = x;
newnode->_next = NULL;
if (head == NULL)
{
head = newnode; //确定新的头
return head;
}
else
{
newnode->_next = head ;
}
head = newnode;
return head;
}
·尾插法(双指针 & 返回值)
void SListPushBack(SListNode** pplist, SLTDataType x)//尾插法(双指针)
//plist 是pplist的地址 *pplist就是plist
{
SListNode* newnode = BuySListNode(x);
if (*pplist == NULL)
{
*pplist = newnode;
}
else
{
SListNode* tail = *pplist;//找尾
while (tail->_next != NULL)
{
tail = tail->_next;
}
tail->_next = newnode;
}
}
void SListPushBack(SListNode* head, SLTDataType x)//用返回值的方式进行尾插
{
SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
newnode->_data = x;
newnode->_next = NULL;
if (head == NULL) //先判断 如果没有结点的情况 考虑一下边界的情况
{
head = newnode;
return head;
}
else
{
SListNode* tail = head;
while (tail->_next != NULL)
{
tail = tail->_next;
}
tail->_next = newnode;
return head;
}
}
·头删法(双指针 & 返回值)
SListNode* SListPopFront(SListNode** pplist) //头删 双指针法
{/*
1.空
2.一个
3.两个以上*/
//SListNode* first = *pplist;
if (*pplist == NULL)
{
return ;
}
else if ((*pplist)->_next == NULL)
{
free(*pplist);
//plist = NULL;//达不到效果 因为plist只是局部变量
*pplist = NULL;
}
else
{
SListNode* _next = (*pplist)->_next;
free(*pplist);
*pplist = _next;
}
}
SListNode* SListPopFront(SListNode* head) //头删 返回值法
{
SListNode* cur = head;
if (cur == NULL)
{
return ;
}
else if (cur->_next == NULL)
{
free(cur);
cur = NULL;
}
else
{
SListNode* next = cur->_next;
free(cur);
cur = next;
}
head = cur;
return head;
}
·尾删法(双指针 & 返回值)
SListNode* SListPopBack(SListNode** pplist) //尾删 双指针法
{
assert(pplist);
//第一步 找尾
SListNode* prev = NULL; //定义tail上一个数
SListNode* tail = *pplist;
//1.空 、只有一个结点
//2.两个及以上的结点
if (tail == NULL || tail->_next == NULL)
{
free(tail);
*pplist = NULL;
}
else
{
while (tail->_next)
{
prev = tail;
tail = tail->_next;
}
free(tail);
tail = NULL;
prev->_next = NULL;
}
}
SListNode* SListPopBack(SListNode* head) //尾删 返回值法
{
assert(head);
//第一步 找尾
SListNode* prev = NULL; //定义tail上一个数
SListNode* tail = head;
//1.空 、只有一个结点
//2.两个及以上的结点
if (tail == NULL || tail->_next == NULL)
{
free(tail);
head = NULL;
}
else
{
while (tail->_next)
{
prev = tail;
tail = tail->_next;
}
free(tail);
tail = NULL;
prev->_next = NULL;
}
return head;
}
5.1 单链表结点的存储结构
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType _data; //数据域
struct SListNode* _next; //指针域
}SListNode;
5.2 单链表的初始化
void SListInit(SListNode* plist)
{
assert(plist);
plist = (SListNode*)malloc(sizeof(SListNode));
plist->next = NULL;
}
5.3 单链表的销毁
void SListDestory(SListNode** pplist)//销毁
{
SListNode* plist = NULL;
while (*pplist)
{
tmp = (*pplist)->_next;
free(*pplist);
(*pplist) = plist;
}
}
5.4 创建结点
SListNode* BuySListNode(SLTDataType x) //把结点开好,并进行初始化
{
//动态申请一个空间,用来存放一个结点,并用临时指针node指向这个结点
SListNode* node = (SListNode*)malloc(sizeof(SListNode));
node->_data = x; //将数据域存储到当前结点的data域中
node->_next = NULL;//设置当前结点的后继指针为空
return node;
}
5.5 打印单链表
void SListPrint(SListNode* plist)//打印
{
SListNode* cur = plist;
while (cur != NULL)//依次遍历一遍
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("NULL\n");
}
5.6 查找
SListNode* SListFind(SListNode* plist, SLTDataType x) //查找
{
SListNode* cur = plist;
while (cur)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
5.7 插入
void SListInsertAfter(SListNode* pos, SLTDataType x) //插入后一个 中间 边界 头部 都可以使用
{
assert(pos);
SListNode* next = pos->_next;
//pos newnode next
SListNode* newnode = BuySListNode(x);
newnode->_next = next;
pos->_next = newnode;
}
5.8 删除
void SListEraseAfter(SListNode* pos)//删除后一个 中间 边界 头部 都可以使用
{
//pos newnode next
assert(pos);
SListNode* next = pos->_next;
if (next != NULL)
{
SListNode* nextnext = next->_next;
free(next);
pos->_next = nextnext;
}
}