线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
C语言定义:
# define MAXSIZE 20
typedef int ElemType;
typedef struct
{
ElmeType data[MAXSIZE];
int length; // 线性表当前的长度;
}sqlist;
注:我们上面封装的这个顺序存储结构的线性表,事实上就是对数组的封装,只是又加了一个变量(属性)"length"来表示当前顺序存储线性表的当前数据长度。
我们把存储数据元素信息的域称为数据域,把存储直接前继或后继位置的域称为指针域。指针域中存储的信息称为指针或链。这两部分信息组成数据元素成为存储映像,称为结点(Node)。n个节点链接成一个链表,即为线性表的链式存储结构。
typedef struct Node
{
ElemType data; // 数据域
struct Node *next; // 指针域,指向下一个节点,所以指针结构类型是下一个节点的类型:Node
} Node; // 其实下面的*LinkList可以加在这里,下面就不用写了;
typedef struct Node *LinkList; // 取别名
可以看到,单链表的节点仅由 存放数据元素的数据域data和存放指向下一个节点地址的指针 组成。
在没有高级语言,没有指针之前,大佬们用数组来代替指针来描述单链表(但是本质仍是数组,所以在生成之初就限制了单链表的大小),称为游标实现法。图示如下:
静态链表游标实现C语言结构定义:
#define MAXSIZE 1000
type struct
{
ElemType data; // 数据域
int cur; // 游标
}Component, StaticLinkList[MAXSIZE];
因为静态链表是用数组模拟的,初始化一个静态链表相当于初始化数组,代码如下:
Status InitList(StaticLinkList space)
{
int i;
for(i=0; i < MAXSIZE-1; i++)
space[i].cur = i + 1;
space[MAXSIZE-1].cur = 0;
return OK;
}
单链表中终端节点的指针由空指针(NULL)改为指向头结点,就是整个单链表形成一个环,这种头尾相连的单链表称为单向循环链表,简称循环链表。
注:并非循环链表一定有头结点;
C语言结构定义:
typedef struct CLinkList
{
ElmeType data;
struct CLinkList *next;
}node;
注:循环链表和单链表的主要差异为判断空链表的方式,单链表:head->next是否为NULL;循环链表:head->next是否等于head。
typedef struct DualNode
{
ElemType data;
struct DualNode *prior; // 前驱节点;
struct DualNode *next; // 后驱节点;
}DualNode, *DuLinkList;
定义:栈(stack)是一个先进先出(Last in first out, LIFO)的线性表,它要求只能在表尾进行插入和删除操作。
栈本质是一个线性表。特点:后进先出,即只能在表尾进行操作。对栈来说,这个线性表的表尾称为栈的栈顶(top),表头称为栈的栈底(bottom)。栈的插入操作(Push),叫进栈,或入栈、压栈;栈的删除操作(Pop),叫出栈。
常用的是栈的顺序存储结构。
typedef struct
{
ElemType *base; //这里的ElemType是对某数据类型的重命名,如char
ElemType *top;
int stackSize;
}sqStack;
// 栈中的每一个元素结构
typedef struct StackNode
{
ElemType data; //存放栈的数据
struct StackNode *next;
}StackNode, *LinkStackPtr;
// 栈的指针和元素计算器
typedef struct LinkStack
{
LinkStackPtr top; //top指针
int count; //栈元素计数器
}
队列(queue)是只能在一端进行插入操作,在另一端进行删除操作的线性表。
与栈相反,队列是一种先进先出(First In First Out, FIFO)的线性表。
与栈相同的是,队列也是一种重要的线性结构,实现队列同样需要顺序表或者链表作为基础。
与栈相反,队列通常用链表来实现。
typedef struct QNode
{
ElemType data;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct
{
QueuePtr front, rear; // 队头指针,队尾指针;
}LinkQueue;
顺序存储实现的队列,入队操作的时间复杂度为O(1),但是出队时,所有元素都需要往前移位,时间复杂度为O(n)。
解决方法是可以加一个队头指针,指向队列的第一个元素,这样出队操作复杂度也可为O(1)了,但这时的队列会存在假溢出现象,如下图所示:
队列的假溢出解决方法是,如果队尾满了就从头开始,形成头尾相接的循环,即循环队列。
循环队列的容量是固定的,并且队头队尾指针都可以随着元素入队出队发生改变,这样,在逻辑上就像一个环形的存储空间。
但需注意的是,实际内存中,不会有真正的环形存储区,只是用顺序表模拟出逻辑上的循环。
实现:让front和rear指针不断+1,采用取模运算(即取余数)处理,这样即使超出了地址范围,也会从头开始。
C语言定义
#define MAXSIZE 100
typedef struct
{
ElemType *base; // 用于存放分配的内存空间的基地址;
int front;
int rear;
}*CycleQueue;
参考链接:小甲鱼的数据结构