目录:
目录
一.基本概念
动态数组是指在程序运行过程中可以根据需要动态地增加或缩小容量的一种数组结构。动态数组实现的栈结构相比于静态数组或链表的实现方式具有灵活性和高效性,因此被广泛应用在计算机科学的诸多领域中。本篇博客将详细介绍动态数组实现的栈结构的细节。
1.栈的基本概念
栈(Stack)是一种特殊的线性数据结构,它具有“先进后出”(Last In First Out,LIFO)的特点,即最先入栈的元素最后出栈,而最后入栈的元素最先出栈。栈通常用一个指针变量来指示栈顶,每次取出一个元素时该指针向下移动,添加元素时该指针向上移动。
2.动态数组的概念
动态数组可以动态地增加或缩小容量,以满足程序运行时的要求。使用动态数组实现栈结构,可以优化空间利用效率,在内存不足时自动扩容以避免内存不足错误。
3.动态数组实现的栈结构的优缺点
使用动态数组实现栈结构的优点:
- 空间利用效率高:在栈空间不足时可以自动扩容,避免内存溢出的问题。
- 时间复杂度低:因为使用了数组结构,所以可以通过下标随机访问任何一个元素,插入和删除操作时间复杂度为O(1)。
使用动态数组实现栈结构的缺点:
- 容易浪费空间:如果没有合理设置扩容策略,则可能会分配过多或过少的内存。
- 插入与删除操作可能导致数据搬移:如果要在动态数组的中间位置插入或删除元素,就需要将后面的所有元素向右或左移动一位。因此,在处理大量数据时,插入和删除操作可能会非常耗时。
二.具体的实现
这段代码实现了一个基于动态数组实现的栈结构,具体实现细节如下:
- STInit:初始化栈,为栈分配内存空间并将栈顶初始化为0。
- STDestroy:销毁栈,释放栈占用的内存空间,并将栈顶、容量等属性重置。
- STPush:向栈中插入数据,如果栈已满则扩大栈的容量。
- STPop:从栈中删除数据,如果栈为空则不进行任何操作。
- STSize:获取栈中数据元素的数量。
- STEmpty:判断栈是否为空。
- STTop:获取栈顶的数据元素。
STInit函数用于初始化栈,其中:
- assert(ps)用于判断ps是否为空指针,如果为空指针则会直接终止程序运行;
- ps->a =(STDataType*)malloc(sizeof(STDataType)*4);为数组a分配4个STDataType类型的空间;
- ps->capacity = 4;将栈的初始容量设定为4;
- ps->top = 0;将栈顶元素的位置置为0。
STDestroy函数用于销毁栈,其中:
- assert(ps)用于判断ps是否为空指针,如果为空指针则会直接终止程序运行;
- free(ps->a);释放栈占用的内存空间;
- ps->a = NULL;将指向数组a的指针置为空指针,防止野指针的产生;
- ps->top = 0;将栈顶元素的位置置为0;
- ps->capacity = 0;将栈的容量置为0。
STPush函数用于向栈中插入数据,其中:
- assert(ps)用于判断ps是否为空指针,如果为空指针则会直接终止程序运行;
- if (ps->top == ps->capacity)判断当前栈是否已满,如果已满则需要扩大栈的容量;
- STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) ps->capacity2);使用realloc函数将数组a的容量扩大为原来的两倍;
- ps->a = tmp;将a指针指向重新分配的空间;
- ps->capacity*=2;将栈的容量设定为现在的两倍;
- ps->a[ps->top] = x;将要插入的元素存放在栈顶所在位置;
- ps->top++;将栈顶的位置加1。
STPop函数用于从栈中删除数据,其中:
- assert(ps)用于判断ps是否为空指针,如果为空指针则会直接终止程序运行;
- assert(!STEmpty(ps))判断栈是否为空,如果为空则会直接终止程序运行;
- ps->top--;将栈顶的位置减1,即删除栈顶元素。
STSize函数用于获取栈中元素的数量,其中:
- assert(ps)用于判断ps是否为空指针,如果为空指针则会直接终止程序运行;
- return ps->top;返回栈顶元素的位置,即栈中元素的数量。
STEmpty函数用于判断栈是否为空,其中:
- assert(ps)用于判断ps是否为空指针,如果为空指针则会直接终止程序运行;
- return ps->top == 0;如果栈顶位置为0,则表示栈为空,返回true;否则返回false。
STTop函数用于获取栈顶元素,其中:
- assert(ps)用于判断ps是否为空指针,如果为空指针则会直接终止程序运行;
- assert(!STEmpty(ps))用于判断栈是否为空,如果为空则会直接终止程序运行;
- return ps->a[ps->top - 1];返回栈顶元素的值。
三.代码的展示
- 1.STInit:初始化栈,为栈分配内存空间并将栈顶初始化为0。
void STInit(ST* ps)//初始化
{
assert(ps);
ps->a =(STDataType*)malloc(sizeof(STDataType)*4);
if (ps->a == NULL) {
printf("malloc fail\n");
return;
}
ps->capacity = 4;
ps->top = 0;//ps->top = 1;
//top=0,意味着top指向栈顶数据的下一个,top=-1指向的是栈顶数据
}
- 2.STDestroy:销毁栈,释放栈占用的内存空间,并将栈顶、容量等属性重置。
void STDesroy(ST* ps)//销毁
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
- 3.STPush:向栈中插入数据,如果栈已满则扩大栈的容量。
void STPush(ST* ps, STDataType x)//插入
{
assert(ps);
//判断空间是否满的
if (ps->top == ps->capacity) {
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) *ps->capacity*2);
if (tmp==NULL) {
printf("relloc fail\n");
return;
}
//把数据放到top的位置
ps->a = tmp;
ps->capacity*=2;
}
ps->a[ps->top] = x;
ps->top++;
}
- STPop:从栈中删除数据,如果栈为空则不进行任何操作。
void STPop(ST* ps)//删除
{
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
- STSize:获取栈中数据元素的数量。
int STSize(ST* ps) {
assert(ps);
return ps->top;
}
- STEmpty:判断栈是否为空。
bool STEmpty(ST* ps)//判断是否为空值
{
assert(ps);
return ps->top == 0;
}
- STTop:获取栈顶的数据元素。
STDataType STTop(ST* ps)//取栈顶的数据
{
assert(ps);
assert(!STEmpty(ps));//加断言解释一下
return ps->a[ps->top - 1];
}
四、代码文件的实现
1.头文件
#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* ps);//初始化
void STDesroy(ST* ps);//销毁
void STPush(ST* ps,STDataType x);//插入
void STPop(ST* ps);//删除
int STSize(ST* ps);//数据的长度
bool STEmpty(ST* ps);//判断是否为空值
STDataType STTop(ST* ps);//取栈顶的数据
2.测试文件
#include"Stack.h"
void TestStack()
{
ST st;
STInit(&st);
STPush(&st,1);
STPush(&st, 2);
printf("%d ", STTop(&st));
STPop(&st);
STPush(&st, 3);
STPush(&st, 4);
printf("%d ", STTop(&st));
STPop(&st);
STPush(&st, 5);
while (!STEmpty(&st))
{
printf("%d ", STTop(&st));
STPop(&st);
}
STDesroy(&st);
}
int main()
{
TestStack();
return 0;
}
3.函数实现文件
#include"Stack.h"
void STInit(ST* ps)//初始化
{
assert(ps);
ps->a =(STDataType*)malloc(sizeof(STDataType)*4);
if (ps->a == NULL) {
printf("malloc fail\n");
return;
}
ps->capacity = 4;
ps->top = 0;//ps->top = 1;
//top=0,意味着top指向栈顶数据的下一个,top=-1指向的是栈顶数据
}
void STDesroy(ST* ps)//销毁
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)//插入
{
assert(ps);
//判断空间是否满的
if (ps->top == ps->capacity) {
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) *ps->capacity*2);
if (tmp==NULL) {
printf("relloc fail\n");
return;
}
//把数据放到top的位置
ps->a = tmp;
ps->capacity*=2;
}
ps->a[ps->top] = x;
ps->top++;
}
void STPop(ST* ps)//删除
{
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
int STSize(ST* ps) {
assert(ps);
return ps->top;
}
bool STEmpty(ST* ps)//判断是否为空值
{
assert(ps);
return ps->top == 0;
}
STDataType STTop(ST* ps)//取栈顶的数据
{
assert(ps);
assert(!STEmpty(ps));//加断言解释一下
return ps->a[ps->top - 1];
}
五、总结
该代码实现了一个动态数组实现的栈,具体实现了以下功能:
初始化栈:STInit函数
销毁栈:STDestroy函数
向栈中插入数据:STPush函数
从栈中删除数据:STPop函数
获取栈中元素的数量:STSize函数
判断栈是否为空:STEmpty函数
获取栈顶元素:STTop函数
在实现该代码时需要注意以下几个事项:
在使用realloc函数重新分配空间时,需要用临时指针保存扩充前的指针,并检查返回值以确保空间分配成功。
在使用assert宏时,需要确保判断的条件不会出现异常或错误。因为assert宏会在判断条件为false时直接终止程序,因此如果条件不合理则可能会导致程序崩溃。
在使用malloc函数分配内存时,需要注意分配的内存大小是否合理,避免内存溢出或浪费。
在使用free函数释放内存时,需要确保要释放的指针指向已经分配的内存,避免野指针的产生。
在使用realloc函数扩充内存时,需要注意扩充的内存大小是否合理,避免内存浪费。
总之,在编写代码时需要充分考虑各种特殊情况,保证程序的鲁棒性和安全性。同时,代码注释清晰明了也是一个好习惯,能够提高代码的可读性和易维护性。
代码文件下载,欢迎访问