上一章我们对带头双向循环链表做了代码实现,并简单说明了顺序存储和链式存储的优缺点比较,这一章我们来对一种特殊的线性表---栈进行代码实现。
文章目录
- 前言
- 栈的初始化
- 栈的销毁
- 栈的内存空间检查
- 入栈
- 出栈
- 返回栈顶数据
- 检查栈的大小
- 检查栈是否为空
- 头文件代码
- 源文件代码
前言
typedef struct stack {
dataType* arr;
size_t top;
size_t capacity;
}stack;
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。(直接搬百度了)
栈其实总结就一句话->后进先出,就像子弹夹,最早压进去的子弹都是最后打出去,最后压进去的子弹都是最先打出来。
实现栈我们可以用顺序存储,也可以用链式存储,两者各有特点我们上一章结尾也分析过。如果想用链表来存储,那么我们需要用尾来做栈底,因为头插头删相对于尾插尾删效率要高(因为单链表无法访问到上一个元素,且如果用头来做栈底我们每次都需要从头遍历到尾再进行出入栈操作,会很复杂)。不过本章我们还是用顺序存储来实现栈,用arr指向动态开辟的数组,top记录栈中数据个数,capacity记录栈的容量。
(由于前三章我们已经介绍过很多代码实现了,栈的实现也是相对很简单的,所以我们有些简单的解释就不再赘述)
栈的初始化
void stackInit(stack* ps) {
assert(ps);
ps->arr = NULL;
ps->top = 0;
ps->capacity = 0;
}
栈的销毁
void stackDestroy(stack* ps) {
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->top = 0;
ps->capacity = 0;
}
栈的内存空间检查
void stackCheckCapacity(stack* ps) {
assert(ps);
if (ps->top == ps->capacity) {
size_t newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
dataType* tmp = (dataType*)realloc(ps->arr, sizeof(dataType) * newCapacity);
if (tmp == NULL) {
printf("realloc fail");
exit(-1);
}
else {
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
}
入栈
void stackPush(stack* ps, dataType val) {
assert(ps);
stackCheckCapacity(ps);
ps->arr[ps->top] = val;
ps->top++;
}
我们初始化是讲top置为0,所以插入第一个数据是0下标对应的就是栈底第一个元素。
出栈
void stackPop(stack* ps) {
assert(ps && ps->top);
ps->top--;
}
返回栈顶数据
dataType stackTop(stack* ps) {
assert(ps && ps->top);
return ps->arr[ps->top - 1];
}
这里需要注意的是top是个数,所以top一定大于0,但访问栈顶的数据需要top-1。
检查栈的大小
size_t stackSize(stack* ps) {
assert(ps);
return ps->top;
}
检查栈的大小只需要返回top。
检查栈是否为空
bool stackEmpty(stack* ps) {
assert(ps);
return ps->top == 0;
}
这里用了一种简单的代码风格,看看top是否为0,为0表达式为真说明栈为空返回true,不为0表达式为假说明栈不为空则返回false。
头文件代码
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int dataType;
typedef struct stack {
dataType* arr;
size_t top;
size_t capacity;
}stack;
//栈的初始化
void stackInit(stack* ps);
//栈的销毁
void stackDestroy(stack* ps);
//栈的内存空间检查
void stackCheckCapacity(stack* ps);
//入栈
void stackPush(stack* ps, dataType val);
//出栈
void stackPop(stack* ps);
//返回栈顶数据
dataType stackTop(stack* ps);
//检查栈的大小
size_t stackSize(stack* ps);
//检查栈是否为空
bool stackEmpty(stack* ps);
源文件代码
#include "stack.h"
void stackInit(stack* ps) {
assert(ps);
ps->arr = NULL;
ps->top = 0;
ps->capacity = 0;
}
void stackDestroy(stack* ps) {
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->top = 0;
ps->capacity = 0;
}
void stackCheckCapacity(stack* ps) {
assert(ps);
if (ps->top == ps->capacity) {
size_t newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
dataType* tmp = (dataType*)realloc(ps->arr, sizeof(dataType) * newCapacity);
if (tmp == NULL) {
printf("realloc fail");
exit(-1);
}
else {
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
}
void stackPush(stack* ps, dataType val) {
assert(ps);
stackCheckCapacity(ps);
ps->arr[ps->top] = val;
ps->top++;
}
void stackPop(stack* ps) {
assert(ps && ps->top);
ps->top--;
}
dataType stackTop(stack* ps) {
assert(ps && ps->top);
return ps->arr[ps->top - 1];
}
size_t stackSize(stack* ps) {
assert(ps);
return ps->top;
}
bool stackEmpty(stack* ps) {
assert(ps);
return ps->top == 0;
}