目录
顺序栈
栈的顺序存储结构
两栈共享空间(双向栈)
链栈
时间复杂度对比
堆栈的基本概念:堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除操作。
栈(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).
下面是C++实现的顺序栈:
sqStack.h—— 顺序栈的头文件
#include
#include
#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;
}
下面用C#代码实现的顺序栈:
namespace DateStructure
{
interface IStack
{
void CreateList(params int[] arrElem);
void clear();
bool isEmpty();
int getTop();
void push(int insertElem);
int pop();
int getLength();
void show();
}
class SeqStack : IStack
{
private int m_maxSize;
private int[] m_data;
private int top;
public SeqStack(int maxSize)
{
Debug.Assert(maxSize > 0, "不能分配小于1的数组!");
m_data = new int[maxSize];
Debug.Assert(m_data != null, "初始化时,内存分配失败!");
m_maxSize = maxSize;
top = -1;
}
public void clear()
{
top = -1;
}
public int getLength()
{
return top + 1;
}
public void CreateList(params int[] arrElem)
{
if ((arrElem != null) && (arrElem.Length != 0) && arrElem.Length <= m_maxSize)
{
for (var t = 0; t != arrElem.Length; ++t)
{
m_data[t] = arrElem[t];
top = t; // 当添加元素时,记录 top的位置
}
}
else
{
WriteLine("顺序栈整栈创建失败!");
}
}
public int getTop()
{
if(top != -1)
{
return m_data[top];
}
return -1;
}
public bool isEmpty()
{
return top == -1;
}
public int pop()
{
if(top == -1)
{
WriteLine("该顺序栈没有元素可以删除!");
return -1;
}
return m_data[top--];
}
public void push(int insertElem)
{
if(top+1 == m_maxSize)
{
WriteLine("顺序栈已满,无法添加元素!");
return;
}
m_data[++top] = insertElem;
}
public void show()
{
if(top != -1)
{
Write("输出所有元素,顺序栈中的所有元素出栈:");
for (var t = top; t != -1; --t)
{
Write($"{m_data[t]},");
}
WriteLine();
}
}
}
class Program
{
static void Main(string[] args)
{
WriteLine("输入顺序表的最大容量:");
int sizeCapacity = Convert.ToInt32(Console.ReadLine());
var myStack = new SeqStack(sizeCapacity);
const int arraySize = 5;
int[] myIntArray = new int[arraySize] { 0, 1, 2, 3,5 };
myStack.CreateList(myIntArray);
WriteLine($"获取当前顺序栈的元素个数:{myStack.getLength()}");
myStack.show();
int getTopElem = myStack.getTop();
if( 0 <= getTopElem)
{
WriteLine($"返回的栈顶元素值为:{getTopElem}");
}
else
{
WriteLine("该顺序栈已经没有元素了,无法返回!");
}
WriteLine("请输入你想插入的元素值:");
int pushElem = Convert.ToInt32(Console.ReadLine());
myStack.push(pushElem);
myStack.show();
int removeElem = myStack.pop();
if(removeElem >=0)
{
WriteLine($"被删除的元素为:{removeElem}");
myStack.show();
}
if(myStack.isEmpty())
{
WriteLine("该顺序栈是空的!");
}
else
WriteLine("该顺序栈非空的!");
WriteLine($"获取当前顺序栈的元素个数:{myStack.getLength()}");
myStack.clear();
WriteLine($"获取当前顺序栈的元素个数:{myStack.getLength()}");
}
}
}
如果我们有两个相同类型的栈,我们为他们各自开辟了数组空间,极有可能第一个栈已经满了,再进栈就溢出了,而另一个栈还有很多存储空间空闲。这时,我们完全可以用一个数组两存储两个栈。
我们的做法如下图,数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为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为栈满。
下面使用C++ 代码实现双向栈:
SqDoubleStack.h 头文件
#include
#include
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;
}
事实上,使用这样的数据结构,通常都是当两个栈的空间需求有相反关系时,也就是一个栈增长时另一个栈在缩短的情况。
注意:这只是针对两个具有相同数据类型的栈。
下面使用C#语言实现双向栈:
namespace DateStructure
{
interface IStack
{
void clear();
void isEmpty();
int getTop();
void push(int insertElem);
void pop();
void getLength();
void show();
}
class SqDoubleStack : IStack
{
private int[] m_data;
private int m_arrMaxLength;
private int m_arrTop1; // 栈1的,栈顶指针
private int m_arrTop2; // 栈2的,栈顶指针
public SqDoubleStack(int maxSize)
{
Debug.Assert(maxSize > 0, "不能分配小于1的数组!");
m_data = new int[maxSize];
Debug.Assert(m_data != null, "初始化时,内存分配失败!");
m_arrTop1 = -1; // 栈1,为空
m_arrTop2 = maxSize; // 栈2,为空
m_arrMaxLength = maxSize;
}
public void clear()
{
m_arrTop1 = -1;
m_arrTop2 = m_arrMaxLength;
}
public void getLength()
{
WriteLine("请输入你想获取哪个栈的元素长度(1或者2):");
int stackNumber = Convert.ToInt32(Console.ReadLine());
switch(stackNumber)
{
case 1:
{
WriteLine($"栈1的长度为:{m_arrTop1 + 1}");
break;
}
case 2:
{
WriteLine($"栈2的长度为:{m_arrMaxLength - m_arrTop2}");
break;
}
default:
{
WriteLine("输入错误,请输入正确的序号(选择1或2)!");
break;
}
};
}
public int getTop()
{
WriteLine("请输入你想获取哪个栈的栈顶元素(1或者2):");
int stackNumber = Convert.ToInt32(Console.ReadLine());
int getTopElem = 0;
switch (stackNumber)
{
case 1:
{
if (m_arrTop1 == -1)
{
return -1;
}
getTopElem = m_data[m_arrTop1];
break;
}
case 2:
{
if (m_arrTop2 == m_arrMaxLength)
{
return -1;
}
getTopElem = m_data[m_arrTop2];
break;
}
default:
{
WriteLine("输入错误,请输入正确的序号(选择1或2)!");
break;
}
}
return getTopElem;
}
public void isEmpty()
{
WriteLine("请输入你想获取判断哪个栈是否为空(1或者2):");
int stackNumber = Convert.ToInt32(Console.ReadLine());
switch(stackNumber)
{
case 1:
{
if(m_arrTop1 == -1)
{
WriteLine("栈1是空的");
}
else
WriteLine("栈1非空的");
break;
}
case 2:
{
if (m_arrTop1 == m_arrMaxLength)
{
WriteLine("栈2是空的");
}
else
WriteLine("栈2非空的");
break;
}
default:
{
WriteLine("输入错误,请输入正确的序号(选择1或2)!");
break;
}
}
}
public void pop()
{
WriteLine("请输入你想要在哪个栈删除元素(1或者2):");
int stackNumber = Convert.ToInt32(Console.ReadLine());
switch(stackNumber)
{
case 1:
{
if(m_arrTop1 == -1)
{
return ;
}
_ = m_data[m_arrTop1--];
break;
}
case 2:
{
if (m_arrTop2 == m_arrMaxLength)
{
return;
}
_ = m_data[m_arrTop2++];
break;
}
default:
{
WriteLine("输入错误,请输入正确的序号(选择1或2)!");
break;
}
}
}
public void push(int insertElem)
{
if (m_arrTop1 + 1 == m_arrTop2)
{
WriteLine("栈已满,无法添加元素!");
return;
}
WriteLine("请输入你想要在哪个栈添加元素(1或者2):");
int stackNumber = Convert.ToInt32(Console.ReadLine());
switch (stackNumber)
{
case 1:
{
m_data[++m_arrTop1] = insertElem;
break;
}
case 2:
{
m_data[--m_arrTop2] = insertElem;
break;
}
default:
{
WriteLine("输入错误,请输入正确的序号(选择1或2)!");
break;
}
}
}
public void show()
{
if(m_arrTop1 == -1)
{
WriteLine("栈1中为空,没有元素可以显示!");
return;
}
else
{
Write("栈1中的所有元素出栈:");
for (var t = m_arrTop1; t != -1; --t)
{
Write($"{m_data[t]},");
}
WriteLine();
}
if(m_arrTop2 == m_arrMaxLength)
{
WriteLine("栈2中为空,没有元素可以显示!");
return;
}
else
{
Write("栈2中的所有元素出栈:");
for (int i = m_arrTop2; i!=m_arrMaxLength;++i)
{
Write($"{m_data[i]},");
}
WriteLine();
}
}
}
class Program
{
static void Main(string[] args)
{
WriteLine("用数组,存储两个栈,现在输入数组的最大容量:");
int sizeCapacity = Convert.ToInt32(Console.ReadLine());
SqDoubleStack myStack = new SqDoubleStack(sizeCapacity);
myStack.push(200);
myStack.push(300);
myStack.push(400);
myStack.push(500);
myStack.push(500);
myStack.show();
myStack.pop();
myStack.pop();
myStack.show();
int getTopElem = myStack.getTop();
if(0 <= getTopElem)
{
WriteLine($"获取的栈顶元素值为:{getTopElem}");
}
else
{
WriteLine("获取栈顶元素失败,因为该栈中没有元素");
}
myStack.isEmpty();
myStack.getLength();
myStack.clear();
myStack.getLength();
}
}
}
当单链表限定只能在头部进行插入和删除操作的时候,即为链栈,一般我们会将单链表的头指针和栈的栈顶指针top合二为一,通常对链栈来说,是不需要头节点的,因为我们维护了栈顶指针,那么栈顶指针就是单链表的头指针。
对于链栈来说,基本不存在栈满的情况,除非内存已经没有可以使用的空间,对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是top = = nullptr 的时候。
不过为了便于操作, 本人写的链栈是带有头结点的,头结点始终指向栈顶元素,那么头指针就是指向头结点的指针,那么链栈为空的话 其实就是 m_head->m_next = nullptr; 这样我就好写链栈的整表创建了, 采用的是头插法的方法。
依次向链式堆栈入栈数据元素a0, a1, a2, ..., an-1后,链式堆栈的示意图如下图所示:
与单链表相同,链栈也是由一个个结点组成的,每个结点由两个域组成,一个是存放数据元素的数据元素域data,另一个是存放指向 下一个结点的对象引用(即指针)域m_next。
链栈有两端,插入数据元素和删除数据元素的一端为栈顶,另一端为栈底。链栈都设计成把靠近栈头m_head的一端定义为栈顶。
采用链栈不必预先估计栈的最大容量,只要系统有可用空间,链栈就不会出现溢出。采用链栈时,栈的各种基本操作的实现与单链表的操作类似。对于链栈,在使用完毕时,应该释放其空间。
下面用C++代码写的链栈:
LinkStack.h 头文件
#include
#include
#ifndef TT_LINK_STACK_H
#define TT_LINK_STACK_H
using namespace std;
namespace tt
{
class LinkStack
{
public:
using ElemType = int;
using Status = void;
public:
enum State
{
TT_ERROR = 0,
TT_OK = 1
};
public:
struct Node
{
ElemType m_data;
Node *m_next;
};
LinkStack(); //初始化一个栈
~LinkStack();
ElemType push(ElemType elem); //若栈存在,插入新元素e 成为栈顶元素
ElemType pop(ElemType &elemOut); //若栈存在,删除栈顶元素
ElemType isEmpty()const; //判断栈是否为空
ElemType getTop(ElemType &elemOut); //若栈存在且非空,用e返回栈的栈顶元素
Status getLength()const; //返回栈中的元素个数
Status show(); //显示栈的所有元素
ElemType clear(); //将栈清空
ElemType destroy(); //若栈存在,则销毁它
Status createHead(ElemType *datum, ElemType extent); //链栈整表创建 ,头插法
private:
Node *m_heap; //声明一个头结点,此链栈中没有栈顶指针, 此链栈的代码有个头结点,链接到链栈中的第一个元素,也就是栈顶元素
ElemType m_stackLength; //栈的当前的元素个数
};
inline LinkStack::ElemType LinkStack::isEmpty()const //判断栈是否为空
{
return (m_stackLength == 0);
}
inline LinkStack::Status LinkStack::getLength()const //得到栈中现在的元素个数
{
cout << "栈中的元素个数为:" << m_stackLength <
TestLinkStack.cpp 源文件
#include"LinkStack.h"
namespace tt
{
LinkStack::LinkStack()
{
m_heap = new Node;
assert(m_heap != nullptr);
m_heap->m_next = nullptr;
m_stackLength = 0;
cout << "*******************链栈初始化成功*****************" << endl;
}
LinkStack::~LinkStack()
{
this->destroy();
}
LinkStack::Status LinkStack::createHead(ElemType *datum, ElemType extent) //链栈整表创建 ,头插法,尾插法不适合
{
Node *s = new Node;
if (!m_heap->m_next) //只有头结点,后面没有元素,创建第一个结点
{
s->m_data = datum[0];
s->m_next = nullptr;
m_heap->m_next = s; //头结点指向第一个元素,即栈顶元素
++m_stackLength;
}
for (int i = 1; i < extent; ++i)
{
Node *m = new Node;
m->m_data = datum[i];
m->m_next = s; //新节点成为栈顶元素,后继元素为s
m_heap->m_next = m; // 头结点链接新节点, 新节点成为栈顶元素
s = m; // s指针指向新节点,即指向栈顶元素
++m_stackLength;
}
}
LinkStack::ElemType LinkStack::push(ElemType elem) //若栈存在,插入新元素e 成为栈顶元素
{
Node *p = new Node; //给一个新结点分配内存
assert(p != nullptr);
p->m_data = elem;
p->m_next = m_heap->m_next; //把栈顶元素变成p的后继结点
m_heap->m_next = p; //在把p变成头结点的后继结点,那么p就是栈顶元素
++m_stackLength; //链栈的当前个数+1
return TT_OK;
}
LinkStack::ElemType LinkStack::pop(ElemType &elemOut) //栈顶数据出栈
{
if (!m_stackLength )
{
return TT_ERROR;
}
Node *p = m_heap->m_next; //首先把栈顶元素给p
elemOut = p->m_data; //输出栈顶元素的数据
m_heap->m_next = p->m_next; //在把p的后继节点变成头结点的后继节点,
delete p; //释放栈顶元素
--m_stackLength;
return TT_OK;
}
LinkStack::ElemType LinkStack::getTop(ElemType &elemOut) //输出栈顶元素
{
if (!m_stackLength )
{
return TT_ERROR;
}
//Node *p = m_heap->m_next;
elemOut = m_heap->m_next->m_data; //把栈顶元素的数据返回
return TT_OK;
}
LinkStack::Status LinkStack::show()
{
if (!m_stackLength)
{
cout << "此栈中没有数据,或者栈未建立!" << "\n" << endl;
}
else
{
Node *p = m_heap->m_next;
cout << "输出栈中所有元素有:";
while (p)
{
cout << p->m_data << ",";
p = p->m_next;
}
cout << endl;
}
}
LinkStack::ElemType LinkStack::clear() //清空一个栈
{
Node *m = m_heap->m_next;
while (m)
{
Node *n = m->m_next; //把第二个元素变成n
delete m; //释放栈顶元素
m = n; //把n变成栈顶元素
}
m_heap->m_next = nullptr; //头结点的指针域指向空
m_stackLength = 0; //当前个数清空
return TT_OK;
}
LinkStack::ElemType LinkStack::destroy() //销毁一个栈
{
this->clear();
delete m_heap;
m_heap = nullptr; //指针清0,防止野指针
return TT_OK;
}
}
void testLinkStack() //测试链栈
{
tt::LinkStack myStack; //初始化一个栈
int myLength(0); //单链表的整表创建,尾插法
cout << "想创建多少数据的链表?";
cin >> myLength;
int *myDatas = new int[myLength];
cout << "请依次输入这" << myLength << "个数据,中间以回车符隔开:" << endl;
for (int i = 0; i < myLength; ++i)
{
cin >> myDatas[i]; //输入要存储的数据的值
}
myStack.createHead(myDatas, myLength); //调用createTail函数 建立链栈
myStack.show();
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
<< "***** 选择0——退出程序! *****" << endl
<< "*****************************************************" << endl
<< "*****************************************************" << endl;
}
cout << "\n*************请输入你想要使用的链栈功能的序号***************" << endl;
cout << "请输入选择:";
int userChoice(0);
cin >> userChoice;
if (!userChoice)
{
cout << "程序已退出,感谢您的使用!" << "\n" << endl;
break;
}
switch (userChoice)
{
case 1:
{
cout << "请输入要进栈的数据:";
int pushDatas(0);
cin >> pushDatas;
if (myStack.push(pushDatas))
{
cout << "数据" << pushDatas << "进栈成功." << "\n" << endl;
myStack.getLength();
myStack.show();
}
else
cout << "内存分配失败,数据" << pushDatas << "进栈失败." << "\n" << endl;
break;
}
case 2:
{
int removeData(0);
if (myStack.pop(removeData))
{
cout << "数据" << removeData << "从栈中成功出栈." << "\n" << endl;
myStack.getLength();
myStack.show();
}
else
{
cout << "目前栈为空,数据" << removeData << "出栈失败!" << "\n" << endl;
myStack.getLength();
}
break;
}
case 3:
myStack.getLength();
myStack.show(); //显示栈中的所有数据元素
break;
case 4:
{
int getTopElem(0);
if (myStack.getTop(getTopElem))
{
cout << "栈顶元素为:" << getTopElem << "\n" << endl;
myStack.getLength();
myStack.show();
}
else
{
cout << "目前栈为空,栈顶元素出栈失败" << "\n" << endl;
myStack.getLength();
}
break;
}
case 5:
if (myStack.isEmpty())
{
cout << "目前是空栈或者是栈初始化失败!" << "\n" << endl;
myStack.getLength();
}
else
{
cout << "目前栈非空!" << "\n" << endl;
myStack.getLength();
myStack.show();
}
break;
case 6:
myStack.getLength(); //输出栈中的元素个数
myStack.show();
break;
case 7:
if (myStack.clear())
{
cout << "栈已被清空!" << "\n" << endl;
myStack.getLength();
}
else
{
cout << "栈清空失败" << "\n" << endl;
myStack.getLength();
myStack.show();
}
break;
case 8:
{
cout << "你确定要销毁一个栈吗?(若销毁请输入输入(Y/y))";
char yesOrNo;
cin >> yesOrNo;
if ((yesOrNo == 'Y') || (yesOrNo == 'y'))
{
if (myStack.destroy())
{
cout << "栈已被销毁." << "\n" << endl;
}
else
cout << "栈销毁失败." << "\n" << endl;
}
break;
}
case 9:
system("cls");
cout << "屏幕已经清屏,可以重新输入!" << "\n" << endl;
break;
default:
cout << "输入的序号不正确,请重新输入!" << "\n" << endl;
}
}
}
int main()
{
testLinkStack();
cout << endl;
system("pause");
return 0;
}
下面用 C# 代码写的链栈:
namespace DateStructure
{
interface IStack
{
void CreateStack(params int[] arrElem);
void clear();
bool isEmpty();
int getTop();
void push(int insertElem);
int pop();
int getLength();
void show();
}
class Node
{
public int m_Data { get; set; } = 0;
public Node m_Next { get; set; } = null;
}
class LinkStack : IStack
{
private Node m_top;
private int m_currentElemLength;
public void CreateStack(params int[] arrElem)
{
if ((arrElem != null) && (arrElem.Length != 0))
{
for (int i = 0; i != arrElem.Length; ++i)
{
Node newNode = new Node();
Debug.Assert(newNode != null, "错误,整表创建栈时,创建新结点,错误!");
if (newNode == null)
{
newNode.m_Data = arrElem[i];
m_top = newNode;
}
else
{
newNode.m_Data = arrElem[0 + i];
newNode.m_Next = m_top;
m_top = newNode;
}
++m_currentElemLength;
}
}
}
public void clear()
{
m_currentElemLength = 0;
m_top = null;
}
public int getLength()
{
return m_currentElemLength;
}
public int getTop()
{
if (m_currentElemLength == 0)
{
return -1;
}
return m_top.m_Data;
}
public bool isEmpty()
{
return m_top == null;
}
public int pop()
{
if(m_currentElemLength == 0)
{
return -1;
}
int tempElem = m_top.m_Data;
m_top = m_top.m_Next;
--m_currentElemLength;
return tempElem;
}
public void push(int insertElem)
{
Node newNode = new Node();
Debug.Assert(newNode != null, "添加元素时,创建新结点失败!");
newNode.m_Data = insertElem;
newNode.m_Next = m_top;
m_top = newNode;
++m_currentElemLength;
}
public void show()
{
if (m_currentElemLength == 0)
{
return;
}
WriteLine("链栈中所有的元素出栈:");
Node tempPoint = m_top;
for (int i = 0; i != m_currentElemLength; ++i)
{
Write($"{tempPoint.m_Data},");
tempPoint = tempPoint.m_Next;
}
WriteLine();
}
}
class Program
{
static void Main(string[] args)
{
LinkStack myStack = new LinkStack();
const int arraySize = 5;
int[] myIntArray = new int[arraySize] { 0, 22, 33, 44, 55 };
myStack.CreateStack(myIntArray);
myStack.show();
WriteLine("请输入你想插入的元素值:");
int pushElem = Convert.ToInt32(Console.ReadLine());
myStack.push(pushElem);
myStack.show();
int removeElem = myStack.pop();
if (removeElem >= 0)
{
WriteLine($"被删除的元素为:{removeElem}");
myStack.show();
}
else
{
WriteLine("链栈为空,无法删除!");
}
int getTopElem = myStack.getTop();
if (0 <= getTopElem)
{
WriteLine($"返回的栈顶元素值为:{getTopElem}");
}
else
{
WriteLine("已经没有元素了,无法返回!");
}
if (myStack.isEmpty())
{
WriteLine("链栈是空的!");
}
else
WriteLine("链栈非空的!");
WriteLine($"获取当前链栈的元素个数:{myStack.getLength()}");
myStack.clear();
WriteLine($"获取当前链栈的元素个数:{myStack.getLength()}");
}
}
}
顺序栈复杂度
操作 | 时间复杂度 |
---|---|
空间复杂度(用于N次push) | O(n) |
push() | O(1) |
pop() | O(1) |
isEmpty() | O(1) |
链栈复杂度
操作 | 时间复杂度 |
---|---|
空间复杂度(用于N次push) | O(n) |
push() | O(1) |
pop() | O(1) |
isEmpty() | O(1) |
可知栈的主要操作都可以在常数时间内完成,这主要是因为栈只对一端进行操作,而且操作的只是栈顶元素。
注意:如果栈的使用过程中元素变幻不可预料,有时很小,有时非常大,那么最好使用链栈,反之如果变化在可控范围内,建议使用顺序栈会更好一些。