一、栈
- 抽象数据结构类型栈的定义:
栈和普通数组和线性表最大的区别在于仅在尾端进行操作,并且具有后进先出(last in first out:简称LIFO结构)的特点。表尾端称为栈顶,表首端称为栈顶。 - 栈的表示和实现:
C++中的栈可以利用数组来实现,只需要简单的声明一个数组,当然Vector等STL数据结构也可以,定义相关的入栈和出栈操作,就可以进行栈的相关操作。C语言则是利用开空间的形式来进行数组声明。首先为栈声明一个基本容量,之后再应用过程中,在栈空间不足的情况下进行一步步的空间扩充,所以一般需要进行和前述线性表所相同的声明存储空间分配量和分配增量宏定义的相关操作。
#include"Base_Class.h"
#include<iostream>
#define STACK_INIT_SIZE 100//初始分配空间
#define STACKINCREMENT 10//后续分配空间的每次增量
typedef struct {
Auto_Class* base;//栈底
Auto_Class* top;//栈顶
int stacksize;
}SqStack;
bool InitStack(SqStack &s) {
s.base = (Auto_Class*)malloc(STACK_INIT_SIZE * sizeof(Auto_Class));//开辟空间
if (!s.base)
return false;
s.top = s.base;//栈顶等于栈尾,意为栈内无任何元素
s.stacksize = STACK_INIT_SIZE;
return true;
}
bool getTop(SqStack s,Auto_Class &e) {
if (s.top == s.base)
return false;
e = *(s.top - 1);//top始终指向栈顶元素的再上一位空间
return true;
}
bool Push(SqStack &s, Auto_Class e) {
if (s.top - s.base >= s.stacksize) {
s.base = (Auto_Class*)realloc(s.base, (s.stacksize + STACKINCREMENT) * sizeof(Auto_Class));
if (!s.base)
return false;
s.top = s.base + s.stacksize;
s.stacksize += STACKINCREMENT;
}
*s.top++ = e;//top始终指向栈顶元素的再上一位空间
return true;
}
bool Pop(SqStack &s, Auto_Class &e) {
if (s.top == s.base)
return false;
e = *--s.top;
return true;
}
二、队列
- 抽象数据类型队列的定义:
和栈正好相反,队列是一种先进先出(first in first out:缩写FIFO)的一种数据结构。插入的一段称为队尾,删除的一端称为队头。
通常来说,除了基本的栈和队列之外,还有限定性数据结构,双端队列。双端队列是限定插入和删除操作在表的两端进行的线性表,两端分别称为端点1和端点2。当然还有改进的输出受限的双端队列或者输入受限的双端队列。 - 链队列-队列的链式表示和实现:
链队列即是链表表示的队列,这里的实现和普通的单链表稍有区别:头节点有两个指针,一个指向队列头部,一个指向队列尾部,分别定义为front和rear,用来进行元素的插入和删除。 - 循环队列:
循环队列相当于头尾相连的、使用指针指示、固定容量的的线性表。因此,我们在使用循环队列的时候,往往要先定义容量,而不是在作为一个可变数组进行屡次开空间。但是在进行指针指示的时候往往会用到问题,也就是,怎么判断队列容量已满呢。为此通常有两个方案:(1)设置标志位来进行容量剩余的判断;(2)少用一个空间元素,当队头指针在队尾指针的下一位时,定义为已满状态。
链队列
#include"Base_Class.h"
#include<iostream>
//注意头节点在头指针之后,所以空队列还是会有一个LQNode节点,头节点内不存储任何元素。
typedef struct LQNode {
Auto_Class data;
struct LQNode* next;
}LQNode;
typedef struct {
LQNode* front;//头指针
LQNode* rear;//尾指针
}LinkQueue;
bool InitQueue(LinkQueue &l) {
l.front = l.rear = (LQNode*)malloc(sizeof(LQNode));
if (l.front != NULL)
return false;
l.front->next = NULL;
return true;
}
bool DestoryQueue(LinkQueue &q) {
while (q.front) {
q.rear = q.front->next;
free(q.front);
q.front = q.rear;
}
}
//尾部进入
bool insertQueue(LinkQueue &q, Auto_Class e) {
LQNode* p = (LQNode*)malloc(sizeof(LQNode));
if (!p)
return false;
p->data = e;
p->next = NULL;
q.rear->next = p;
//队尾最后一个节点指针指向p;
q.rear = p;
//对尾指针指向p;
return true;
}
//头部弹出
bool deleteQueue(LinkQueue &q, Auto_Class &e) {
if (q.front == q.rear)
return false;
LQNode* p = q.front->next;
e = p->data;
q.front->next = p->next;
if (q.rear == p)
q.rear = q.front;
free(p);
return true;
}
循环队列
//循环队列结构
typedef struct {
Auto_Class *base;
int front;//相当于头指针,index索引
int rear;//相当于尾指针,index索引
}SqQueue;
//
///循环队列
bool InitQueue_circle(SqQueue &q) {
q.base = (Auto_Class *)malloc(MAXQSIZE * sizeof(Auto_Class));
if (!q.base)
return false;
q.front = q.rear = 0;
}
int QueueLength(SqQueue Q) {
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
//注意这一步,相当于取绝对值。因为循环队列的队尾索引可以小于队首,因此利用这一步进行运算可以获得相应的容量。
}
bool insertQueue_circle(SqQueue &Q, Auto_Class e) {
if ((Q.rear + 1) % MAXQSIZE == Q.front)
//如果队列已经满
return false;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXQSIZE;
return true;
}
bool deleteQueue_circle(SqQueue &Q, Auto_Class e) {
//因为不可能提前出现满队列的情况,所以不用取余
if (Q.front == Q.rear)
return false;
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXQSIZE;
return true;
}