目录
前言:
前面介绍了顺序表、单链表(单向非循环链表)、双链表(双向循环链表),基本上已经结束了链表的讲解,今天谈一下栈和队列。可以简单的说是前面学习的一特殊化实现,但是总体是相似的。
栈
一、栈的基本概念
1、栈的定义
栈:⼀种特殊的线性表,只允许在固定的⼀端进行插入和删除元素操作。进行数据插⼊和删除操作 的⼀端称为栈顶,另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO(LastInFirstOut)的原则。
栈顶:能进行进栈(插入)和出栈(删除)操作。
栈底:固定的,不能进行任何操作。
空栈:没有任何元素,栈顶=栈底。
2、栈的常见的基础操作
● STInit(&st):初始化一个空栈st。
● STEmpty(&st):判断一个栈是否为空,若栈为空则返回true,否则返回false。
● STPush(&st,x):进栈(栈的插入操作),若栈st未满,则将x加入使之成为新栈顶。
● STPop(&st):出栈(栈的删除操作),若栈st非空,则弹出栈顶元素,并用x返回。● STCheckCapacity(&st):增容,栈顶等于栈的空间大小时,空间增大一倍。
● STSize(&st):大小,计算队列元素个数,返回capacity。
● GetTop(&st):读栈顶元素,若栈st非空,则用top返回栈顶元素。
● STDestroy(st):栈销毁,并释放st占用的存储空间。
3、栈的实现
(1)结构体
typedef int STDataType;
typedef struct stack
{
STDataType* a;
int top; //栈顶
int capacity; //栈的空间大小
}ST;
(2)初始化
void STInit(ST* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType)*4);
if (ps->a == NULL)
{
perror("malloc fail");
return;
}
ps->capacity = 4;
ps->top = 0;
}
(3)进栈(插入操作)
void STpush(ST* ps,STDataType x)
{
assert(ps);
ps->a[ps->top] = x;
ps->top++;
}
(4)出栈(删除操作)
void STPop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
(5)计算栈内元素个数
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
(6)判断栈内是否为空
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
(7)读取栈顶元素
STDataType STTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps))
return ps->a[ps->top-1];
}
(8)销毁
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
(9)增容
//检查容量
void CheckCapacity(ST*ps)
{
assert(ps);
if (ps->top == ps->capacity)
{
ST* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * (ps->capacity) * 2);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
ps->capacity *= 2;
ps->a = tmp;
}
}
队列
一、队列的基本概念
1、队列的定义
队列:只允许在⼀端进⾏插⼊数据操作,在另⼀端进⾏删除数据操作的特殊线性表,队列具有先进先 出FIFO(First In First Out)。允许插入的一端称为队尾,允许删除的一端称为队头。
- 队头:进行删除的一端,又称队首。
队尾:进行插入的一端。
空队列:不包含任何元素的空表。
2、队列的常见的基础操作
● QueueInit(&s):初始化队列,构造一个空队列ps。
● QueueEmpty(s):判队列空,若队列ps为空返回true,否则返回false。
● QueuePush(&s, x):入队,若队列ps未满,将x加入,使之成为新的队尾。
● QueuePop(&s):出队,若队列ps非空,删除队头元素,并用x返回。
● QueueFront(s, &x):读队头元素,若队列ps非空,则将队头元素赋值给x。● QueueBack:读队尾元素,若队列ps非空,则将队头元素赋值给x。
● QueueDestroy(&s):队列销毁,并释放ps占用的存储空间。
3、队列的实现
(1)结构体
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* phead;//队头
QueueNode* ptail;//队尾
int size; //队内元素个数
}Queue;
(2)初始化
void QueueInit(Queue* ps)
{
assert(ps);
ps->phead = ps->ptail = NULL;
ps->size = 0;
}
(3)入队(插入操作)
void QueuePush(Queue* ps, QDataType x)
{
assert(ps);
//创建一个节点newnode
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
//当队列为空时
if (ps->phead == NULL)
{
ps->phead = ps->ptail = newnode;
}
//队列不为空时
else
{
ps->ptail->next = newnode;
ps->ptail = newnode;
}
ps->size++;
}
(4)判断队列是否为空
bool QueueEmpty(Queue* ps)
{
assert(ps);
return ps->phead = NULL && ps->ptail == NULL;
}
(5)出队(删除操作)
void QueuePop(Queue* ps)
{
assert(ps);
assert(! QueueEmpty(ps));
//只有一个节点时,避免ptail成为野指针
if (ps->ptail == ps->phead)
{
free(ps->phead);
ps->phead = ps->ptail = NULL;
}
else
{
//删除头元素
QueueNode* next = ps->phead->next;
free(ps->phead);
ps->phead = next;
}
ps->size--;
}
(6)读取队头数据
QDataType QueueFront(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
return ps->phead->data;
}
(7)读取队尾数据
QDataType QueueBack(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
return ps->ptail->data;
}
(8)计算队内元素个数
int Queuesize(Queue* ps)
{
assert(ps);
return ps->size;
}
(9)销毁
void QueueDestroy(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
QueueNode* pcur = ps->phead;
while (pcur)
{
QueueNode* next = pcur->next;
free(pcur);
pcur = next;
}
ps->phead = ps->ptail = NULL;
ps->size = 0;
}
总结
栈
头文件Stack.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int STDataType;
typedef struct stack
{
STDataType* a;
int top;
int capacity;
}ST;
//初始化
void STInit(ST* ps);
//压栈
void STpush(ST* ps, STDataType x);
//删除
void STPop(ST* ps);
//大小
int STSize(ST* ps);
//判空
bool STEmpty(ST* ps);
//出栈
STDataType STTop(ST* ps);
//检查容量
void CheckCapacity(ST* ps);
//销毁
void STDestroy(ST* ps);
Stack.c
#define _CRT_SECURE_NO_WARNINGS
#include "stack.h"
//初始化
void STInit(ST* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType*)*4);
if (ps->a == NULL)
{
perror("malloc fail");
return;
}
ps->capacity = 4;
ps->top = 0;
}
//销毁
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
//检查容量
void CheckCapacity(ST*ps)
{
assert(ps);
if (ps->top == ps->capacity)
{
ST* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * (ps->capacity) * 2);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
ps->capacity *= 2;
ps->a = tmp;
}
}
//压栈
void STpush(ST* ps,STDataType x)
{
assert(ps);
ps->a[ps->top] = x;
ps->top++;
}
//删除
void STPop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
//判空
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//出栈
STDataType STTop(ST* ps)
{
assert(ps);
return ps->a[ps->top-1];
}
//大小
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
测试文件test.c
#define _CRT_SECURE_NO_WARNINGS
#include "stack.h"
void teststack()
{
ST st;
STInit(&st);
STpush(&st, 1);
STpush(&st, 2);
STpush(&st, 3);
STpush(&st, 4);
STpush(&st, 5);
printf("%d", STSize(&st));
printf("\n");
while (!STEmpty(&st))
{
printf("%d ", STTop(&st));
STPop(&st);
}
printf("\n");
printf("%d", STSize(&st));
STDestroy(&st);
}
int main()
{
teststack();
return 0;
}
队列
头文件Queue.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
//定义队列的结构
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* phead;
QueueNode* ptail;
int size;
}Queue;
//链表的实现
//初始化
void QueueInit(Queue* ps);
//入栈
void QueuePush(Queue* ps, QDataType x);
//队列判空
bool QueueEmpty(Queue* ps);
//出栈
void QueuePop(Queue* ps);
//取队头数据
QDataType QueueFront(Queue* ps);
//取队尾数据
QDataType QueueBack(Queue* ps);
//队列有效元素
int Queuesize(Queue* ps);
//销毁队列
void QueueDestroy(Queue* ps);
Queue.c
#include"Queue.h"
//初始化
void QueueInit(Queue* ps)
{
assert(ps);
ps->phead = ps->ptail = NULL;
ps->size = 0;
}
//入栈
void QueuePush(Queue* ps, QDataType x)
{
assert(ps);
//创建一个节点newnode
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
//当队列为空时
if (ps->phead == NULL)
{
ps->phead = ps->ptail = newnode;
}
//队列不为空时
else
{
ps->ptail->next = newnode;
ps->ptail = newnode;
}
ps->size++;
}
//队列判空
bool QueueEmpty(Queue* ps)
{
assert(ps);
return ps->phead = NULL && ps->ptail == NULL;
}
//出栈
void QueuePop(Queue* ps)
{
assert(ps);
assert(! QueueEmpty(ps));
//只有一个节点时,避免ptail成为野指针
if (ps->ptail == ps->phead)
{
free(ps->phead);
ps->phead = ps->ptail = NULL;
}
else
{
//删除头元素
QueueNode* next = ps->phead->next;
free(ps->phead);
ps->phead = next;
}
ps->size--;
}
//取队头数据
QDataType QueueFront(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
return ps->phead->data;
}
//取队尾数据
QDataType QueueBack(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
return ps->ptail->data;
}
//队列有效元素
int Queuesize(Queue* ps)
{
assert(ps);
return ps->size;
}
//销毁队列
void QueueDestroy(Queue* ps)
{
assert(ps);
assert(!QueueEmpty(ps));
QueueNode* pcur = ps->phead;
while (pcur)
{
QueueNode* next = pcur->next;
free(pcur);
pcur = next;
}
ps->phead = ps->ptail = NULL;
ps->size = 0;
}
测试文件test.c
#define _CRT_SECURE_NO_WARNINGS
#include "queue.h"
void testQueue()
{
Queue s;
QueueInit(&s);
QueuePush(&s, 1);
QueuePush(&s, 2);
QueuePush(&s, 3);
QueuePush(&s, 4);
//printf("%d ", QueueTop(&s));
//QueuePop(&s);
//printf("%d ", QueueTop(&s));
//QueuePop(&s);
//printf("%d ", QueueTop(&s));
//QueuePop(&s);
//printf("%d ", QueueTop(&s));
//QueuePop(&s);
//printf("\n");
while (!(QueueEmpty(&s)))
{
printf("%d ", QueueTop(&s));
QueuePop(&s);
}
QueueDestroy(&s);
}
int main()
{
testQueue();
return 0;
}