《大话数据结构2》——顺序栈、两栈共享空间(双向栈)、C++代码实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/83542377

目录

栈的顺序存储结构 

两栈共享空间(双向栈)

 



顺序栈


●  堆栈的基本概念:堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除操作。

栈(Stack): 是限定仅在表尾进行插入和删除操作的线性表。所谓的表尾是指栈顶,而不是栈底。栈元素也具有线性关系,即前驱后继关系。

先进后出堆栈中允许进行插入和删除操作的一端称为栈顶,另一端称为栈底。堆栈的插入和删除操作通常称为进栈或入栈,堆栈的删除操作通常称为出栈或退栈,不含任何元素的栈称为空栈。

备注:栈本身就是一个线性表,所以我们之前讨论过线性表的顺序存储和链式存储,对于栈来说,同样适用。

栈的顺序存储结构 

1. 栈的示意图

栈中的数据依次是 30 --> 20 --> 10

2. 出栈

出栈前:栈顶元素是30。此时,栈中的元素依次是 30 --> 20 --> 10 
出栈后:30出栈之后,栈顶元素变成20。此时,栈中的元素依次是 20 --> 10

时间复杂度为O(1).

3. 入栈

入栈前:栈顶元素是20。此时,栈中的元素依次是 20 --> 10 
入栈后:40入栈之后,栈顶元素变成40。此时,栈中的元素依次是 40 --> 20 --> 10

时间复杂度为O(1).

下面贴代码把:

sqStack.h—— 顺序栈的头文件

#include<iostream>
#include<cassert>
#define STACK_INCREMENT 5   //存储空间分配增量
using namespace std;
using ElemType = int;
using Status = void;

class sqStack
{
public:
	enum State
	{
		TT_ERROR = 0,
		TT_OK = 1
	};
public:
	sqStack(ElemType initSize); //  初始化操作,建立一个空栈
	~sqStack();
	Status isFull()const; //确定栈是否已满
	ElemType destroy();  //若栈存在,则销毁它
	Status clear();  //将栈清空
	Status isEmpty()const;  //若栈为空,返回true 否则false
							
	ElemType getTop( ElemType &elemOut);  //若栈存在且非空,用e返回栈的栈顶元素
	ElemType push(ElemType elem); //若栈存在,插入新元素e 成为栈顶元素
	ElemType pop( ElemType &elemOut);  //删除栈的栈顶元素,并用e返回其值

	Status getLength()const;  //返回栈中的元素个数
	Status show();  //显示栈的所有元素
private:
	ElemType *m_top;  //指向栈顶元素的指针
	ElemType *m_base;   //指向栈底元素的指针
	ElemType m_stackSize;  //栈的最大容量
};

sqStack.cpp—— 顺序栈的源文件

sqStack::sqStack(ElemType initSize) //  初始化操作,建立一个空栈
{
	assert(initSize != 0);
	m_base = new ElemType[initSize];  //为栈分配空间
	m_stackSize = initSize;
	m_top = m_base;  //最开始,栈顶就是栈底
	cout << "***********************   顺序栈初始化成功!  ***********************" << endl
	     << "栈的大小是: " << m_stackSize << "\n" << endl;
}
 sqStack::~sqStack()
{
	this->destroy();
}
ElemType sqStack::push(ElemType elem) //若栈存在,插入新元素e 成为栈顶元素
{
	/* 一般来说,不需要去写这个动态的追加空间,因为没有必要, 这里写,只是锻炼一下,如果去追加容量的话, 销毁栈时会出错
	if ((m_top - m_base) >= m_stackSize)  //栈满,追加存储空间
	{
		ElemType *allocateMemory = new ElemType[m_base, m_stackSize + STACK_INCREMENT];
		assert(allocateMemory != nullptr);
		m_top = m_base + m_stackSize;
		m_stackSize += STACK_INCREMENT;   //增加存储容量
	}*/
	if ((m_top - m_base) == m_stackSize)
	{
		return TT_ERROR;
	}
	*(m_top)++ = elem; //先把元素elem 放进m_top指针 指向的位置,然后m_top指针向上移一位
	//++m_top;
	return TT_OK;
}
ElemType sqStack::pop(ElemType &elemOut)  //删除栈的栈顶元素,并用e返回其值
{
	if (m_top == m_base) //当栈底指针和栈顶指针重合,说明栈中没有元素
	{
		return TT_ERROR;
	}
	//--Top;  //栈顶指针先往下移动一格
	elemOut = *--(m_top);  //然后取出栈顶指针指着的元素
	return TT_OK;
}
ElemType sqStack::getTop(ElemType &elemOut)//若栈存在且非空,用e返回栈的栈顶元素
{
	if (m_top == m_base) 
	{
		return TT_ERROR;
	}
	elemOut = *(m_top - 1);
	return TT_OK;
}

Status sqStack::show()  //显示栈的所有元素
{
	if (m_top == m_base)
	{
		cout << "顺序栈中没有元素,无法显示!" << endl;
	}
	else
	{
		auto temp = (m_top - m_base);  //先算出栈中的元素的个数
		m_top = m_base;  //把栈底指针变成栈顶指针,从栈底开始遍历输出
		cout << "显示出栈中的所有元素:";
		for (int i = 0; i < temp; ++i)
		{
			cout << *(m_top)++ << ","; //先输出 m_top 指针指向的元素,然后往上移一下
		}
		cout << endl;
	}
}
ElemType sqStack::destroy()  //若栈存在,则销毁它
{
	delete m_base;    //把分配的内存释放掉
	m_base = m_top = nullptr;
	m_stackSize = 0;  //然后把栈的最大容量设置为0
	return TT_OK;
}
inline Status sqStack::isFull()const //确定栈是否已满
{
	cout << "顺序栈现在" << ((m_top - m_base == m_stackSize) ? "已满!" : "未满!") << endl;
}
inline Status sqStack::isEmpty()const  
{
	cout << "\n顺序栈现在" << ((m_top == m_base) ? "为空!" : "非空!") << endl;
}

inline Status sqStack::clear() //将栈清空
{
	m_top = m_base;
	cout << "\n顺序栈" <<((m_top == m_base) ? "清空成功!" : "清空失败!") << endl;
}

inline Status sqStack::getLength()const  //返回栈中的元素个数
{
	cout << "\n顺序栈中的元素个数为:" << (m_top - m_base) << endl;

}

// Test sqStack
void testStack()
{
	int sizeCapacity(0);
	cout << "输入顺序栈的最大容量:";
	cin >> sizeCapacity;
	sqStack myStack(sizeCapacity);

	while (true)
	{
		{
			cout << "\n*******************************************************************" << endl
				<< "*******************   顺序栈的基本功能展示   *******************" << endl
				<< "*******************************************************************" << endl
				<< "********************   选择1——数据进栈.   **********************" << endl
				<< "********************   选择2——数据出栈.   **********************" << endl
				<< "********************   选择3——判断栈是否为空.   **********************" << endl
				<< "********************   选择4——获取栈的长度.   **********************" << endl
				<< "********************   选择5——判断栈是否满了.   **********************" << endl
				<< "********************   选择6——输出栈的栈顶元素.   **********************" << endl
				<< "********************   选择7——输出栈的所有元素.   **********************" << endl
				<< "********************   选择8——将栈清空.   **********************" << endl
				<< "********************   选择9——销毁栈.   **********************" << endl
				<< "********************   选择10——清屏!   **********************" << endl
				<< "********************   选择0——退出程序!   **********************" << endl
				<< "***********************************************************************" << endl
				<< "***********************************************************************" << endl;
		}
		cout << "\n*******************   请输入你想要使用的栈功能的序号  ***************" << endl;
		cout << "请输入你的选择: " << endl;
		int userChoice = 0;
		cin >> userChoice;
		if (!userChoice)
		{
			cout << "程序已退出,感谢您的使用!" << "\n" << endl;
			break;
		}

		switch (userChoice)
		{
		case 1:
		{
			cout << "请输入要进栈的数据:";
			int pushData = 0;
			cin >> pushData;
			if (myStack.push(pushData))
			{
				cout << "数据 " << pushData << "已经入栈成功!" << endl;
				myStack.show();
			}
			else
			{
				cout << "数据 " << pushData << "入栈失败,可能是顺序栈已满!" << endl;
				myStack.show();
			}
			break;
		}
		case 2:
		{
			int removeData = 0;
			if (myStack.pop(removeData))
			{
				cout << "数据 " << removeData << "成功出栈!" << endl;
				myStack.show();
			}
			else
			{
				cout << "出栈失败,可能是栈中没有元素!" << endl;
				myStack.show();
			}
			break;
		}
		case 3:
		{
			myStack.isEmpty();
			break;
		}
		case 4:
			myStack.getLength();  //得到栈中此时的元素个数
			break;
		case 5:
			myStack.isFull();  //判断是否栈满
			break;
		case 6:
		{
			int getElement = 0;
			if (myStack.getTop(getElement))
			{
				cout << "栈顶元素为:" << getElement << endl;
				myStack.show();
			}
			else
			{
				cout << "获取栈顶元素失败,可能是栈中没有元素!" << endl;
				myStack.getLength();
			}
			break;
		}
		case 7:
			myStack.show();  //显示栈中的元素,从栈底开始输出的
			break;

		case 8:
		{
			myStack.clear();
			break;
		}
		case 9:
		{
		
			char yesOrNo;
			cout << "你确定要销毁一个栈吗?(若销毁请输入输入(Y/y))";
			cin >> yesOrNo;
			if ((yesOrNo == 'Y') || (yesOrNo == 'y'))
			{
				if (myStack.destroy())
				{
					cout << "栈已被销毁." << endl;
				}
				else
					cout << "栈销毁失败." << endl;
			}
			break;
			
		}
		case 10:
			system("cls");
			cout << "屏幕已经清屏,可以重新输入!" << endl;
			break;
		default:
			cout << "输入的序号不正确,请重新输入!" << endl;
		}
	}
}
int main()
{
	testStack();
	system("pause");
	return 0;
}

● 注意: 把以上代码复制黏贴到 Visual Studio 2017 上 或者 Visual Studio 2015 上,如果是其他的编译器,可能会出错, 因为该程序用了一点 C++11 的语法, 如果你的编译器不遵循C++11的语法的法,一般来说会出错。

代码的测试结果我就不贴出了,没有必要,你们可以自己测试,应该是对的。

如果有错误的话,欢迎指教。

大家可以把我的代码看懂了,自己写,才是最好,才能学到东西。

如果转载的话, 请指明出处。谢谢。


两栈共享空间(双向栈)


●    如果我们有两个相同类型的栈,我们为他们各自开辟了数组空间,极有可能第一个栈已经满了,再进栈就溢出了,而另一个栈还有很多存储空间空闲。这时,我们完全可以用一个数组两存储两个栈。

 ●   我们的做法如下图,数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为0处,另一个栈为数组的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就是两端点向中间延伸。

  其实关键思路是:他们是在数组的两端,向中间靠拢。top1和top2是栈1和栈2的栈顶指针,可以想象,只要他们两不见面,两个栈就可以一直使用。

 从这里也就可以分析出来,栈1为空时,就是top1等于-1时;而当top2等于n时,即是栈2为空时,那么什么时候栈满呢?

     想想极端的情况,若栈2是空栈,栈1的top1等于n-1时,就是栈1满了。反之,当栈1为空栈时,top2等于0时,为栈2满。但更多的情况,其实就是刚才说的,两个栈见面之时,也就是两个指针之间相差1时,即top1+1==top2为栈满。

下面开始贴我自己写的代码

SqDoubleStack.h 头文件

#include<iostream>
#include<cassert>
using namespace std;
#ifndef TT_DU_STATCK
#define TT_DU_STATCK
namespace tt
{
	class SqDoubleStack
	{
	public:
		using  ElemType = int;
		using Status = void ;
	public:
		enum State
		{
			TT_ERROR = 0 ,
			TT_OK = 1
		};
	public:
		SqDoubleStack(ElemType maxSize);
		~SqDoubleStack();

		ElemType isFull()const;
		ElemType destroy();
		ElemType clear();
		ElemType isEmpty()const;
		ElemType getTop(ElemType &elemOut);
		ElemType push(ElemType elem);
		ElemType pop(ElemType &elemOut);
		Status getLength()const;
		Status show();
	private:
		ElemType *m_data;     //采用动态存储分配结构
		ElemType  m_maxLength; //栈的最大容量
		ElemType m_top1; //栈1栈顶指针
		ElemType m_top2; //栈2栈顶指针
	};

	inline SqDoubleStack::Status SqDoubleStack::getLength()const
	{
		cout << "\n输出双向栈当前的长度:" << (m_top1 + 1) + (m_maxLength - m_top2) << endl;
	}
	inline SqDoubleStack::ElemType SqDoubleStack::isEmpty()const
	{
		return ((m_top1 == -1) && (m_top2 == m_maxLength));
	}
	inline SqDoubleStack::ElemType SqDoubleStack::isFull()const
	{
		return(m_top1 + 1 == m_top2);
	}

}
#endif //TT_DU_STATCK

TestmySqDoubleStack.cpp 源文件

#include"SqDoubleStack.h"

namespace tt
{
	SqDoubleStack::SqDoubleStack(ElemType maxSize)
	{
		assert(maxSize > 0);
		m_data = new ElemType[maxSize];
		assert(m_data != nullptr);
		m_top1 = -1;  //栈1 为空
		m_top2 = maxSize;  // 栈2为空
		m_maxLength = maxSize;
		cout << "*****************************   双向栈初始化成功!  **********************" << endl;

	}
	SqDoubleStack::~SqDoubleStack()
	{
		this->destroy();
	}
	SqDoubleStack::ElemType SqDoubleStack::push(ElemType elem)
	{
		if (m_top1 + 1 == m_top2)  //栈满
		{
			return TT_ERROR;
		}

		int stackNumber(0);
		cout << "请输入你想要为哪个栈添加元素的序号(1或者2):";
		cin >> stackNumber;
		switch (stackNumber)
		{
		case 1:                    //栈1有元素进栈
			m_data[++m_top1] = elem;   //若是栈1则先top1+1后给数组元素赋值
			break;
		case 2:                  //栈2有元素进栈
			m_data[--m_top2] = elem;         //若是栈2则先top2-1后给数组元素赋值
			break;
		default:
			cout << "输入错误,请输入正确的进栈的序号(选择1或2)!" << "\n" << endl;
		}
		return TT_OK;
	}
	SqDoubleStack::ElemType SqDoubleStack::pop(ElemType &elemOut)
	{
		int stackNumber(0);
		cout << "请输入你想要为哪个栈删除元素的序号(1或者2):";
		cin >> stackNumber;
		switch (stackNumber)
		{
		case 1:
			if (m_top1 == -1)   //栈1空
			{
				cout << "栈1为空,删除元素失败!" << endl;
				return TT_ERROR;
			}
			elemOut = m_data[m_top1--];  //将栈1的栈顶元素出栈
			break;
		case 2:
			if (m_top2 == m_maxLength)  //栈2空
			{
				cout << "栈2为空,删除元素失败!" << endl;
				return TT_ERROR;
			}
			elemOut = m_data[m_top2++]; // 将栈2的栈顶元素出栈
			break;
		default:
			cout << "输入错误,请输入正确的删除的序号(选择1或2)!" << "\n" << endl;
		}
		this->show();
		return TT_OK;
	}
	SqDoubleStack::ElemType SqDoubleStack::getTop(ElemType &elemOut)
	{
		int stackNumber(0);
		cout << "请输入你想要获取哪个栈的元素的序号(1或者2):";
		cin >> stackNumber;
		switch (stackNumber)
		{
		case 1:
			if (m_top1 == -1)   //栈1空
			{
				cout << "栈1为空,获取元素失败!" << endl;
				return TT_ERROR;
			}
			elemOut = m_data[m_top1];
			break;
		case 2:
			if (m_top2 == m_maxLength)  //栈2空
			{
				cout << "栈2为空,获取元素失败!" << endl;
				return TT_ERROR;
			}
			elemOut = m_data[m_top2];
			break;
		default:
			cout << "输入错误,请输入正确的获取元素的序号(选择1或2)!" << "\n" << endl;
		}
		this->show();
		return TT_OK;
	}
	SqDoubleStack::Status SqDoubleStack::show()
	{

		if (m_top1 == -1)   //栈1空
		{
			cout << "栈1为空,无法显示元素!" << endl;
		}
		else
		{
			cout << "输出栈1中所有元素:";
			for (int i = 0; i <= m_top1; ++i)
			{
				cout << m_data[i] << ' ';
			}
			cout << endl;
		}
		if (m_top2 == m_maxLength)  //栈2空
		{
			cout << "栈2为空,无法显示元素!" << endl;
		}
		else
		{
			cout << "输出栈2中所有元素:";
			for (int i = m_maxLength - 1; i >= m_top2; --i)
			{
				cout << m_data[i] << ' ';
			}
			cout << endl;
		}
		this->getLength();
	}
	SqDoubleStack::ElemType SqDoubleStack::clear()
	{
		m_top1 = -1;
		m_top2 = m_maxLength;
		return TT_OK;
	}
	SqDoubleStack::ElemType SqDoubleStack::destroy()
	{
		delete[]m_data;
		m_data = nullptr;
		m_top1 = -1;
		m_top2 = m_maxLength;
		m_maxLength = 0;
		return TT_OK;
	}
}


// 双向栈的测试函数
void testmySqDoubleStack()
{
	int sizeCapacity(0);
	cout << "输入双向栈的最大容量:";
	cin >> sizeCapacity;
	tt::SqDoubleStack mySqDoubleStack(sizeCapacity);

	while (true)
	{

		{
			cout << "\n*******************************************************************" << endl
				<< "*******************   双向栈的基本功能展示   *******************" << endl
				<< "*******************************************************************" << endl
				<< "********************   选择1——数据进栈.   **********************" << endl
				<< "********************   选择2——数据出栈.   **********************" << endl
				<< "********************   选择3——判断栈是否为空.   **********************" << endl
				<< "********************   选择4——获取栈的长度.   **********************" << endl
				<< "********************   选择5——判断栈是否满了.   **********************" << endl
				<< "*************************************************************************" << endl
				<< "********************   选择6——输出栈的栈顶元素.   **********************" << endl
				<< "********************   选择7——输出栈的所有元素.   **********************" << endl
				<< "********************   选择8——将栈清空.   **********************" << endl
				<< "********************   选择9——销毁栈.   **********************" << endl
				<< "*************************************************************************" << endl
				<< "********************   选择10——清屏!   **********************" << endl
				<< "********************   选择0——退出程序!   **********************" << endl
				<< "***********************************************************************" << endl
				<< "***********************************************************************" << endl;
		}
		cout << "\n*******************   请输入你想要使用的双向栈功能的序号  ***************" << endl;
		int useChoice(0);
		cout << "请输入你的选择:";
		cin >> useChoice;
		if (useChoice == 0)
		{
			cout << "程序已退出,感谢您的使用!" << "\n" << endl;
			break;
		}
		switch (useChoice)
		{
		case 1:
		{
			int insertElem(0);
			cout << "请输入你想要添加的元素:";
			cin >> insertElem;
			if (mySqDoubleStack.push(insertElem))
			{
				cout << "数据" << insertElem << "插入成功!" << "\n" << endl;
				mySqDoubleStack.show();
			}
			else
			{
				cout << "数据" << insertElem << "插入失败,或许栈已经满了!" << endl;
				mySqDoubleStack.getLength();
				mySqDoubleStack.isFull();
			}
			break;
		}
		case 2:
		{
			int cancelElem(0);
			if (mySqDoubleStack.pop(cancelElem))
			{
				cout << "数据" << cancelElem << "删除成功!" << "\n" << endl;
			}
			break;
		}
		case 3:
			if (mySqDoubleStack.isEmpty())
			{
				cout << "目前双向栈为空!" << endl;
				mySqDoubleStack.getLength();
			}
			else
			{
				cout << "目前双向栈非空!" << endl;
				mySqDoubleStack.getLength();
			}
			break;
		case 4:
			mySqDoubleStack.getLength();
			break;
		case 5:
			if (mySqDoubleStack.isFull())
			{
				cout << "目前双向栈已满,不能再添加元素了!" << endl;
				mySqDoubleStack.getLength();
			}
			else
			{
				cout << "目前双向栈非满,还可以添加元素!" << endl;
				mySqDoubleStack.getLength();
			}
			break;
		case 6:
		{
			int getElem(0);
			if (mySqDoubleStack.getTop(getElem))
			{
				cout << "获取的栈顶元素为:" << getElem << endl;
			}
			break;
		}
		case 7:
			mySqDoubleStack.show();
			break;
		case 8:
			if (mySqDoubleStack.clear())
			{
				cout << "双向栈已被清空!" << endl;
				mySqDoubleStack.getLength();
			}
			else
			{
				cout << "双向栈清空失败!" << endl;
				mySqDoubleStack.getLength();
			}
			break;
		case 9:
		{
			char yesOrNo('\0');
			cout << "你确定要销毁一个栈吗?(若销毁请输入输入(Y/y))";
			cin >> yesOrNo;
			if ((yesOrNo == 'Y') || (yesOrNo == 'y'))
			{
				if (mySqDoubleStack.destroy())
				{
					cout << "双向栈已被销毁." << endl;
				}
				else
					cout << "双向栈销毁失败." << endl;
			}
			break;
		}
		case 10:
			system("cls");
			cout << "屏幕已经清屏,可以重新输入!" << endl;
			break;
		default:
			cout << "输入的序号不正确,请重新输入!" << endl;
		}
	}
}
int main()
{
	testmySqDoubleStack();
	system("pause");
	return 0;
}

 ● 事实上,使用这样的数据结构,通常都是当两个栈的空间需求有相反关系时,也就是一个栈增长时另一个栈在缩短的情况。

    ●  注意:这只是针对两个具有相同数据类型的栈。

把该代码分别放进编译器中的源文件和头文件就能编译运行成功。  如果要合成到一块的源文件的话, 需要修改一下地方。你们自己修改吧。

如果有错误的话,欢迎指教。

如果转载的话, 请指明出处。谢谢。

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/83542377
今日推荐