栈和队列是两种重要的线性结构,从数据结构的角度看,栈和队列也是线性表,其特殊性在于栈和队列的基本操作是线性表的子集。他们是操作受限的线性表,因此,可称为限定性的数据结构。但从数据类型角度看,他们是和线性表大不相同的两类重要的的抽象数据类型。
1. 栈
栈的概念:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
栈的特性:后进先出LIFO(Last In First Out)。
栈的基本操作:栈的初始化、判空、判满、取栈顶元素、在栈顶进行插入和删除。在栈顶插入元素称为入栈,在栈顶删除元素称为出栈。
1. 代码实现:
stack.h:
#ifndef __STACK_H__
#define __STACK_H__
typedef int DataType;
typedef struct Stack
{
DataType* array;
int capacity;
int size;
}Stack;
//初始化栈
void StackInit(Stack* ps);
//检查容量
void CheckCapacity(Stack* ps);
//压栈
void StackPush(Stack* ps, DataType data);
//出栈
void StackPop(Stack* ps);
//返回栈顶元素值
DataType StackTop(Stack* ps);
//返回压入栈的元素数量
int StackSize(Stack* ps);
//判断栈空
int StackEmpty(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);
#endif // !__STACK_H__
stack.c:
#include"stack.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//初始化栈
void StackInit(Stack* ps)
{
assert(ps);
ps->array = (DataType*)malloc(sizeof(DataType) * 5);
if (NULL == ps->array)
{
assert(0);
return;
}
ps->capacity = 5;
ps->size = 0;
}
//检查容量
void CheckCapacity(Stack* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
ps->array = (DataType*)realloc(ps->array, sizeof(DataType)*(ps->capacity) * 2);
if (NULL == ps->array)
{
assert(0);
return;
}
ps->capacity *= 2;
}
}
//压栈
void StackPush(Stack* ps, DataType data)
{
assert(ps);
CheckCapacity(ps);
ps->array[ps->size] = data;
ps->size++;
}
//出栈
void StackPop(Stack* ps)
{
assert(ps);
if (StackEmpty(ps))
{
return;
}
ps->size--;
}
//返回栈顶元素值
DataType StackTop(Stack* ps)
{
assert(ps&&StackEmpty(ps)==0);
return ps->array[ps->size - 1];
}
//返回压入栈的元素数量
int StackSize(Stack* ps)
{
assert(ps);
return ps->size;
}
//判断栈空
int StackEmpty(Stack* ps)
{
assert(ps);
return 0==ps->size;
}
//销毁栈
void StackDestroy(Stack* ps)
{
assert(ps);
if (ps->array)
{
free(ps->array);
ps->array = NULL;
ps->capacity = 0;
ps->size = 0;
}
}
2. 测试代码:
#include<stdio.h>
#include"stack.h"
int main()
{
Stack p;
Stack *ps = &p;
StackInit(ps);
printf("将2,3,4,5,6依次压入栈\n");
StackPush(ps, 1);
StackPush(ps, 2);
StackPush(ps, 3);
StackPush(ps, 4);
StackPush(ps, 5);
StackPush(ps, 6);
printf("栈顶元素值为%d\n", StackTop(ps));
printf("栈内元素数量为%d\n\n", StackSize(ps));
printf("出栈\n");
StackPop(ps);
printf("栈顶元素值为%d\n", StackTop(ps));
printf("栈内元素数量为%d\n\n", StackSize(ps));
printf("出栈\n");
StackPop(ps);
printf("栈顶元素值为%d\n", StackTop(ps));
printf("栈内元素数量为%d\n\n", StackSize(ps));
printf("出栈\n");
StackPop(ps);
printf("栈顶元素值为%d\n", StackTop(ps));
printf("栈内元素数量为%d\n\n", StackSize(ps));
StackDestroy(ps);
return 0;
}
3. 栈的应用(括号匹配)
逻辑:
- 依次获取每个括号
- 判断他们是左括号还是右括号,如果是左括号直接入栈,如果是右括号,先看栈顶元素是否与之配对,如果栈空或者不配对直接返回false,如果配对,将栈顶元素出栈。
- 最后看栈是否为空,如果栈空则返回ture,反之返回false。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
#include"stack.h"
//判断括号是否配对
bool PairingBracket(char* str)
{
assert(str);
Stack* ps = (Stack*)malloc(sizeof(Stack));
int i = 0;
StackInit(ps);
while (str[i])
{
if ('(' == str[i] || '[' == str[i] || '{' == str[i])
{
StackPush(ps, str[i]);
}
if (')' == str[i] || ']' == str[i] || '}' == str[i])
{
if (0 == StackEmpty(ps) && ((')' == str[i] && '(' == StackTop(ps)) || \
(']' == str[i] && '[' == StackTop(ps)) || \
('}' == str[i] && '{' == StackTop(ps)) ))
StackPop(ps);
else
{
free(ps);
return false;
}
}
i++;
}
if (0 == StackEmpty(ps))
{
free(ps);
return false;
}
free(ps);
return true;
}
int main()
{
char str[100];
scanf("%s", str);
if (PairingBracket(str))
{
printf("括号完全匹配\n");
}
else
printf("括号匹配失败\n");
return 0;
}
2. 队列
队列的概念:队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
1. 队列的实现
queue.h
#ifndef __QUEUE_H__
#define __QUEUE_H__
// 链式结构:表示队列
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* next;
QDataType data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* front;
QNode* rear;
}Queue;
void QueueInit(Queue* q);// 初始化队列
void QueuePush(Queue* q, QDataType data);// 队尾入队列
QDataType QueuePop(Queue* q);// 队头出队列
QDataType QueueFront(Queue* q);// 获取队列头部元素
QDataType QueueBack(Queue* q);// 获取队列尾部元素
int QueueSize(Queue* q);// 获取队列中有效元素个数
int QueueEmpty(Queue* q);// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
void QueueDestroy(Queue* q);// 销毁队列
#endif // !__QUEUE_H__
queue.c
#include<assert.h>
#include<stdlib.h>
#include"queue.h"
QNode* BuyQueueNode(QDataType data)
{
QNode* node = (QNode*)malloc(sizeof(QNode));
if (NULL == node)
{
assert(0);
return NULL;
}
node->data = data;
node->next = NULL;
return node;
}
// 初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->front = q->rear = BuyQueueNode(0);
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q);
q->rear->next = BuyQueueNode(data);
q->rear = q->rear->next;
}
// 队头出队列
QDataType QueuePop(Queue* q)
{
assert(q);
if (QueueEmpty(q)) //如果为空直接跳出函数
return 0;
QNode* DelNode = q->front->next;
QDataType temp = DelNode->data;
q->front->next = DelNode->next;
if (q->front->next == 0)
{
q->rear = q->front;
}
free(DelNode);
return temp;
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q);
if (QueueEmpty(q))
return 0;
return q->front->next->data;
}
// 获取队列尾部元素
QDataType QueueBack(Queue* q)
{
assert(q);
if (QueueEmpty(q))
return 0;
return q->rear->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);
int count = 0;
QNode* pcurrent = q->front->next;
while (pcurrent)
{
count++;
pcurrent = pcurrent->next;
}
return count;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{
assert(q);
return NULL == q->front->next;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
assert(q);
QNode* pcurrent = q->front;
while (pcurrent)
{
q->front = pcurrent->next;
free(pcurrent);
pcurrent = q->front;
}
q->rear = NULL;
free(q);
q = NULL;
}
}
2.测试代码:
test.c
#include<stdio.h>
#include"queue.h"
int main()
{
Queue Q;
Queue* pQ = &Q;
QueueInit(pQ);
QueuePush(pQ, 1);
QueuePush(pQ, 2);
QueuePush(pQ, 3);
QueuePush(pQ, 4);
QueuePush(pQ, 5);
printf("队头元素为:%d\n",QueueFront(pQ));
printf("队尾元素为:%d\n",QueueBack(pQ));
printf("队内有效元素个数:%d\n", QueueSize(pQ));
printf("执行一次出队操作\n");
QueuePop(pQ);
printf("队头元素为:%d\n", QueueFront(pQ));
printf("队尾元素为:%d\n", QueueBack(pQ));
printf("队内有效元素个数:%d\n", QueueSize(pQ));
printf("执行一次出队操作\n");
QueuePop(pQ);
printf("队头元素为:%d\n", QueueFront(pQ));
printf("队尾元素为:%d\n", QueueBack(pQ));
printf("队内有效元素个数:%d\n", QueueSize(pQ));
QueueDestroy(pQ);
return 0;
}