目录
1.栈
1.1栈的概念及结构
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。形象一点就是吃进去吐出来,只是在一端进行操作。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
1.2栈的实现
栈的话用动态顺序表实现就是比较简单的,当然也可用单链表实现,但是注意一个问题,栈是不可以被遍历的,我们就用顺序表来实现
顺序结构
链式结构
1.3接口以及实现
Stack.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
typedef int Datatype;
//其实就是一个阉割版的顺序表
//我们知道栈是先进后出,只要给他的操作遵循就好了
typedef struct Stack {
//动态的栈
Datatype* arr;
int capacity;
//标记栈顶
int top;
}Stack;
//栈的初始化
void StackInit(Stack* p, int capacity);
//入栈
void StackPush(Stack* p, Datatype data);
//出栈
void StackPop(Stack* p);
//获取栈顶元素
Datatype Stacktop(Stack* p);
//获取栈的大小
int StackSize(Stack* p);
//判断栈是否为空
int StackEmpty(Stack* p);
//栈的销毁
void StackDestroy(Stack* p);
//栈的扩容
//阉割版的顺序表呀在此就不再赘述
void StackCheckCapacity(Stack* p);
Stack.c
#include "Stack.h"
//栈的初始化
void StackInit(Stack* p, int capacity)
{
//检测参数合法性
assert(p);
//对传入的capacity为负数的体现
capacity = capacity <= 0 ? 3 : capacity;
//动态在堆上申请空间来初始化栈
p->arr = (Datatype* )malloc(sizeof(Stack) * capacity);
//开辟未成功
if (NULL == p->arr) {
assert(0);
}
//更新参数
p->capacity = capacity;
p->top = 0;
}
//入栈
void StackPush(Stack* p, Datatype data)
{
StackCheckCapacity(p);
//直接压栈把data放在栈顶指针这块
p->arr[p->top] = data;
//栈顶指针++
p->top++;
}
//出栈
void StackPop(Stack* p)
{
//先得看看是否为空
if (StackEmpty(p)) {
return;
}
//栈顶指针--
p->top--;
}
//获取栈顶元素
Datatype Stacktop(Stack* p)
{
//先得看看是否为空
assert(p);
if (StackEmpty(p)) {
return;
}
// return ps->arr[--p->top]; // 错误写法
return p->arr[p->top - 1];
}
// 获取栈中有效元素的个数
int StackSize(Stack* p)
{
//检测参数合法性
assert(p);
return p->top;
}
// 检测栈是否为空,如果为空返回真,否则返回假
int StackEmpty(Stack* p)
{
//检测参数合法性
assert(p);
return 0 == p->top;
}
//栈的销毁
void StackDestroy(Stack* p)
{
//检测参数合法性
assert(p);
//free掉防止内存泄露
if (p->arr) {
free(p->arr);
p->capacity = 0;
p->top = 0;
}
}
//扩容
//先申请新的内存空间
//把原来的数据拷贝到新扩容的空间里面去
//free掉原来空间,让arr指向新开辟的内存空间
void StackCheckCapacity(Stack* p)
{
//检测参数合法性
assert(p);
if (p->capacity == p->top) {
int Newcapacity = (p->capacity << 1);
Datatype* temp = (Datatype*)malloc(sizeof(Datatype) * Newcapacity);
if (NULL == temp) {
assert(0);
}
memcpy(temp, p->arr, sizeof(Datatype) * p->capacity);
free(p->arr);
p->arr = temp;
p->capacity = Newcapacity;
}
}
int main() {
Stack s;
StackInit(&s,3);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", Stacktop(&s));
StackPush(&s, 4); // 扩容
StackPush(&s, 5);
StackPush(&s, 6);
StackPush(&s, 7); // 扩容
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", Stacktop(&s));
StackPop(&s);
StackPop(&s);
StackPop(&s);
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", Stacktop(&s));
StackDestroy(&s);
}
栈的初始化
//栈的初始化
void StackInit(Stack* p, int capacity)
{
//检测参数合法性
assert(p);
//对传入的capacity为负数的体现
capacity = capacity <= 0 ? 3 : capacity;
//动态在堆上申请空间来初始化栈
p->arr = (Datatype* )malloc(sizeof(Stack) * capacity);
//开辟未成功
if (NULL == p->arr) {
assert(0);
}
//更新参数
p->capacity = capacity;
p->top = 0;
}
- assret我们的老朋友先对参数合法性判断。
- 然后对capacity合法性判断,如果是负数就给他一个初始值,c++用缺省参数就规避掉了给他一个默认值就好了。
- 在堆上申请空间,然后对申请的空间进行判断是否申请成功了。
- 再更新我们的参数。
入栈
//入栈
void StackPush(Stack* p, Datatype data)
{
StackCheckCapacity(p);
//直接压栈把data放在栈顶指针这块
p->arr[p->top] = data;
//栈顶指针++
p->top++;
}
- 压栈把data放在栈顶部位。
- 在把站栈顶指针向上移动。
出栈
//出栈
void StackPop(Stack* p)
{
//先得看看是否为空
if (StackEmpty(p)) {
return;
}
//栈顶指针--
p->top--;
}
- 看看栈是否为空,要是空就直接返回,就不删除了。
- 然后栈顶指针向下移动。
获取栈顶元素
//获取栈顶元素
Datatype Stacktop(Stack* p)
{
//先得看看是否为空
assert(p);
if (StackEmpty(p)) {
return;
}
// return ps->arr[--p->top]; // 错误写法
return p->arr[p->top - 1];
}
- 先判空是否为空栈。
- 减1让我们栈顶指针指向栈顶元素。
- 然后直接把栈顶元素返回就好了。
获取栈中有效元素的个数
// 获取栈中有效元素的个数
int StackSize(Stack* p)
{
//检测参数合法性
assert(p);
return p->top;
}
-
直接把top输出传回来就好了。
检测栈是否为空
// 检测栈是否为空,如果为空返回真,否则返回假
int StackEmpty(Stack* p)
{
//检测参数合法性
assert(p);
return 0 == p->top;
}
- 判断是否为空其实就是栈顶指针是否等于栈底指针。
- 这里我们0就是栈底指针 top就是栈顶指针相等就是空。
栈的销毁
//栈的销毁
void StackDestroy(Stack* p)
{
//检测参数合法性
assert(p);
//free掉防止内存泄露
if (p->arr) {
free(p->arr);
p->capacity = 0;
p->top = 0;
}
}
- 先检验参数合法性。
- 把这个栈free掉。
- 再把参数更新。
扩容
//扩容
//先申请新的内存空间
//把原来的数据拷贝到新扩容的空间里面去
//free掉原来空间,让arr指向新开辟的内存空间
void StackCheckCapacity(Stack* p)
{
//检测参数合法性
assert(p);
if (p->capacity == p->top) {
int Newcapacity = (p->capacity << 1);
Datatype* temp = (Datatype*)malloc(sizeof(Datatype) * Newcapacity);
if (NULL == temp) {
assert(0);
}
memcpy(temp, p->arr, sizeof(Datatype) * p->capacity);
free(p->arr);
p->arr = temp;
p->capacity = Newcapacity;
}
}
- 开辟新的内存空间。
- 把数据拷贝到新空间去。
- 释放旧空间。
- p的arr指向新空间。
测试
void text() {
Stack s;
StackInit(&s, 3);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", Stacktop(&s));
StackPush(&s, 4); // 扩容
StackPush(&s, 5);
StackPush(&s, 6);
StackPush(&s, 7); // 扩容
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", Stacktop(&s));
StackPop(&s);
StackPop(&s);
StackPop(&s);
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", Stacktop(&s));
StackDestroy(&s);
}