目录
一、栈
1.1栈的定义
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。
进行数据插入和删除操作的一端
称为栈顶,另一端称为栈底。
栈中的数据元素遵守后进先出
LIFO
(
Last In First Out
)的原则。
栈顶是线性表允许进行插入删除的那一端,栈顶的位置是由栈顶指针初始位置间接决定的,它可以是最顶部元素位置,也可以是栈顶元素往上空一格的位置。而栈底则是固定的,是不允许进行插入和删除的另一端。
1.2栈的实现
栈的实现一般可以使用
数组或者链表实现
,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的 代价比较小。
![](https://img-blog.csdnimg.cn/d16df0f1a7724af9977006ad10ba5d52.png)
![](https://img-blog.csdnimg.cn/4e90835bc3864bc7a544e4e3c22a49fa.png)
支持动态增长的栈
1.定义节点
#define DEFSTACKSIZE 100
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;
2.栈初始化
void StackInit(Stack* ps)
{
ps->array = (STDataType *)calloc(DEFSTACKSIZE, sizeof(STDataType));
ps->capacity = DEFSTACKSIZE;
ps->size = 0;
}
3.入栈
void StackPush(Stack* ps, STDataType x)
{
CheckCapacity(ps);
ps->array[ps->size] = x;
ps->size++;
}
4.出栈
void StackPop(Stack* ps)
{
if (ps->size == 0)
{
return;
}
ps->size--;
}
5.获得栈顶元素
STDataType StackTop(Stack* ps)
{
if (ps->size == 0)
{
return (STDataType)0;
}
return ps->array[ps->size - 1];
}
6.获取栈中有效元素个数
int StackSize(Stack* ps)
{
return ps->size;
}
7.判断栈空
int StackEmpty(Stack* ps)
{
return ps->size == 0;
}
8.栈销毁
void StackDestory(Stack* ps)
{
if (ps->array)
{
free(ps->array);
ps->array = NULL;
ps->size = 0;
ps->capacity = 0;
}
}
二、队列
2.1队列的定义
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)的原则。
入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
常规简单队列(以数组方式实现)对先入队列的数据进行出队操作之后会空出一部分空间,此时后面的数据并不会自动进位补齐,容易造成空间浪费,而循环队列可以完美的解决这个问题。
循环队列的物理模型本质上也是普通的线性队列,其手段不过是设置了一个取模指针来重新指向前面出队列空出来的空余空间。
一般来说,不会让尾指针取模以后等于头指针,这是为了防止其判满与判空发生冲突。
![](https://img-blog.csdnimg.cn/269dde15c75c483cadecfdba7f1290ff.png)
2.2队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
![](https://img-blog.csdnimg.cn/190cd0db96fd4d3f8e1e9093477cfac8.png)
链式结构实现队列
1.定义节点
(由于是链表的应用,此处不需要定义固定大小的空间)
typedef struct QListNode
{
struct QListNode* _next;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;
QNode* _rear;
}Queue;
//建立新节点
QueueNode * BuyQueueNode(QuDataType x)
{
QueueNode * cur = (QueueNode *)malloc(sizeof(QueueNode));
cur->_data = x;
cur->_next = NULL;
return cur;
}
2.初始化队列
void QueueInit(Queue* q)
{
q->_front = NULL;
q->_rear = NULL;
}
3.入队
void QueuePush(Queue* q, QuDataType x)
{
QueueNode * cur = BuyQueueNode(x);
if (q->_front == NULL)
{
q->_front = q->_rear = cur;
}
else
{
q->_rear->_next = cur;
q->_rear = cur;
}
}
4.出队
void QueuePop(Queue* q)
{
if (q->_front == NULL)
{
return;
}
QueueNode* tmp = q->_front->_next;
free(q->_front);
q->_front = tmp;
}
5.获取队列头部元素
QuDataType QueueFront(Queue* q)
{
return q->_front->_data;
}
6.获取队列队尾元素
QuDataType QueueBack(Queue* q)
{
return q->_rear->_data;
}
7.获取队列中有效元素个数
int QueueSize(Queue* q)
{
QListNode * cur;
int count = 0;
for (cur = q->_front; cur; cur = cur->_next)
{
count++;
}
return count;
}
8.队列判空
int QueueEmpty(Queue* q)
{
return q->_front == NULL;
}
9.队列销毁
void QueueDestory(Queue* q)
{
if (q->_front == NULL)
{
return;
}
while (q->_front)
{
QueuePop(q);
}
}
(PS:对于链栈和数组队列本文不拿来凑字数)