栈和队列
队列结构
结构定义
FIFO先进先出的特性,与现实生活中的队列相似;
队列的假溢出: 由于顺序队列的出队和入队操作会导致空间的浪费,使得被出队元素存储空间无法再次使用;
解决方案:循环队列, 每当头尾指针指向存储空间的最后位置时重新分别调整头尾指针的位置;
typedef int data_t;
typedef struct queue {
data_t *data;
int head;
int tail;
int size;
int cnt;
}queue;
循环队列结构操作
队列出队
循环队列出队操作前需要先判空操作,当队列不为空时将待出队元素保存,随后将head指针向后移动一位,当head移动到顺序存储空间最后一位时,就将head重置为0;
data_t pop(queue *que) {
if (que == NULL) return -1;
if (empty(que)) return -1;
data_t elem = que->data[que->head];
if (++que->head >= que->size) que->head = 0;
que->cnt--;
return elem;
}
队列入队
循环队列入队前先判断是否队满,将新元素存储到tail指针指向的位置,随后将tail指针向后移动一位,并判断是否指向了顺序存储空间的最后一位,将tail重置为0;
int push(queue *que, data_t val) {
if (que == NULL) return 0;
if (que->cnt >= que->size) return 0;
que->data[que->tail] = val;
if (++que->tail >= que->size) que->tail = 0;
que->cnt++;
return 1;
}
队列判空
判空只需要判断cnt是否为0;
int empty(queue *que) {
return que->cnt == 0;
}
获取队首元素
获取队首元素首先判断队列是否为空,不为空就直接返回head指向的元素;
data_t front(queue *que){
return empty(que) ? -1 : que->data[que->head];
}
完整代码
循环队列
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef int data_t;
typedef struct queue {
data_t *data;
int head;
int tail;
int size;
int cnt;
}queue;
queue* init(int size) {
queue *que = (queue *)calloc(sizeof(queue), 1);
que->data = (data_t *)calloc(sizeof(data_t), size);
que->head = que->tail = 0;
que->size = size;
que->cnt = 0;
return que;
}
int empty(queue *que) {
return que->cnt == 0;
}
int push(queue *que, data_t val) {
if (que == NULL) return 0;
if (que->cnt >= que->size) return 0;
que->data[que->tail] = val;
if (++que->tail >= que->size) que->tail = 0;
que->cnt++;
return 1;
}
data_t pop(queue *que) {
if (que == NULL) return -1;
if (empty(que)) return -1;
data_t elem = que->data[que->head];
if (++que->head >= que->size) que->head = 0;
que->cnt--;
return elem;
}
data_t front(queue *que){
return empty(que) ? -1 : que->data[que->head];
}
void output(queue *que) {
if (que == NULL) return ;
printf("queue : [");
for (int i = 0, j = que->head; i < que->cnt; i++) {
i && printf(", ");
printf("%d", que->data[j]);
if (++j == que->size) j = 0;
}
printf("]\n");
return ;
}
void clear(queue *que) {
if (que == NULL) return ;
if (que->data) free(que->data);
free(que);
return ;
}
int main() {
#define max_op 20
int op, val;
srand(time(0));
queue *que = init(max_op);
for (int i = 0; i < max_op; i++) {
op = rand() % 4;
val = rand() % 100;
switch (op) {
case 0:
case 1: {
printf("push val[%d] into queue stat[%d] !\n", val, push(que, val));
} break;
case 2: {
printf("pop val from queue elem[%d] !\n", pop(que));
} break;
case 3: {
printf("get front elem from queue : [%d] !\n", front(que));
} break;
}
output(que);
}
#undef max_op
clear(que);
return 0;
}
栈结构
结构定义
具备FILO先进后出的特性, 与现实生活中的弹夹工作流程相似;
适合处理具有完全包含关系的问题;
typedef int data_t;
typedef struct stack {
data_t *data;
int top;
int size;
}stack;
结构操作
入栈操作
元素入栈前需要先行判断顺序存储空间是否已满,如果未满就将元素入栈,++top;
int push(stack *stk, data_t val) {
if (stk == NULL || stk->top + 1 == stk->size) return 0;
stk->data[++stk->top] = val;
return 1;
}
元素出栈时判断栈结构是否为空,不为空就返回top指针指向的元素, top指向下一个元素;
data_t pop(stack *stk) {
if (empty(stk)) return 0;
return stk->data[stk->top--];
}
获取栈顶元素需要先判断栈结构是否为空了,直接返回top指向的元素;
data_t top(stack *stk) {
if (stk == NULL || stk->top == -1) return -1;
return stk->data[stk->top];
}
判空栈结构为空,需要判断top == -1;
int empty(stack *stk) {
return stk == NULL ? 1 : stk->top == -1;
}
栈和队列的应用
栈:树的深度遍历、深度优先搜索
队列:树的层序遍历,广度优先搜索
单调栈:临界最值问题
单调队列:区间最值问题
完整代码
栈结构
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef int data_t;
typedef struct stack {
data_t *data;
int top;
int size;
}stack;
stack *init(int size) {
stack *stk = (stack *)calloc(sizeof(stack), 1);
stk->data = (data_t *)calloc(sizeof(data_t), size);
stk->size = size;
stk->top = -1;
return stk;
}
int empty(stack *stk) {
return stk == NULL ? 1 : stk->top == -1;
}
data_t top(stack *stk) {
if (stk == NULL || stk->top == -1) return -1;
return stk->data[stk->top];
}
int push(stack *stk, data_t val) {
if (stk == NULL || stk->top + 1 == stk->size) return 0;
stk->data[++stk->top] = val;
return 1;
}
data_t pop(stack *stk) {
if (empty(stk)) return 0;
return stk->data[stk->top--];
}
void output(stack *stk) {
if (stk == NULL) return ;
printf("stack :\n");
for (int i = stk->top; i >= 0; i--) {
i == stk->top && printf("top => ");
printf("\t| %2d |\n", stk->data[i]);
}
printf(" \t ———— \n");
return ;
}
void clear(stack *stk) {
if (stk == NULL) return ;
if (stk->data) free(stk->data);
free(stk);
return ;
}
int main() {
#define max_op 20
int op, val;
stack *stk = init(max_op);
srand(time(0));
for (int i = 0; i < max_op; i++) {
op = rand() % 4;
val = rand() % 100;
switch (op) {
case 0:
case 1: {
printf("push val[%d] to stack stat[%d] !\n", val, push(stk, val));
} break;
case 2: {
printf("pop elem from the stack val[%d] !\n", pop(stk));
} break;
case 3:{
printf("top elem of the stack val[%d] !\n", top(stk));
} break;
}
output(stk);
}
#undef max_op
clear(stk);
return 0;
}