前言
链表是一种基础的线形数据结构,但是其与顺序表有着较大的差别。但是由于链表与顺序表均为线形结构,本篇将穿插对比分析它们在部分性能上的优劣性。建议萌新先学习顺序表,再来看链表。
【结构体解析】传送门:http://t.csdn.cn/iawZx。
【顺序表解析】传送门:http://t.csdn.cn/TZ5mw。
1 链表的基本思路
1.1 思路引入
相信大家一定都会串珠子,当我们有一根线和若干珠子的时候,我们可以把珠子一个一个地串到线上,这样就形成了一条链子。当被串成链子后,珠子就不会分散很,更加方便我们管理。这是一个简单的生活技巧。
1.2 基本思路
链表的思路其实就是参考了串珠子。如果我们把每一个数据存储在一个珠子里,再用某种方式将这些珠子串起来,不就形成一条链子了吗?这就是数据结构中的链表的基本思路。
在链表中,我们通常把这些存储数据的珠子称为节点。那么我们要怎么样将这些珠子串在一起呢?C语言的结构体提供了一种用法,叫做结构体的自引用。我们可以在结构体中声明一个与该结构体同类的指针,这样一来我们就可以通过在一个节点中保存下一个节点的地址的方式来将这些节点串在一起。
下面为代码和图片演示,这是一个节点的声明,这类节点中包含一个整型变量data和一个指针next,那么在该类节点中,每个节点可以存放一个整型数据和一个节点地址,通过地址又可以找到下一个节点。这样一来,只要我们能找到第一个节点,就能访问链表中任何一个节点。由于数据量是有限的,因此链表也不可能无限长,我们一般将链表中最后一个节点置空(防止越界访问)。
struct SListNode
{
int data;
struct SListNode* next;
};
1.3 注意事项
在我们的想象中,链表是一种线形结构,每个节点都被我们通过指针串在一起。但实际上,在内存当中,链表的各个节点的地址并不一定是连续的,而大概率是分散的。这里需要理解,我们是通过在节点中保存下一个节点的地址,再通过地址来找到下一个节点,而不是将所有节点移动到一块连续的空间。
这是与顺序表不同的地方。顺序表的数据是存储在一块连续的内存空间上的。
2 单链表
单链表,即单向链表。单向链表顾名思义,就是只有一个方向,也就是说只能通过前一个节点找到后一个节点,而不能从后一个节点找到前一个节点。
由于静态版数据结构在大部分场景下应用价值不大,本篇主要介绍动态版链表。
大部分链表OJ题都采用这种链表结构,如图(图中一个圆圈表示一个节点,圈内数字表示该节点所储存的数据,箭头表示节点中指向下一个节点的指针)。
2.1 接口
作为一种基础的数据结构,链表的基本功能当然也就是增删查改了。
而链表的基本思路是通过连接节点的方式将数据联系起来,那么我们的增加和删除数据其实要做的就是在合适的位置增加和删除节点。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDataType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDataType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDataType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链