栈的使用就是先进后出,那么使用什么结构进行先进后出?以及先进后出用什么作用呢?
栈的先进先出(LIFO)特性在计算机科学和编程中有许多重要的应用,其中包括:
-
函数调用: 编程语言使用栈来管理函数调用和返回。当一个函数被调用时,其局部变量、参数和返回地址被压入栈中,当函数执行完毕时,这些数据被弹出栈。
-
内存管理: 操作系统使用栈来管理进程的内存分配和释放。每个进程通常都有自己的栈空间,用于存储函数调用、局部变量和其他临时数据。
-
表达式求值: 在表达式求值中,栈常用于将中缀表达式转换为后缀表达式,以便更容易进行计算。
-
逆序输出: 栈可以用于逆序输出数据。例如,当需要逆序输出字符串或者逆序遍历一个数据结构时,可以使用栈来实现。
-
浏览器历史记录: Web浏览器使用栈来管理用户的浏览历史记录。每次用户访问一个新页面时,该页面的URL被压入栈中,用户可以通过后退按钮来弹出最近访问的页面。
总的来说,栈的先进先出特性在各种情况下都能够提供简单而有效的数据管理方式,使得程序设计和数据处理更加方便和高效。
一、原理
上图就是栈的一个增和删,易知,栈就是一个后进先出的结构。
我们可以使用数组和链表表示栈。这里我们用较为简单的数组表示;使用链表的话,增就是头插,删就是头删,也好理解。
使用数组的话删除数据只删除数组最后的数据,不需要对其它数据进行挪用就使用数组来讲解。
二、实现
栈的定义:
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}Stack;
STDataType* a 是栈;top是最后一个数据的下一位,栈为空的时候top为0,所以top也等同于size(大小);capacity是数组的容量,对数组进行扩容。(这里看不懂的话可以先去学一下顺序表)
栈的功能包括:(Stack.h--头文件)
//初始化栈
void STInit(Stack* ST);
//销毁栈
void STDestory(Stack* ST);
//入栈
void STPush(Stack* ST, STDataType x);
//出栈
void STPop(Stack* ST);
//返回栈的大小
int STSize(Stack* ST);
//返回栈顶元素
STDataType STTop(Stack* ST);
//销毁栈
int STEmpty(Stack* ST);
入栈,就是在顺序表中依次往后放;删除就是把top--即可;返回栈顶元素就返回a[top-1]。
代码简单,直接上代码,同学们自行理解。
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}Stack;
// 初始化栈
void STInit(Stack* ST);
// 销毁栈
void STDestory(Stack* ST);
// 入栈
void STPush(Stack* ST, STDataType x);
// 出栈
void STPop(Stack* ST);
// 返回栈的大小
int STSize(Stack* ST);
// 返回栈顶元素
STDataType STTop(Stack* ST);
// 检查栈是否为空
int STEmpty(Stack* ST);
void STInit(Stack* ST)
{
assert(ST);
ST->a = NULL;
ST->capacity = ST->top = 0;
}
void STPush(Stack* ST, STDataType x)
{
assert(ST);
if (ST->top >= ST->capacity)
{
int newcapacity = ST->capacity == 0 ? 4 : 2 * ST->capacity;
STDataType* tmp = (STDataType*)realloc(ST->a, sizeof(STDataType) * newcapacity);
if (tmp == NULL)
{
perror("STPush realloc fail");
exit(EXIT_FAILURE); // 重新分配内存失败,退出程序
}
ST->a = tmp;
ST->capacity = newcapacity;
}
ST->a[ST->top++] = x; // 使用后增操作符
}
void STPop(Stack* ST)
{
assert(ST);
if (STEmpty(ST)) return; // 空栈直接返回
ST->top--; // 栈顶指针先减1
ST->a[ST->top] = 0; // 释放栈顶元素,赋值为0
}
int STSize(Stack* ST)
{
assert(ST);
return ST->top; // 返回栈的当前大小
}
STDataType STTop(Stack* ST)
{
assert(ST);
if (STEmpty(ST)) exit(EXIT_FAILURE); // 空栈直接退出程序
return ST->a[ST->top - 1]; // 返回栈顶元素
}
int STEmpty(Stack* ST)
{
assert(ST);
return ST->top == 0; // 检查栈顶是否为0,表示栈是否为空
}
void STDestory(Stack* ST)
{
assert(ST);
if (ST->a != NULL) free(ST->a); // 检查栈是否为空,再释放内存
ST->a = NULL;
ST->capacity = ST->top = 0;
}
int main()
{
Stack S;
STInit(&S);
STPush(&S, 1);
STPush(&S, 2);
STPush(&S, 3);
STPush(&S, 4);
STPush(&S, 5);
while (!STEmpty(&S))
{
printf("%d %d\n", STTop(&S), STSize(&S));
STPop(&S);
}
STDestory(&S); // 释放栈所占用的内存
return 0;
}
通过本文的介绍,读者应该对栈的概念、特性、实现方式以及在C语言中的应用有了更深入的了解。栈作为一种重要的数据结构,在算法和软件开发中具有广泛的应用。掌握栈的原理和基本操作,将有助于读者更好地理解和应用栈这一重要数据结构。