【数据结构入门】栈(Stack)详解(初始化、增、删、查、判空)

时间:2023-03-14 22:56:25

1、栈

1.1栈的概念及结构

栈(stack)是限定仅在表尾进行插入或者删除的线性表。对于栈来说,表尾端称为栈顶(top),表头端称为栈低(bottom)。不含元素的空表称为空栈。因为栈限定在表尾进行插入或者删除,所以栈又被称为​后进先出​的线性表(简称LIFO:​Last in, First out.​结构)。

​压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶

出栈:栈的删除操作叫做出栈。出数据也在栈顶

【数据结构入门】栈(Stack)详解(初始化、增、删、查、判空)



1.2栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。时间复杂度更小。

【数据结构入门】栈(Stack)详解(初始化、增、删、查、判空)

一般我们以能实现动态增长的栈为标准,以下为需要实现的栈操作:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDataType;
typedef struct Stack
{
STDataType* a; //动态顺序
int top; //栈顶的位置
int capacity; //容量


}ST;

//栈的初始化
void StackInit(ST* ps);
//栈的销毁
void StackDesroy(ST* ps);

// push就是放栈顶
void StackPush(ST* ps,STDataType x);
void StackPop(ST* ps); //删除

STDataType StackTop(ST* ps); //查看栈顶的数据

//栈内的个数
int StackSize(ST* ps);
//检查是否为空
bool StackEmpty(ST* ps);

注意我们在判空的时候需要使用布尔值,头文件需要包含一个#include<stdbool.h>


1.2.1栈的初始化

栈的初始化,我们的栈顶可以设置为-1或者0,如果设置为-1,那么top就是栈顶的下标,如果设置为0,那么栈顶的下标就是top-1。本文选用的是top=0。然后容量我们设为0,在push 压栈的时候判断增容。我们的数组指针置为NULL,防止野指针出现。

void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;

}

1.2.2栈的销毁

因为通过malloc动态开辟的数组存储数据,基本上地址是连续的也就是原地扩容(也存在异地扩容),那么我们释放的时候要释放malloc返回的指针地址。

void StackDesroy(ST* ps)
{

assert(ps);
free(ps->a);
ps->a = NULL;


}

1.2.3 进栈操作(个人理解成尾插)

在插入之前判断是否容量满了,满了就扩容

void StackPush(ST* ps, STDataType x)
{
assert(ps);

if (ps->top == ps->capacity)
{
//增容 //如果栈的capacity为0 就先赋成4 如果不是就扩容两倍
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; //三目操作判断
//数组扩容
STDataType* tmp =(STDataType*)realloc(ps->a, sizeof(STDataType)* newCapacity);
//增加程序健壮性
if (tmp == NULL)
{
perror("realloc fail");
return;
}
//把新的空间给到a
ps->a = tmp;
ps->capacity = newCapacity; //更新容量
}

ps->a[ps->top] = x; //插入数据
ps->top++; //更新top

}

1.2.4出栈操作(个人理解为尾删)

相当于顺序表的尾删,只需要改变top就可以,一定要注意空栈问题,所以要断言ps->top

void StackPop(ST* ps)
{
assert(ps);
//有一个问题就是最后的空栈
//暴力检查
assert(ps->top);
ps->top--;

}

1.2.5查看栈顶的数据

一定要判空,因为会怕越界,所以进行暴力断言来判空

STDataType StackTop(ST* ps)
{
assert(ps);
//如果删空了怎么办
//那么返回的是随机数
assert(!StackEmpty(ps));

return ps->a[ps->top - 1];
}

1.2.6查看栈内的个数

返回top就可以

int StackSize(ST* ps)
{

assert(ps);

return ps->top;

}

1.2.7判空

bool StackEmpty(ST* ps)
{

/*if (ps->top == 0)
{
return true;
}
else
{
return false;
}*/

return ps->top == 0;



}




2、整体代码实现

Stack.h

#pragma once


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>



typedef int STDataType;
typedef struct Stack
{
STDataType* a; //动态顺序
int top; //栈顶的位置
int capacity; //容量


}ST;

//栈的初始化
void StackInit(ST* ps);
//栈的销毁
void StackDesroy(ST* ps);

// push就是放栈顶
void StackPush(ST* ps,STDataType x);
void StackPop(ST* ps); //删除

STDataType StackTop(ST* ps); //查看栈顶的数据

//栈内的个数
int StackSize(ST* ps);
//检查是否为空
bool StackEmpty(ST* ps);


Stack.c

#include"Stack.h"

void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;

}


void StackPush(ST* ps, STDataType x)
{
assert(ps);

if (ps->top == ps->capacity)
{
//增容 //如果单钱capacity为0 就先赋成4 如果不是就扩容两倍
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//数组扩容
STDataType* tmp =(STDataType*)realloc(ps->a, sizeof(STDataType)* newCapacity);

if (tmp == NULL)
{
perror("realloc fail");
return;
}
//把新的空间给到a
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}


void StackPop(ST* ps)
{
assert(ps);
//有一个问题就是最后的空栈
//暴力检查
if (ps->top > 0)
{
ps->top--;
}

}



STDataType StackTop(ST* ps)
{
assert(ps);
//如果删空了怎么办
//那么返回的是随机数
assert(!StackEmpty(ps));

return ps->a[ps->top - 1];

}


int StackSize(ST* ps)
{

assert(ps);

return ps->top;

}



bool StackEmpty(ST* ps)
{

/*if (ps->top == 0)
{
return true;
}
else
{
return false;
}*/

return ps->top == 0;



}

void StackDesroy(ST* ps)
{


assert(ps);
free(ps->a);
ps->a = NULL;


}

test.c

// 进出数据的地方叫栈顶     栈是先进后出 后进先出
// 数组栈 、 链式栈
//如果用尾做栈顶 尾插尾删 要设计成双向链表 否则删除数据效率低
//如果用头做栈顶 头插头删 就可以设计成单链表

//顺序栈


#include"Stack.h"
#include<stdio.h>

void TestSatck()
{

ST st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);

while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
int ret=StackSize(&st);
printf("%d", ret);
}
int main()
{
TestSatck();


return 0;
}

代码运行图片

【数据结构入门】栈(Stack)详解(初始化、增、删、查、判空)