目录
顺序栈
● 堆栈的基本概念:堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除操作。
栈(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;
}
● 事实上,使用这样的数据结构,通常都是当两个栈的空间需求有相反关系时,也就是一个栈增长时另一个栈在缩短的情况。
● 注意:这只是针对两个具有相同数据类型的栈。
把该代码分别放进编译器中的源文件和头文件就能编译运行成功。 如果要合成到一块的源文件的话, 需要修改一下地方。你们自己修改吧。
如果有错误的话,欢迎指教。