目录
链表结构及概念
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。数据像链一样连接,每个块包含数据和下一个块的地址,以此类推形成链表,最后一个块没有下一个块地址,指向空。
结构:
注意:
- 从结构图可以看出,链式结构在逻辑上是连续的,但是在物理上不一定连续
- 现实中的节点一般是从堆上申请的
- 从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,可能不连续
链表的分类
实际中链表的结构有很多,以下情况就有八种组合:
1.链表单项或双向
2.链表带头或不带头
3.链表循环或非循环
结构很多,但平时常用的有两种:
- 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
- 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了。
常用链表的实现
//无头单向链表
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDatatype;
typedef struct SListNode
{
SLTDatatype data;
struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead);
void SLPushFront(SLTNode** pphead, SLTDatatype x);
void SLPushBack(SLTNode** pphead, SLTDatatype x);
void SLPopFront(SLTNode** pphead);
void SLPopBack(SLTNode** pphead);
SLTNode* SLFind(SLTNode* phead, SLTDatatype x);
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDatatype x);
void SLErase(SLTNode** phead, SLTNode* pos);
打印:
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
创建存储数据空间:
SLTNode* BuyLTNode(SLTDatatype x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
头插:
void SLPushFront(SLTNode** pphead,SLTDatatype x)
{
assert(pphead);//断言,因为pphead是plist地址,不可能为空,除非传参传错
//assert(*pphead);不用断言
SLTNode* newnode = BuyLTNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
尾插:
void SLPushBack(SLTNode** pphead, SLTDatatype x)
{
assert(pphead);
SLTNode* newnode = BuyLTNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
头删:
void SLPopFront(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);//断言,因为链表为空不能头删(当然也可以使用温柔检查)
SLTNode* del = *pphead;
*pphead = (*pphead)->next;
free(del);
}
尾删:
void SLPopBack(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* tail = *pphead;
SLTNode* prev = NULL;
while (tail->next)
{
prev = tail;
tail = tail->next;
}
free(tail);
prev->next = NULL;
}
}
查找:
SLTNode* SLFind(SLTNode* phead, SLTDatatype x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
插入:
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDatatype x)
{
assert(pphead);
assert(pos);
SLTNode* prev = *pphead;
if (*pphead == pos)
{
SLPushFront(pphead, x);
}
else
{
while (prev)
{
if (prev->next != pos)
{
prev = prev->next;
}
SLTNode* newnode = BuyLTNode(x);
newnode = prev->next;
newnode->next = pos;
}
}
}
删除:
void SLErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
if (*pphead == pos)
{
SLPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;//1 2 3 4
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
}
}