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

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

一、栈


(一)栈的概念


栈是一种只允许在一端进行插入或删除操作的线性表,它是一种特殊的线性表,它与队列具有相同的逻辑结构,都属于线性结构,区别在于对其中元素的处理不同,栈遵循的原则是先进后出(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;
}


相关文章
|
5天前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
116 75
|
5天前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
27 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
5天前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
31 9
|
5天前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
25 7
|
2月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
265 9
|
2月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
42 1
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
80 5
|
2月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
2月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
2月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
59 4