之前稍微学了一点数据结构与算法的相关知识,平时也很少用,基本上忘得差不多了。最近在学习RT-Thread(国产物联网、嵌入式实时操作系统),阅读其内核源码时发现其用到循环双链表,趁此做一下一些学习笔记。
知识总是互相串联起来的,刚开始学的时候可能没那么快用得上,等到后面逐渐深入一些细节、原理的时候就会发现一些知识是相互联系起来的。下面分享线性表的一些知识:
线性表的概念
线性表是一个有限序列。其中的数据元素具有相同的特性。
线性表的存储结构
1、数据元素在内存中集中存储,采用顺序存储结构(顺序表)。
2、数据元素在内存中分散存储,采用链式存储结构(链表)。
线性表结构的定义
1、顺序表的结构定义
typedef struct Sqlist
{
int data[maxSize]; //存放顺序表元素的数组
int length; //存放顺序表的长度
}Sqlist;
或者:
typedef struct Sqlist
{
int* head; //声明了一个名为head的长度不确定的数组,也叫“动态数组”
int length; //记录当前顺序表的长度
int size; //记录顺序表分配的存储容量
}Sqlist;
2、单链表结点结构定义
typedef struct LNode
{
char data; //数据域
struct LNode *next; //指针域
}LNode;
3、双链表结点结构定义
typedef struct DLNode
{
struct DLNode *prior; //指向直接前驱
int data; //数据域
struct DLNode *next; //指向直接后继
}DLNode;
4、静态链表结点定义
typedef struct Component
{
int data;//数据域
int cur; //游标
}Component;
链表的形式
1、单链表
(1)结点的组成:1个数据域+1指针域。
(2)头结点:在开始结点之前的结点(可有可无)。其值域不包含任何信息。
(3)开始结点:第一个元素所在的结点。
(4)头指针:永远指向链表中第一个结点的位置(如果链表有头结点,头指针指向头结点;否则,头指针指向首元结点)。
(5)带头结点的单链表:头指针head指向头结点。头指针head始终不等于NULL,head->next等于NULL的时候链表为空。
(6)不带头结点的的单链表:头指针head指向开始结点,当head等于NULL时链表为空。
2、双链表
(1)结点的组成:1个数据域+2个指针域。
(2)带头结点:当head->next为NULL时链表为空。
(3)不带头结点:当head为NULL时链表为空。
3、循环单链表
(1)循环单链表:将单链表的最后一个指针域指向链表的中的第一个结点即为循环单链表。
(2)带头结点:当head等于head->next时链表为空。
(3)不带头结点:当head等于NULL时链表为空。
4、循环双链表
(1)循环双链表:将最后一个结点的next指针指向第一个结点,将第一个结点的prior指针指向终端结点即为循环双链表。
(2)带头结点:当head->next和head->prior两个指针都等于head时链表为空。
(3)不带头结点:当head等于NULL时链表为空。
5、静态链表
(1)静态链表:被局限在特定内存空间的链表即为静态链表。
(2)静态链表与动态链表的区别:静态链表限制了数据元素存放的位置范围;动态链表是整个内存空间。
(3)结点的组成:数据域+游标。
顺序表和链表的比较
1、基于空间的比较(存储分配的方式、存储密度)
(1)存储分配方式的比较
顺序表的存储空间是静态分配的,链表的存储空间是动态分配的。
(2)存储密度(存储密度=结点值域所占的存储量/结点结构所占的存储总量)的比较
顺序表的存储密度=1,链式表的存储密度<1(因为结点中有指针域)。
2、基于时间的比较
(1)存取方式的比较
顺序表是随机存取,链表是顺序存取。
(2)插入/删除时移动元素的个数
顺序表平均需要移动近一半元素,链表不需要移动元素,只需修改指针。
以上就是关于线性表的一些概念性的笔记,更具体的请看之后的分享。
联系客服