首页 > 其他分享 >【两栈共享空间】------一种特殊的顺序栈

【两栈共享空间】------一种特殊的顺序栈

时间:2024-08-26 19:24:27浏览次数:7  
标签:出栈 两栈 栈顶 top2 top1 ------ 共享 data 指针

前言:

  • 虽然顺序栈的存储已经十分方便,但是它有一个非常致命的缺陷:
    必须事先确定数组存储空间的大小,万一不够用就需要动态扩容
  • 但对于两个相同类型的栈,我们可以做到最大限度的利用其事先开辟的存储空间,既让两栈共享空间

1.共享栈的定义

两个栈共享同一个存储空间,这片空间不单独属于任何一个栈,某个栈需要的多一点,它就可能得到更多的存储空间
在这里插入图片描述

2.共享栈的情况分析

注意

  • 这里所说的栈顶指针为int 下标模拟出来的指针功能
  • 这里栈顶指针指向栈顶元素

2.1栈为空的情况:

top1等于-1: 一号栈为空栈
top2等于数组长度: 二号栈为空栈

2.3栈满的情况:

极端情况1一号栈为空栈,二号栈为满栈;此时 top2=0,top1=-1
在这里插入图片描述
极端情况2一号栈为满栈,二号栈为空栈;此时 top2=数组长度,top1=数组长度
在这里插入图片描述
最多出现的情况:
两个栈顶指针见面的时候:
在这里插入图片描述
而不管是极端情况还是最多出现的情况,都可以总结成一种情况:
两个指针之差结果等于1这种情况

3.共享栈的相关核心操作

3.1共享栈的结构定义:

包括了一号栈 与 二号栈的栈顶指针,以及容纳两个栈中元素的数组

//1.共享栈的结构定义
typedef struct StackNode
{
	SElemType data[MAXSIZE];
	int top1;//栈1的栈顶指针(从数组的0开始)
	int top2;//栈2的栈顶指针(从数组的n-1开始)
}DoubleStack;
//DoubleStack:用来定义栈的结构

3.2共享栈的入栈操作

注意:要传入栈的结构体指针,即&s,以及要入栈的元素要入栈的栈号

Push(DoubleStack * s, SElemType e,int stacknumber)
3.2.1算法步骤:

(1判断两个栈是否栈满
(2)若给一号栈入栈,进行一号栈的入栈操作
<1>栈顶指针后移
<2>为当前栈顶空间赋值
两步可以合并为一步:s->data[++s->top1]; 先移动栈顶指针,再赋值
(3)若给二号栈入栈,进行二号栈的入栈操作
<1>栈顶指针前移
<2>为当前栈顶空间赋值
两步可以合并为一步:s->data[–s->top2]; 先移动栈顶指针,再赋值

  • 一号栈的入栈图解:

在这里插入图片描述
2.先后移栈顶指针
在这里插入图片描述
3.再赋值
在这里插入图片描述

  • 二号栈的入栈图解:

在这里插入图片描述

2.先前移栈顶指针
在这里插入图片描述

3.再赋值
在这里插入图片描述

//2.共享栈的入栈操作
//注意:要传入栈的结构体指针,即&s,以及要入栈的元素,要入栈的栈号
bool Push(DoubleStack * s, SElemType e,int stacknumber)
{
	//[1]判断两个栈是否栈满
	if (s->top1 + 1 == s->top2)
	{
		printf("栈满!\n");
		return false;
	}

	//[2]若给一号栈入栈,进行一号栈的入栈操作
	if(stacknumber == 1)
	{
		//<1>栈顶指针后移
		s->top1++;
		//<2>为当前栈顶空间赋值
		s->data[s->top1] = e;

		//两步可以合并为一步:
		//s->data[++s->top1];先移动栈顶指针,再赋值
		return true;
	}
	//[3]若给二号栈入栈,进行二号栈的入栈操作
	else if (stacknumber == 2)
	{
		//<1>栈顶指针前移
		s->top2--;
		//<2>为当前栈顶空间赋值
		s->data[s->top2] = e;

		//两步可以合并为一步:
		//s->data[--s->top2];先移动栈顶指针,再赋值
		return true;
	}
	else
	{
		return false;//错误的栈编号!
	}
}

3.3共享栈的出栈操作:

注意:要传入栈的结构体指针,即&s,以及接收栈顶元素的变量要出栈的栈号

Pop(DoubleStack* s, SElemType* e, int stacknumber)
3.3.1算法步骤:

(1)若给一号栈出栈,进行一号栈的出栈操作
<1>若栈空,则返回false
<2>将当前栈顶元素赋值给e
<3>栈顶指针前移
2,3步可以合并为一步:*e = s->data[s->top1- -]; 先将栈顶元素出栈,再将栈顶指针前移
(2)若给二号栈出栈,进行二号栈的出栈操作
<1>若栈空,则返回false
<2>将当前栈顶元素赋值给e
<3>栈顶指针后移
2,3步可以合并为一步:*e = s->data[s->top1++]; 先将栈顶元素出栈,再将栈顶指针前移
(3) 若栈编号不正确,则返回false

  • 一号栈的出栈图解:

在这里插入图片描述

2.先将当前栈顶元素赋值给e
在这里插入图片描述

3.再前移栈顶指针
在这里插入图片描述

  • 二号栈的出栈图解:

在这里插入图片描述

2.先将当前栈顶元素赋值给e
在这里插入图片描述

3.再后移栈顶指针
在这里插入图片描述

//3.共享栈的出栈操作
bool Pop(DoubleStack* s, SElemType* e, int stacknumber)
{

	//[1]若给一号栈出栈,进行一号栈的出栈操作
	if (stacknumber == 1)
	{
		//<1>若栈空,则返回false
		if (s->top1 == -1)
		{
			printf("栈空!\n");
			return false;
		}

		//<2>将当前栈顶元素赋值给e
		*e = s->data[s->top1];
		//<3>栈顶指针前移
		s->top1--;

		//两步可以合并为一步:
		//*e = s->data[s->top1--];先将栈顶元素出栈,再将栈顶指针前移
	}

	//[2]若给二号栈出栈,进行二号栈的出栈操作
	else if (stacknumber == 2)
	{
		//<1>若栈空,则返回false
		if (s->top2 == MAXSIZE)
		{
			printf("栈空!\n");
			return false;
		}

		//<2>将当前栈顶元素赋值给e
		*e = s->data[s->top2];
		//<3>栈顶指针后移
		s->top2++;

		//两步可以合并为一步:
		//*e = s->data[s->top1++];先将栈顶元素出栈,再将栈顶指针前移
	}
	else
	{
		return false;//错误的栈编号!
	}
	return true;
}

4.核心操作的整体实现

//共享栈
//为了最大限度的节省空间,让两个同类型的栈共享同一快存储空间
#include<stdio.h>
#include<stdlib.h>

#define MAXSIZE 100//两栈的最大容量


typedef int SElemType;//栈中元素的类型

#define bool int
#define true 1
#define false 0


//1.共享栈的结构定义
typedef struct StackNode
{
	SElemType data[MAXSIZE];
	int top1;//栈1的栈顶指针(从数组的0开始)
	int top2;//栈2的栈顶指针(从数组的n-1开始)
}DoubleStack;
//DoubleStack:用来定义栈的结构

//共享栈的初始化操作
void InitStack(DoubleStack* s)
{
	s->top1 = -1; // 初始化一号栈的栈顶指针
	s->top2 = MAXSIZE; // 初始化二号栈的栈顶指针
}


//2.共享栈的入栈操作
//注意:要传入栈的结构体指针,即&s,以及要入栈的元素,要入栈的栈号
bool Push(DoubleStack * s, SElemType e,int stacknumber)
{
	//[1]判断两个栈是否栈满
	if (s->top1 + 1 == s->top2)
	{
		printf("栈满!\n");
		return false;
	}

	//[2]若给一号栈入栈,进行一号栈的入栈操作
	if(stacknumber == 1)
	{
		//<1>栈顶指针后移
		s->top1++;
		//<2>为当前栈顶空间赋值
		s->data[s->top1] = e;

		//两步可以合并为一步:
		//s->data[++s->top1];先移动栈顶指针,再赋值
		return true;
	}
	//[3]若给二号栈入栈,进行二号栈的入栈操作
	else if (stacknumber == 2)
	{
		//<1>栈顶指针前移
		s->top2--;
		//<2>为当前栈顶空间赋值
		s->data[s->top2] = e;

		//两步可以合并为一步:
		//s->data[--s->top2];先移动栈顶指针,再赋值
		return true;
	}
	else
	{
		return false;//错误的栈编号!
	}
}


//3.共享栈的出栈操作
bool Pop(DoubleStack* s, SElemType* e, int stacknumber)
{

	//[1]若给一号栈出栈,进行一号栈的出栈操作
	if (stacknumber == 1)
	{
		//<1>若栈空,则返回false
		if (s->top1 == -1)
		{
			printf("栈空!\n");
			return false;
		}

		//<2>将当前栈顶元素赋值给e
		*e = s->data[s->top1];
		//<2>栈顶指针前移
		s->top1--;

		//两步可以合并为一步:
		//*e = s->data[s->top1--];先将栈顶元素出栈,再将栈顶指针前移
	}

	//[2]若给二号栈出栈,进行二号栈的出栈操作
	else if (stacknumber == 2)
	{
		//<1>若栈空,则返回false
		if (s->top2 == MAXSIZE)
		{
			printf("栈空!\n");
			return false;
		}

		//<2>将当前栈顶元素赋值给e
		*e = s->data[s->top2];
		//<2>栈顶指针后移
		s->top2++;

		//两步可以合并为一步:
		//*e = s->data[s->top1++];先将栈顶元素出栈,再将栈顶指针前移
	}
	else
	{
		return false;//错误的栈编号!
	}
	return true;
}





int main()
{
	DoubleStack s1; // 声明一个共享栈
	InitStack(&s1); // 初始化共享栈

	// 测试用例
	Push(&s1, 10, 1);
	Push(&s1, 20, 2);
	SElemType e;
	Pop(&s1, &e, 1);
	printf("栈1出栈元素:%d\n", e);
	Pop(&s1, &e, 2);
	printf("栈2出栈元素:%d\n", e);

	return 0;
}

在这里插入图片描述

标签:出栈,两栈,栈顶,top2,top1,------,共享,data,指针
From: https://blog.csdn.net/2401_82676816/article/details/141564703

相关文章

  • 机器学习:svm算法原理的优缺点和适应场景
    1、概述:基本原理:间隔(Margin):SVM试图找到一个超平面,这个超平面不仅能够区分不同的类别,而且具有最大的间隔。间隔是数据点到超平面的最近距离。支持向量(SupportVectors):这些是距离超平面最近的数据点,它们决定了超平面的位置和方向。        支持向量机(SVM)是一种在机器......
  • 【含文档】基于Springboot+Vue的流浪猫狗救助救援系统(含源码数据库)
    1.开发环境开发系统:Windows10/11架构模式:MVC/前后端分离JDK版本:JavaJDK1.8开发工具:IDEA数据库版本:mysql5.7或8.0数据库可视化工具:navicat服务器:SpringBoot自带apachetomcat主要技术:Java,Springboot,mybatis,mysql,vue2.视频演示地址3.功能该系统......
  • Ubuntu20.04安装ROS,一次成功,详细简洁
     仔细看文档系统要求:Ubuntu20.04ROS安装版本:Noetic首先,最重要的就是ROS软件源,很多小伙伴都是在网上随便复制的软件源和密钥,非常不建议,复制三方的软件源,因为如果出新的,可能旧的官方维护就少了,ROS就容易崩。我是使用中科大的ROS软件源接下来教大家怎么做进这个网址https:/......
  • 动态dp——P8820 [CSP-S 2022] 数据传输 题解
    P8820[CSP-S2022]数据传输可怜的cnblog被(昨天DDos+今天CC)攻击了(望周知!),只好先发在CSDN题面:题目描述小C正在设计计算机网络中的路由系统。测试用的网络总共有nn......
  • lambda表达式
    1.什么是lambda表达式Lambda允许把函数作为一个方法的参数,使用Lambda表达式可以写出更简洁、更灵活的代码,而其作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。2.lambda表达式语法Lambda表达式在Java语言中引入了一个操作符**“->”**,该操作符被称为Lambda操作符......
  • 数据仓库系列6:数据仓库建模的主要步骤是什么?
    你是否曾经面对海量的数据感到无所适从?你是否想知道那些运转良好的数据仓库背后究竟有什么秘密?今天,让我们一起揭开数据仓库建模的神秘面纱,探索那些能够将杂乱无章的数据转化为有价值洞察的关键步骤!目录引言:数据仓库建模的重要性第一步:需求分析与规划为什么需求分......
  • 数据仓库系列7:什么是概念模型、逻辑模型和物理模型,它们有什么区别?
    你是否曾经困惑于数据仓库中的各种模型?概念模型、逻辑模型、物理模型-它们听起来很相似,但实际上各有千秋。目录引言:为什么模型如此重要?1.概念模型:勾勒数据的蓝图什么是概念模型?概念模型的特点概念模型的例子概念模型的作用如何创建概念模型2.逻辑模型:细化......
  • Python——生成器、递归、内省、高阶和偏函数
    Python的生成器(Generators)是一种特殊的迭代器,它使用类似于函数的语法定义,但是使用yield语句一次返回一个值(可以多次返回),而不是使用return语句。生成器函数允许你声明一个像迭代器那样的对象,但是你可以使用更简洁的语法来创建它们。为什么要使用生成器?内存效率高:生成器按需产......
  • Request processing failed:MyBatisSystemException 黑马web开发课程P152中可能出现的
    该异常的最后一句,通过翻译,大概是:   [dispatcherServlet]:servlet.service()forservlet[dispatcherServlet]在路径[]的上下文中抛出异常[请求处理失败:MyBatisSystemException]    经过对代码的检查,发现controller,sevice,dao层业务逻辑都没有问题dao层的map......
  • sqli-labs靶场通关攻略(31-35关)
    第31关(")闭合)查数据库?id=")unionselect1,2,database()--+查表?id=")unionselect1,2,group_concat(table_name)frominformation_schema.tableswheretable_schema='security'--+查列?id=")unionselect1,2,group_concat(column_nam......