1.链表的概念
概念:链表是一种物理上不连续,非顺序的存储结构,数据元素的逻辑顺序上是通过指针来连接的线性表。
2.链表的分类
链表的分类有很多,主要有以下部分组成不同的链表:
3.链表和顺序表的区别
不同点 顺序表 链表
存储空间上 物理上一定连续 逻辑上连续,但物理上不一定连续
随机访问 支持O(1) 不支持:O(N)
任意位置插入或者删除元素 可能需要搬移元素,效率低O(N) 只需修改指针指向
插入 动态顺序表,空间不够时需要扩容 没有容量的概念
应用场景 元素高效存储+频繁访问 任意位置插入和删除频繁
缓存利用率 高 低
3.单链表的增删查改
链表结构如下:
头文件(函数声明):
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType a;
struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead);
//头部插入删除/尾部插入删除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//销毁链表
void SListDesTroy(SLTNode** pphead);
代码实现
打印链表:
//打印
void SLTPrint(SLTNode* phead)
{
SLTNode* node = phead;
while (node)
{
printf("%d ", node->a);
node = node->next;
}
}
头部插入删除:
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* node = c_jian(x);
if (*pphead==NULL)
{
*pphead = node;
}
node->next = *pphead;
*pphead = node;
}
//头删
void SLTPopFront(SLTNode** pphead)
{
assert(*pphead && pphead);
SLTNode* node = (*pphead)->next;
free(*pphead);
*pphead = NULL;
*pphead = node;
}
尾部插入删除:
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
SLTNode* node = c_jian(x);
if (*pphead == NULL)
{
*pphead = node;
}
else
{
SLTNode* tail = *pphead;
while (tail->next)
{
tail = tail->next;
}
tail->next = node;
}
}
//尾删
void SLTPopBack(SLTNode** pphead)
{
assert(*pphead && pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
SLTNode* tail= *pphead;
SLTNode* tail_1 = *pphead;
while (tail->next)
{
tail_1 = tail;
tail = tail->next;
}
free(tail);
tail_1->next = NULL;
tail = NULL;
}
查找数据:
//查找结点
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
assert(phead);
while (phead)
{
if (phead->a == x)
return phead;
phead = phead->next;
}
return NULL;
}
在指定位置之前插入数据:
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
SLTNode* node = c_jian(x);
SLTNode* prev = *pphead;
if (*pphead == pos)
{
SLTPushFront(pphead, x);
}
else
{
while (prev->next != pos)
{
if (prev->next == NULL)
exit(1);
prev = prev->next;
}
node->next = pos;
prev->next = node;
}
}
删除pos节点:
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
SLTNode* node = *pphead;
if (*pphead == pos)
{
SLTPopFront(pphead);
}
else
{
while (node->next != pos)
{
if (node == NULL)
exit(1);
node = node->next;
}
SLTNode* node1 = node->next;
node->next = node1->next;
free(node1);
node1 = NULL;
}
}
在指定位置之后插入数据:
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* node = c_jian(x);
node->next = pos->next;
pos->next = node;
}
销毁链表:
void SListDesTroy(SLTNode** pphead)
{
SLTNode* node = NULL;
while ((*pphead)->next)
{
node = *pphead;
*pphead = (*pphead)->next;
free(node);
}
free(*pphead);
}