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

一、栈的相关知识

(一)栈的定义

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

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

(二)栈的排列

根据栈的基本性质,对于n个不同数据元素执行进栈,出栈元素不同排列的个数为以下个数:
在这里插入图片描述

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

(三)栈的常见应用

栈的常见应用有以下:
(1)进制转换(例如,十进制数转为二进制数等等);
(2)表达式求值(例如,中后缀表达式、括号匹配等等);
(3)迷宫求解;
(3)递归(例如,斐波那契数列等等)以及函数调用;
(4)缓存机制.。
(5)用栈对二叉树进行前、中、后序遍历;
(6)用栈模拟队列。

(四)共享栈的概念

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

二、顺序栈的代码实现

(一)顺序栈的定义

顺序栈存储空间的实现是使用数组来存储栈元素的,通过一组数组地址的连续的存储单元来存放从栈底开始至栈顶的数据元素,同时设置一个栈顶指针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);
	}
}

(九)栈的遍历输出

首先判断顺序栈是否为空,然后通过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<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;
} 

/*主函数*/
int main() {
	SqStack S;
	int x;
	InitStack(S);//初始化
	CreateStack(S,x);//创建顺序栈
	StackGetTop(S,x);//读取栈顶元素
	printf("读取栈顶元素,当前栈顶元素为:%d\n",x);
	printf("从栈顶到栈底的元素(出栈顺序)依次为:");
	PrintStack(S,x); //遍历输出栈中元素
}

运行结果如下:
在这里插入图片描述

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

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

#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;
} 

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

例如,创建一个顺序栈,栈中元素从栈底到栈顶依次为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);
}

运行结果如下:
在这里插入图片描述

  • 36
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
引用\[1\]提供了一个朴素的解法,使用两个来存储字符串,一个用来存储普通字符,另一个用来存储特殊字符。遍历字符串,如果是普通字符则压入第一个,如果是特殊字符则弹出第一个顶元素。最后比较两个是否相同即可判断字符串是否有效。这个解法的时间复杂度是O(M + N),空间复杂度也是O(M + N)。\[1\] 引用\[2\]提供了另一个的应用场景,即判断括号是否有效。遍历字符串,如果是左括号则压入,如果是右括号则判断和顶元素是否匹配,不匹配则返回false,匹配则弹出顶元素。最后判断是否为空即可判断括号是否有效。\[2\] 引用\[3\]也提供了一个判断括号是否有效的解法,使用来操作。遍历字符串,如果是左括号则压入,如果是右括号则判断和顶元素是否匹配,不匹配则返回false,匹配则弹出顶元素。最后判断是否为空即可判断括号是否有效。这个解法使用了HashMap来存储括号的对应关系。\[3\] 综上所述,在解决字符串相关问题中有着广泛的应用,包括判断字符串是否有效、逆波兰表达式等。在解决这些问题时,可以帮助我们保存和处理字符的顺序,从而简化问题的处理过程。 #### 引用[.reference_title] - *1* *3* [Leetcode刷题03-](https://blog.csdn.net/weixin_47802917/article/details/123007699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] - *2* [leetCode-类型详解](https://blog.csdn.net/zhiyikeji/article/details/125508011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晚风(●•σ )

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值