数据结构学习笔记——栈的基本知识和顺序存储结构实现栈(顺序栈)

简介: 数据结构学习笔记——栈的基本知识和顺序存储结构实现栈(顺序栈)

一、栈


(一)栈的概念


栈是一种只允许在一端进行插入或删除操作的线性表,它是一种特殊的线性表,它与队列具有相同的逻辑结构,都属于线性结构,区别在于对其中元素的处理不同,栈遵循的原则是先进后出(FILO),即后进的元素先被取出来,它是被限制存取点的线性结构。由于它是一种线性表,所以有两种方式:顺序存储结构和链式存储结构,即顺序栈和链式栈。

1667225175488.jpg

其中,栈的插入操作称为进栈,栈的删除操作称为出栈。


(二)栈的排列


根据栈的基本性质,对于n个不同数据元素执行进栈,出栈元素不同排列的个数为以下个数:

1667225196922.jpg


例如,三个不同的数据元素进栈,则1/(3+1)C36=1/4×20=5,即可以得到5种不同的出栈序列。


(三)共享栈


使用共享栈可以更加有效地利用存储空间,降低发生上溢的可能,通过让两个顺序栈共享一个一维数组空间,将这两个顺序栈的栈底分别设置在数组空间的两端,其中两个栈的栈顶指针都指向栈顶元素,当top1=-1时顺序栈1为空,当top2=MaxSize时顺序栈2为空,另外当两个栈顶指针相邻,即top2-top1=1时,此时共享栈满。

1667225213536.jpg


(四)栈的常见应用


栈的常见应用有以下:

(1)进制转换(例如十进制数转为二进制数等等);

(2)表达式求值(中后缀表达式、括号匹配等等);

(3)迷宫求解;

(3)递归(例如斐波那契数列等等)以及函数调用。


二、顺序栈的定义


顺序栈存储空间的实现是使用数组来存储栈元素的,通过一组数组地址的连续的存储单元来存放从栈底开始至栈顶的数据元素,同时设置一个栈顶指针top,用于指示当前栈顶元素的位置,代码如下:

#define MaxSize 20//可自行设置
typedef struct {
  int data[MaxSize];//存放栈中元素 ,使用数组
  int top;//栈顶指针 ,记录栈顶元素的位置 
} SqStack;//顺序栈的类型定义


我们可以得到顺序栈的长度,由于数组下标是从0开始的,所以栈的长度为S.top+1,即要加1。顺序栈采用数组存储数据元素,由于数组的大小是固定的,不能动态分配大小,但链栈相比顺序栈的最大优势就是它可以动态地分配存储空间。


三、顺序栈的初始化


初始化一个顺序栈,这里的参数SqStack &S,带有“&”,表示引用调用,即对参数的修改结果进行带回,栈顶指针为S.top,栈顶元素的值为S.data[S.top],初始化时定义S.top=-1表示顺序栈为空,而当S.top=0时,表示栈中只存在一个元素,代码如下:

/*顺序栈的初始化,初始化一个空栈*/
void InitStack(SqStack &S) {
  S.top=-1;//顺序栈为空
}


四、判断顺序栈是否为空栈


可以得到,判断顺序栈是否为空栈的条件是S.top==-1,表示此时顺序栈中为空栈,无任何元素,代码如下:

/*判断顺序栈是否为空*/
bool StackEmpty(SqStack S) {
  if(S.top==-1)//当top=-1时,栈为空,而并不是S.top=0(它表示的是栈中有一个元素).
  return true;
  else
  return false;
}


五、判断顺序栈是否为满栈


判断顺序栈是否为空栈的条件是S.top==MaxSize-1,由于c语言数组下标从0开始的,栈中元素最大个数MaxSize要减1,即当top=MaxSize-1时,表示此时顺序栈中已满,无法再存入元素,代码如下:

/*判断顺序栈是否为满栈*/
bool StackFull(SqStack S) {
  if(S.top==MaxSize-1)//由于c语言数组下标从0开始的,即当top=MaxSize-1时,此时栈满。
  return true;
  else
  return false;
}


六、进栈(插入操作)


将一个元素插入顺序栈中,即进栈,首先应判断栈是否为满,即S.top==MaxSize-1,进栈的操作可以概括为指针先加1,然后再入栈,由于进栈后元素个数有变化,所以要用引用“&”,即SqStack &S,首先判断顺序栈是否已满,然后在新的元素进栈前,所以栈顶指针要先加1,即++S.top,然后将进栈元素的值传入并将其入栈,如下:

++S.top;//top指针始终指向栈顶,新的元素进栈,所以指针先加1
S.data[S.top]=x;//将进栈元素的值传入并入栈


这两行代码也可以使用一行代码:S.data[++S.top]=x直接替换。

进栈操作的完整代码如下:

/*进栈操作*/
bool StackPush(SqStack &S,int x) {
  if(S.top==MaxSize-1)//若栈已满,则报错
  return false;
  ++S.top;//top指针始终指向栈顶,新的元素进栈,所以指针先加1
  S.data[S.top]=x;//将进栈元素的值传入并入栈
  //S.data[++S.top]=x;
  return true;
}


七、出栈(删除操作)


将一个元素从顺序栈中删除,即出栈,首先应判断栈是否为空,即S.top==-1,出栈的操作可以概括为先出栈,然后指针再减1,由于栈的特性,只能先进后出,即从栈顶进行删除操作然后依次,同样出栈后元素个数有变化,所以要用引用“&”,即SqStack &S,首先判断顺序栈是否为空,元素出栈后(将栈顶元素赋给x),然后栈顶指针要减1,如下:

x=S.data[S.top];//出栈
S.top--;//指针减1


这两行代码也可以使用一行代码:x=S.data[S.top--]直接替换。

出栈操作的完整代码如下:

/*出栈操作*/
bool StackPop(SqStack &S,int x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//出栈
  S.top--;//指针减1
  //x=S.data[S.top--];
  return true;
}


八、读取顺序栈顶元素


读取顺序栈顶元素,这里并没有将栈顶元素取出(无出栈操作),首先判断当前顺序栈是否为空,然后通过x来记录栈顶元素,如下:

/*读取栈顶元素*/
bool StackGetTop(SqStack S,int &x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//x记录栈顶元素
  return true;
}


九、顺序栈的建立


顺序栈的建立中输入一个值代表要创建的栈的元素个数,然后通过一个for循环建立顺序栈,其中使用到栈的进栈操作,每次向栈中插入元素,代码如下:

/*栈的建立*/
void CreateStack(SqStack &S,int x){
  int number;
  printf("请输入要建立栈的元素个数:\n");
  scanf("%d",&number);
  for(int i=0; i<number; i++) {
  printf("输入第%d个入栈的元素:\n",i+1);
  scanf("%d",&x);
  StackPush(S,x);
  }
}


一个简单的顺序栈的基本实现例子

例如,创建一个顺序栈,栈中元素从栈底到栈顶依次为1,2,3,4,5,第一步首先输出当前栈顶元素;第二步通过用户输入一个要进栈的元素“6”,并输出进栈后此时的栈顶元素;第三步通过执行一次出栈操作后,然后再输出此时的栈顶元素。

实现代码如下:

#include<stdio.h>
#define MaxSize 20//可自行设置
typedef struct {
  int data[MaxSize];//存放栈中元素 ,使用数组
  int top;//栈顶指针 ,记录栈顶元素的位置
} SqStack;//顺序栈的类型定义
/*顺序栈的初始化,初始化一个空栈*/
void InitStack(SqStack &S) {
  S.top=-1;//顺序栈为空
}
/*判断顺序栈是否为空*/
bool StackEmpty(SqStack S) {
  if(S.top==-1)//当top=-1时,栈为空,而并不是S.top=0(它表示的是栈中有一个元素).
  return true;
  else
  return false;
}
/*判断顺序栈是否为满栈*/
bool StackFull(SqStack S) {
  if(S.top==MaxSize-1)//由于c语言数组下标从0开始的,即当top=MaxSize-1时,此时栈满。
  return true;
  else
  return false;
}
/*进栈操作*/
bool StackPush(SqStack &S,int x) {
  if(S.top==MaxSize-1)//若栈已满,则报错
  return false;
  ++S.top;//top指针始终指向栈顶,新的元素进栈,所以指针先加1
  S.data[S.top]=x;//将进栈元素的值传入并入栈
  //S.data[++S.top]=x;
  return true;
}
/*出栈操作*/
bool StackPop(SqStack &S,int x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//出栈
  S.top--;//指针减1
  //x=S.data[S.top--];
  return true;
}
/*读取栈顶元素*/
bool StackGetTop(SqStack S,int &x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//x记录栈顶元素
  return true;
}
/*栈的建立*/
void CreateStack(SqStack &S,int x) {
  int number;
  printf("请输入要建立栈的元素个数:\n");
  scanf("%d",&number);
  for(int i=0; i<number; i++) {
  printf("输入第%d个入栈的元素:\n",i+1);
  scanf("%d",&x);
  StackPush(S,x);
  }
}
/*主函数*/
int main() {
  SqStack S;
  int x,e;
  InitStack(S);//初始化
  CreateStack(S,x);//创建顺序栈
  StackGetTop(S,x);//读取栈顶元素
  printf("读取栈顶元素,当前栈顶元素为:%d\n",x);
  printf("输入一个要进栈的元素:");
  scanf("%d",&e);
  StackPush(S,e);//进栈
  StackGetTop(S,x);
  printf("读取栈顶元素,当前栈顶元素为:%d\n",x);
  StackPop(S,x);//出栈
  StackGetTop(S,x);
  printf("执行一次出栈操作后,当前栈顶元素为:%d",x);
}


运行结果如下:

1667225414171.jpg


十、栈的遍历输出


首先判断顺序栈是否为空,然后通过while循环,当S.top!=-1时一直执行下去,每次输出栈顶的元素,然后再减1,如下代码:

/*栈的遍历输出*/
bool PrintStack(SqStack S,int x){
  if(S.top==-1)//若栈为空,则报错
  return false;
  while(S.top!=-1){
  x=S.data[S.top--];
  printf("%d ",x);
  }
  return true;
}


例如,下列代码:

#include
#define MaxSize 20//可自行设置
typedef struct {
  int data[MaxSize];//存放栈中元素 ,使用数组
  int top;//栈顶指针 ,记录栈顶元素的位置
} SqStack;//顺序栈的类型定义
/*顺序栈的初始化,初始化一个空栈*/
void InitStack(SqStack &S) {
  S.top=-1;//顺序栈为空
}
/*判断顺序栈是否为空*/
bool StackEmpty(SqStack S) {
  if(S.top==-1)//当top=-1时,栈为空,而并不是S.top=0(它表示的是栈中有一个元素).
  return true;
  else
  return false;
}
/*判断顺序栈是否为满栈*/
bool StackFull(SqStack S) {
  if(S.top==MaxSize-1)//由于c语言数组下标从0开始的,即当top=MaxSize-1时,此时栈满。
  return true;
  else
  return false;
}
/*进栈操作*/
bool StackPush(SqStack &S,int x) {
  if(S.top==MaxSize-1)//若栈已满,则报错
  return false;
  ++S.top;//top指针始终指向栈顶,新的元素进栈,所以指针先加1
  S.data[S.top]=x;//将进栈元素的值传入并入栈
  //S.data[++S.top]=x;
  return true;
}
/*出栈操作*/
bool StackPop(SqStack &S,int x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//出栈
  S.top--;//指针减1
  //x=S.data[S.top--];
  return true;
}
/*读取栈顶元素*/
bool StackGetTop(SqStack S,int &x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//x记录栈顶元素
  return true;
}
/*栈的建立*/
void CreateStack(SqStack &S,int x) {
  int number;
  printf("请输入要建立栈的元素个数:\n");
  scanf("%d",&number);
  for(int i=0; i
  printf("输入第%d个入栈的元素:\n",i+1);
  scanf("%d",&x);
  StackPush(S,x);
  }
}
/*栈的遍历输出*/
bool PrintStack(SqStack S,int x){
  if(S.top==-1)//若栈为空,则报错
  return false;
  while(S.top!=-1){
  x=S.data[S.top--];
  printf("%d ",x);
  }
  return true;
} 
/*主函数*/
int main() {
  SqStack S;
  int x;
  InitStack(S);//初始化
  CreateStack(S,x);//创建顺序栈
  StackGetTop(S,x);//读取栈顶元素
  printf("读取栈顶元素,当前栈顶元素为:%d\n",x);
  printf("从栈顶到栈底的元素(出栈顺序)依次为:");
  PrintStack(S,x); //遍历输出栈中元素
}


运行结果如下:

1667379796628.jpg


顺序存储结构实现栈的完整代码


链式存储结构实现栈的完整代码如下:

#include<stdio.h>
#define MaxSize 20//可自行设置
typedef struct {
  int data[MaxSize];//存放栈中元素 ,使用数组
  int top;//栈顶指针 ,记录栈顶元素的位置
} SqStack;//顺序栈的类型定义
/*顺序栈的初始化,初始化一个空栈*/
void InitStack(SqStack &S) {
  S.top=-1;//顺序栈为空
}
/*判断顺序栈是否为空*/
bool StackEmpty(SqStack S) {
  if(S.top==-1)//当top=-1时,栈为空,而并不是S.top=0(它表示的是栈中有一个元素).
  return true;
  else
  return false;
}
/*判断顺序栈是否为满栈*/
bool StackFull(SqStack S) {
  if(S.top==MaxSize-1)//由于c语言数组下标从0开始的,即当top=MaxSize-1时,此时栈满。
  return true;
  else
  return false;
}
/*进栈操作*/
bool StackPush(SqStack &S,int x) {
  if(S.top==MaxSize-1)//若栈已满,则报错
  return false;
  ++S.top;//top指针始终指向栈顶,新的元素进栈,所以指针先加1
  S.data[S.top]=x;//将进栈元素的值传入并入栈
  //S.data[++S.top]=x;
  return true;
}
/*出栈操作*/
bool StackPop(SqStack &S,int x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//出栈
  S.top--;//指针减1
  //x=S.data[S.top--];
  return true;
}
/*读取栈顶元素*/
bool StackGetTop(SqStack S,int &x) {
  if(S.top==-1)//若栈为空,则报错
  return false;
  x=S.data[S.top];//x记录栈顶元素
  return true;
}
/*栈的建立*/
void CreateStack(SqStack &S,int x) {
  int number;
  printf("请输入要建立栈的元素个数:\n");
  scanf("%d",&number);
  for(int i=0; i<number; i++) {
  printf("输入第%d个入栈的元素:\n",i+1);
  scanf("%d",&x);
  StackPush(S,x);
  }
}
/*栈的遍历输出*/
bool PrintStack(SqStack S,int x){
  if(S.top==-1)//若栈为空,则报错
  return false;
  while(S.top!=-1){
  x=S.data[S.top--];
  printf("%d ",x);
  }
  return true;
} 
/*输出栈的元素个数*/
bool LengthStack(SqStack S,int length){
  if(S.top==-1)//若栈为空,则报错
  return false;
  length=S.top+1;
  printf("%d",&length);
  return true;
}
/*栈的遍历输出*/
bool PrintStack(SqStack S,int x){
  if(S.top==-1)//若栈为空,则报错
  return false;
  while(S.top!=-1){
  x=S.data[S.top--];
  printf("%d ",x);
  }
  return true;
}


相关文章
|
6天前
|
存储 监控 NoSQL
Redis处理大量数据主要依赖于其内存存储结构、高效的数据结构和算法,以及一系列的优化策略
【5月更文挑战第15天】Redis处理大量数据依赖内存存储、高效数据结构和优化策略。选择合适的数据结构、利用批量操作减少网络开销、控制批量大小、使用Redis Cluster进行分布式存储、优化内存使用及监控调优是关键。通过这些方法,Redis能有效处理大量数据并保持高性能。
27 0
|
6天前
|
存储 SQL 关系型数据库
关系型数据库数据结构化存储
【5月更文挑战第8天】关系型数据库数据结构化存储
30 6
|
1天前
|
缓存 算法 C语言
数据结构与算法⑧(第三章_上)栈的概念和实现(力扣:20. 有效的括号)
数据结构与算法⑧(第三章_上)栈的概念和实现(力扣:20. 有效的括号)
4 0
|
5天前
|
存储 机器学习/深度学习 人工智能
数据结构(五)----特殊矩阵的压缩存储
数据结构(五)----特殊矩阵的压缩存储
15 3
|
5天前
|
前端开发 JavaScript 算法
JavaScript 中实现常见数据结构:栈、队列与树
JavaScript 中实现常见数据结构:栈、队列与树
|
6天前
|
存储 NoSQL C语言
数据结构——顺序栈与链式栈的实现-2
数据结构——顺序栈与链式栈的实现
数据结构——顺序栈与链式栈的实现-2
|
6天前
|
存储 C语言
数据结构——顺序栈与链式栈的实现-1
数据结构——顺序栈与链式栈的实现
数据结构——顺序栈与链式栈的实现-1
|
6天前
栈的基本应用
栈的基本应用
14 3
|
6天前
栈与队列理解
栈与队列理解
13 1
|
6天前
|
机器学习/深度学习 算法 测试技术
【单调栈】3113. 边界元素是最大值的子数组数目
【单调栈】3113. 边界元素是最大值的子数组数目