概述
栈和队列都是非常常用的结构,它们与线性表逻辑相同,但特点在于运算存在限制。
队列按照 先进先出(FIFO, First In First Out) 的原则,即最先放入队列的元素最先退出;
栈按照 后进先出(LIFO, Last In First Out) 的原则,即最后放入队列的元素最先退出;
栈(Stack)
栈是一种计算机中非常常用的结构,如表达式求值、括号匹配、包括程序的运行都非常依赖这种结构。实际上,递归的程序也可以利用栈来实现。其结构非常简单,就不在赘述了,见下图:
定义
栈是一种只能通过访问它的一端来实现数据存储及检索的线性数据结构。栈的修改按照后进先出的原则实现,栈中进行插入和删除的一端称为栈顶(Top),相应的另一端称为栈底(Bottom),没有任何元素的栈称为空栈。将一个元素插入栈顶称为入栈,反之则为出栈。
基本运算
- isEmpty(S) 判断栈是否为空
- Push(S, x) 将元素x入栈
- Pop(S) 将栈顶元素出栈
- Top(S) 读栈顶元素
存储结构
栈是一种特殊的 线性表,与线性表一样,它也可以通过顺序或者链式存储实现。唯一不一样的是需要对访问做限制,实际上栈的实现比线性表要简单。
顺序存储实现的就是通过控制一个栈顶指针即数组(即连续存储空闲)实现。而链式存储(链表)的头指针实际上就是栈顶。
C实现
采用顺序存储方式实现,仅实现了上面提到的基本运算,分为两个文件:
- Stack.h 头文件,定义数据类型及函数说明
- Stack.c 函数实现
//Stack.h
#ifndef _STACK_H_
#define _STACK_H_
#include <stdio.h>
typedef char DataType;
typedef struct stack {
unsigned int size;
int count;
int pTop;
DataType *data;
}stack;
/*
初始化栈
操作结果:成功返回1,否则返回0(内存分配失败)
*/
int S_Initialize(stack *s, unsigned int size);
/*
判断栈是否为空
操作条件:s已初始化
操作结果:为空则返回1,否则返回0
*/
int S_isEmpty(stack s);
/*
入栈:将elem压入栈s
操作条件:s已初始化、未满
操作结果:成功返回1,否则返回0
*/
int S_Push(stack *s, DataType elem);
/*
出栈:将s栈顶元素弹出并返回
操作条件:s不为空
操作结果:成功返回栈顶元素,否则返回值不可预期。
*/
DataType S_Pop(stack *s);
/*
查看栈顶:将s栈顶元素返回,但不弹出
操作条件:s不为空
操作结果:成功返回栈顶元素,否则返回值不可预期。
*/
DataType S_Top(stack s);
#endif // !_STACK_H_
//Stack.c
#include "Stack.h"
#include <malloc.h>
//需要修改s的函数均使用stack *为参数。
int S_Initialize(stack *s, unsigned int size)
{
s->count = 0;
s->size = size;
s->pTop = 0;
s->data = malloc(sizeof(DataType)* size);
if (s->data == NULL)
{
fprintf(stderr, "Can't allocate memory!");
return 0;
}
return 1;
}
int S_isEmpty(stack s)
{
return s.count == 0;
}
int S_Push(stack *s, DataType elem)
{
if (s->count == s->size)
{
fprintf(stderr, "Stack is full!");
return 0;
}
s->data[++s->pTop] = elem;
s->count++;
return 1;
}
DataType S_Pop(stack *s)
{
if (S_isEmpty(*s))
{
fprintf(stderr, "Stack is empty!");
return (DataType)0;
}
s->count--;
return s->data[s->pTop--];
}
DataType S_Top(stack s)
{
if (S_isEmpty(s))
{
fprintf(stderr, "Stack is empty!");
return (DataType)0;
}
return s.data[s.pTop];
}
队列(Queue)
队列这一结构是人类社会生活中最常使用的,最主要的作用就是处理需要排队的事务。它和栈只是限制的不同,结构件下图:
定义
队列是一种只能在一端进入,另一端退出的线性数据结构。队列整体按照先进先出的原则实现修改及操作,允许插入元素的一端称为队尾(Rear),允许删除元素的一端则称为队首(Front)。将元素插入队列的操作称为入队,反之则为出队。
基本运算
- isEmpty(Q) 判断队列是否为空
- enQueue(Q, x) 将元素x入队
- deQueue(Q) 将队首元素出队
- frontQue(Q) 读队首元素
存储结构
队列也是一种特殊的线性表,与栈相同,它也可以通过顺序或者链式存储实现,只需要对访问做限制即可。
与栈不同,顺序存储实现的队列需要两个指针,一个标记队头位置,另一个则标记队尾位置来实现。而链式存储则要简单许多,只需要额外保存一个指向最后一个结点的尾指针即可。
C实现
采取链式存储结构实现,仅实现了简单的基本运算。有两个文件:
- Queue.h 定义数据类型,函数说明
- Queue.c 函数实现
//Queue.h
#ifndef _QUEUE_H_
#define _QUEUE_H_
typedef char DataType;
struct queueNode;
typedef struct queue {
struct queueNode *pFront;
struct queueNode *pRear;
int count;
}queue;
typedef struct queueNode {
DataType dat;
struct queueNode *next;
}queueNode;
/*
初始化队列
*/
void Q_Initialize(queue *q);
/*
判断队列是否为空
操作结果:是则返回1,否则返回0
*/
int Q_isEmpty(queue q);
/*
入队:将elem入队到q中
操作条件:q已初始化
操作结果:成功则返回1,否则返回0
*/
int Q_enQueue(queue *q, DataType elem);
/*
出队:将队首元素出队
操作条件:q已初始化且非空
操作结果:成功则返回队首元素,否则返回不可预期
*/
DataType Q_deQueue(queue *q);
/*
查看队首
操作条件:q已初始化且非空
操作结果:成功则返回队首元素,否则返回不可预期
*/
DataType Q_frontQue(queue q);
#endif // !_QUEUE_H_
//Queue.c
#include "Queue.h"
#include <stdio.h>
#include <malloc.h>
static queueNode* Q_newNode(DataType elem, queueNode *next)
{
queueNode *p = (queueNode*) malloc(sizeof(queueNode));
if (p == NULL)
return NULL;
p->dat = elem;
p->next = next;
return p;
}
void Q_Initialize(queue * q)
{
q->count = 0;
q->pFront = q->pRear = NULL;
}
int Q_isEmpty(queue q)
{
return q.count == 0;
}
int Q_enQueue(queue * q, DataType elem)
{
queueNode *p = Q_newNode(elem, NULL);
if (p == NULL)
{
fprintf(stderr, "Can't allocate memory!");
return 0;
}
if (Q_isEmpty(*q))
q->pRear = q->pFront = p;
else
{
q->pRear->next = p;
q->pRear = p;
}
q->count++;
return 1;
}
DataType Q_deQueue(queue * q)
{
if (Q_isEmpty(*q))
{
fprintf(stderr, "Queue is empty!");
return (DataType)0;
}
queueNode *p = q->pFront;
DataType temp = p->dat;
if (q->count == 1)
q->pFront = q->pRear = NULL;
else
q->pFront = p->next;
free(p);
q->count--;
return temp;
}
DataType Q_frontQue(queue q)
{
if (Q_isEmpty(q))
{
fprintf(stderr, "Queue is empty!");
return (DataType)0;
}
return q.pFront->dat;
}
文中图片来自互联网