栈操作原则
使用栈操作数据,必须遵循“先入后出”的原则;
栈操作之顺序栈
使用顺序表实现栈的存储结构,本质上是数组,数组的一端做栈底,另一端做栈顶;
一个数组其下标最低的位置可当做栈底(注意,此处“下标最低”并不一定是0,可以是任何位置,只要是一段数组的最低下标即可);
入栈
写入数据时:最先进入的数据,放入栈底,后进入的放在数组下标加1的位置,以此类推;这种操作即为入栈(压栈);
出栈
读出数据时:最后进入的数据,位于栈顶,最先被取出,依次类推,直到取出所需值为止;这种操作即为出栈(弹栈);
现实中的“入栈”“出栈”
可以想象一下手枪弹夹的结构:装子弹的动作就是压栈,射出子弹的动作就是弹栈;最先压入弹夹的那颗子弹一定是最后一颗子弹,即先进后出;
代码实现
模拟压栈过程,初始数组或栈为空,变量top为数组或栈顶位置下标,初始化为top=-1;例如有一个数据压栈后,即数组下标最低的位置有数据(此处为a[0]),此时top+1,即top=0;如下图
模拟出栈过程,变量top为数组或栈顶位置下标;出栈必须从栈顶开始,一个一个取出,直到取出所需值为止。例如从当前栈顶取出一个数据后,即当前数组下标最高的位置数据已被取出(实际上该位置的数据依然存在,下次写入会覆盖掉),top应该指向下一个有数据待取出的位置,此时top-1;如下图:
在这段代码中,主要实现:
1.定义一个数组;
2.入栈操作,压入8个数据;
3.出栈操作,弹出6个数据,栈中剩余最先入栈的2个数据;
4.打印各个过程的情况;
5.在CMD中运行查看结果;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int tab[8];
int top = -1;
/**
* @brief 入栈操作
* @param buf 存储栈元素的数组
* @param top 数组下标
* @param elem 栈元素
* @retval int
*/
int push(int *buf, int top, int elem)
{
top += 1;
buf[top] = elem;
printf("push elem %d into tab[%d]\r\n", buf[top], top);
return top;
}
/**
* @brief 出栈操作
* @param buf 存储栈元素的数组
* @param top 数组下标
* @retval int
*/
int pop(int *buf, int top)
{
// 栈内为空
if (top == -1)
{
printf("stack is empty!\r\n");
return -1;
}
printf("pop elem %d from tab[%d]\r\n", buf[top], top);
// 此处把已出栈的元素清0,实际操作中无需清零,直接覆盖即可
buf[top] = 0;
top -= 1;
return top;
}
/**
* @brief 主函数
* @param none
* @retval int
*/
int main(void)
{
int i = 0;
int k = 0;
int j = 0;
int m = 0;
// 压栈操作
printf("push stack:\r\n");
for (k = 0; k < 8; k++)
{
top = push(tab, top, k);
}
// 打印压栈操作后的栈内元素
printf("stack is: \r\n");
for (i = 7; i > -1; i--)
{
printf("tab[%d] = %d\r\n", i, tab[i]);
}
// 打印压栈操作后栈顶top值
printf("current top is = %d\r\n\n", top);
// 弹栈操作
printf("pop stack:\r\n");
for (j = 0; j < 6; j++)
{
top = pop(tab, top);
}
// 打印弹栈操作后的栈内元素
printf("final stack is: \r\n");
for (m = 7; m > -1; m--)
{
printf("tab[%d] = %d\r\n", m, tab[m]);
}
// 打印弹栈操作后的栈顶top值
printf("final top is = %d\r\n", top);
return 0;
}
CMD运行结果