数据结构(三)——详解栈和队列及完整代码实现

文章目录

  • 一.栈
    • 1.1 栈的逻辑结构
    • 1.2 栈的顺序存储结构及实现
      • 1.2.1 顺序栈的实现——入栈
      • 1.2.2顺序栈的实现——出栈
      • 1.2.3 两栈共享空间
    • 1.3 栈的链接存储结构及实现
      • 1.3.1 链栈的实现——入栈
      • 1.3.2 链栈的实现——出栈
    • 1.4 顺序栈和链栈的比较
  • 二.队列
    • 2.1 队列的逻辑结构
    • 2.2 队列的顺序存储结构及实现
      • 2.2.1 循环队列
      • 2.2.2 循环队列的实现——入队
      • 2.2.3 循环队列的实现——出队
      • 2.2.4 循环队列的实现——读队头元素
    • 2.3 队列的链接存储结构及实现
      • 2.3.1 链队列的实现——构造函数
      • 2.3.2 链队列的实现——入队
      • 2.3.3 链队列的实现——出队
    • 2.4 循环队列和链队列的比较
  • 三 .栈和队列完整代码实现
    • 3.1 顺序栈类模板实现:
    • 3.2 链队列的代码实现:
    • 3.3 循环队列实现代码
    • 3.4 顺序栈,两栈共享,链栈的应用

两种特殊的线性表——栈和队列:

 从数据结构角度看,栈和队列是操作受限的线性表,他们的逻辑结构相同。
 从抽象数据类型角度看,栈和队列是两种重要的抽象数据类型。

一.栈

1.1 栈的逻辑结构

栈的相关定义:
1.栈:限定仅在表的一端进行插入和删除操作的线性表
2.允许插入和删除的一端称为栈顶,另一端称为栈底。
3. 空栈:不含任何数据元素的栈。
数据结构(三)——详解栈和队列及完整代码实现_第1张图片
如上图所示,栈的插入和删除是有一定条件的,即栈顶的元素先出栈,下面的元素才能接着出,如果栈顶的元素 a 3 a3 a3没有出栈,那么下面的元素 a 2 、 a 1 a2、a1 a2a1是不可能出栈的,就比如往弹夹里面压子弹一样,最上面的一发子弹没有射出去,下面的子弹自然不可能出去了——这就是栈的操作特性:后进先出

1.2 栈的顺序存储结构及实现

顺序栈是指栈的顺序存储结构,那么如何改造数组来实现栈的顺序存储呢?
数据结构(三)——详解栈和队列及完整代码实现_第2张图片
如上图所示,我们先确定用数组的哪一端表示栈底,假设我们用a[0]端作为栈底,附设指针top指示栈顶元素在数组中的位置
数据结构(三)——详解栈和队列及完整代码实现_第3张图片
如果a2进栈的,就让top++,指向a2对应的位置
数据结构(三)——详解栈和队列及完整代码实现_第4张图片
a3进栈,就让top++,指向a3对应的位置,同理,如果a3出栈了,就让top–,这样就用数组来实现栈的顺序存储,当栈空的适合,就让top=-1,而栈满的适合,则让top=数组的最大值-1.

1.2.1 顺序栈的实现——入栈

实现代码如下:

template <class DataType>
void  seqStack<DataType> ::Push ( DataType  x)
{
     if (top == MAX_SIZE-1)  throw  “溢出”;
     top++;
     data[top] = x;
 } 

如果栈没有满的话,就让top++,然年把x压栈到数组中即可,而这两步可以合并为一步:
在这里插入图片描述

1.2.2顺序栈的实现——出栈

template  <class  DataType>
DataType  seqStack<DataType> :: Pop ( )
{
     if (top == -1)  throw  “溢出”;
     x = data[top--];
     return  x;
}

原理很简单,再此处不多说啦

1.2.3 两栈共享空间

如果在一个程序中需要同时使用具有相同数据类型的两个栈,如何顺序存储这两个栈呢?
我们可以采用顺序栈单向延伸——使用一个数组来存储两个栈,即两栈共享空间:
使用一个数组来存储两个栈,让一个栈的栈底为该数组的始端,另一个栈的栈底为该数组的末端,两个栈从各自的端点向中间延伸。
数据结构(三)——详解栈和队列及完整代码实现_第5张图片
如上图所示,栈1的底固定在下标为0的一端;栈2的底固定在下标为StackSize-1的一端。
top1和top2分别为栈1和栈2的栈顶指针;Stack_Size为整个数组空间的大小
(图中用S表示);

当top1== -1时,栈1为空
当top2= =Stack_Size时,栈2为空
而当top2= =top1+1时,栈满

1.3 栈的链接存储结构及实现

同理,我们应该如何改造链表实现栈的链接存储呢?
数据结构(三)——详解栈和队列及完整代码实现_第6张图片
如上图所示,我们将链头作为栈顶,方便操作;且链栈不需要附设头结点。

1.3.1 链栈的实现——入栈

数据结构(三)——详解栈和队列及完整代码实现_第7张图片
如上图所示,让入栈时,我们定义一个新的结点s,然后将x赋值给s的数据部分,然后让s的下一个结点指向top,再修改top指向新入栈的结点s即可。
实现代码如下:

template <class DataType>
void LinkStack<DataType> ::Push(DataType x)
{
    s = new Node<DataType>;
    s->data = x; 
    s->next = top; 
   top = s; 
}

1.3.2 链栈的实现——出栈

数据结构(三)——详解栈和队列及完整代码实现_第8张图片
同理,出栈时,我们先存入x的值便于返回,然后让栈顶指针p指向结点top,修改top,让他指向他的下一个结点,删除结点p即可。
实现代码如下:

template <class DataType>
DataType LinkStack<DataType> ::Pop( )
{
    if (top == NULL)
     throw "下溢";
    x = top->data; 
    p = top; 
    top = top->next;   
    delete p;
    return x;
}

1.4 顺序栈和链栈的比较

时间性能:相同,都是常数时间O(1)。
空间性能

顺序栈:有元素个数的限制和空间浪费的问题。
链栈:没有栈满的问题,只有当内存没有可用空间时才会出现栈满,但是每个元素都需要一个指针域,从而产生了结构性开销。

总之,当栈的使用过程中元素个数变化较大时,用链栈是适宜的,反之,应该采用顺序栈。

二.队列

2.1 队列的逻辑结构

队列的相关定义:
1.队列:只允许在一端进行插入操作,而另一端进行删除操作的线性表。
2. 允许插入(也称入队、进队)的一端称为队尾,允许删除(也称出队)的一端称为队头。
3. 空队列:不含任何数据元素的队列。
数据结构(三)——详解栈和队列及完整代码实现_第9张图片
如上图所示,队列的特性是先出先进,也就和我们排队是一个道理。

2.2 队列的顺序存储结构及实现

如何才能改造数组实现队列的顺序存储呢?
数据结构(三)——详解栈和队列及完整代码实现_第10张图片
如上图所示,我们设置队头、队尾两个指针,分别约定:让队头指针front指向队头元素的前一个位置,让队尾指针rear指向队尾元素。
数据结构(三)——详解栈和队列及完整代码实现_第11张图片
当a1、a2依次出队后,对头和队尾指针也跟着相应变化。

2.2.1 循环队列

假溢出当元素被插入到数组中下标最大的位置上之后,队列的空间就用尽了,尽管此时数组的低端还有空闲空间,这种现象叫做假溢出。
数据结构(三)——详解栈和队列及完整代码实现_第12张图片
如上图所示,虽然0和1位置还空着,但由于rear指针已经到数组中下标最大的位置,便无法再插入了。
如何解决假溢出呢?
我们设置一个循环队列,将存储队列的数组头尾相接:
数据结构(三)——详解栈和队列及完整代码实现_第13张图片
这样就能让rear指向前面的元素位置了。
但循环队列并不存在物理的循环结构,用软件方法求模实现,比如上图:
我们求模:(4+1)mod 5=0即可让rear指向0位置了
当需要执行出队操作,出队完成后,front==rear时,就表示队空了:
数据结构(三)——详解栈和队列及完整代码实现_第14张图片
数据结构(三)——详解栈和队列及完整代码实现_第15张图片

而当front==rear时,也能表示队满:
数据结构(三)——详解栈和队列及完整代码实现_第16张图片如何才能确定不同的队空、队满的判定条件?有三种方法:

方法一:附设一个存储队列中元素个数的变量num,
       当num==0时队空,当num==QueueSize时为队满;
方法二:修改队满条件,浪费一个元素空间,队满时数组中只有一个空闲单元;
方法三:设置标志flag,当front==rear且flag==0时为队空,
       当front==rear且flag==1时为队满。

数据结构(三)——详解栈和队列及完整代码实现_第17张图片
在此当(rear+1) mod QueueSize==front时为队满,当rear=front时队空

2.2.2 循环队列的实现——入队

数据结构(三)——详解栈和队列及完整代码实现_第18张图片
入队的适合,当(rear+1) % QueueSize与front相同时,就说明队满了,否则修改rear的指向,然后x赋值到rear对应的数组元素处即可。
实现代码如下:

template <class DataType>
void CirQueue<DataType> ::EnQueue(DataType x)
{
   if ((rear+1) % QueueSize == front) throw "上溢";
   rear =(rear+1) % QueueSize;    
   data[rear] = x;                 
 }

2.2.3 循环队列的实现——出队

数据结构(三)——详解栈和队列及完整代码实现_第19张图片
当a3进行出队操作时,当rear == front,表示队列为空,否则修改front的指向,返回data值即可,因为front指向的是队头元素的前一个位置。
代码实现如下:

template <class DataType>
DataType CirQueue<DataType> ::DeQueue( )
{
     if (rear == front) throw "下溢"; 
     front = (front + 1) % QueueSize; 
     return data[front];
} 

2.2.4 循环队列的实现——读队头元素

数据结构(三)——详解栈和队列及完整代码实现_第20张图片
实现代码如下:

template <class DataType>
DataType CirQueue<DataType> ::GetQueue( )
{
    if (rear == front) throw "下溢"; 
    i = (front + 1) % QueueSize;  
    return data[i];
}

2.3 队列的链接存储结构及实现

数据结构(三)——详解栈和队列及完整代码实现_第21张图片
如上图所示,队头指针即为链表的头指针

2.3.1 链队列的实现——构造函数

数据结构(三)——详解栈和队列及完整代码实现_第22张图片
构造一个空链表,让队头和队尾指针都指向该结点即可
代码实现如下:

template <class DataType>
LinkQueue<DataType> ::LinkQueue( )
{
     front = new Node<DataType>; 
     front->next = NULL;  
     rear = front;
}

2.3.2 链队列的实现——入队

数据结构(三)——详解栈和队列及完整代码实现_第23张图片
如上图所示,如果要插入结点s,那么让s的下一个结点为空,让rear的下一个结点指向s,再修改rear指向s即可

template <class DataType>
void LinkQueue<DataType> ::EnQueue(DataType x)
{ 
    s = new Node<DataType>; 
    s->data = x; 
    s->next = NULL;
    rear->next = s; 
    rear = s;
}

2.3.3 链队列的实现——出队

数据结构(三)——详解栈和队列及完整代码实现_第24张图片
如上图所示,我们先让p结点为front的下一个结点,然后让front的下一个结点指向p的下一个结点,删除p结点即可
此处需要注意当队列中只有一个元素时,我们要让rear指向front,然后再删除p结点。
数据结构(三)——详解栈和队列及完整代码实现_第25张图片
代码实现如下:

template <class DataType>
DataType LinkQueue<DataType> ::DeQueue( )
{ 
     if (rear == front) throw "下溢";
     p = front->next; 
     x = p->data; 
     front->next = p->next;        
     if (p->next == NULL)  rear = front;   
     delete p;
     return x;
}

2.4 循环队列和链队列的比较

时间性能:
 循环队列和链队列的基本操作都需要常数时间O (1)。
空间性能:

	循环队列:必须预先确定一个固定的长度,
            所以有存储元素个数的限制和空间浪费的问题。
	链队列:没有队列满的问题,只有当内存没有可用空间时才会出现队列满,
           但是每个元素都需要一个指针域,从而产生了结构性开销。

三 .栈和队列完整代码实现

3.1 顺序栈类模板实现:

#include//cout,cin
#include"process.h"//exit()
#include"stdio.h"//EOF,NULL
//顺序栈类定义
template <class T>
class SqStack
{
	private:
		T  *base;//栈底指针
		int top;//栈顶
		int stacksize;//栈容量
	public:
		SqStack(int m);//构建函数
		~SqStack(){delete [] base;top=-1;stacksize=0;}//析构函数
		void Push(T x);//入栈
		T Pop();//出栈
		T GetTop();//获取栈顶元素
		int StackEmpty();//测栈空
		void ClearStack();//清空栈
		void StackTop();//返回栈顶指针
		void StackTranverse();//显示栈中元素
};
//顺序栈类实现
template <class T>
SqStack<T>::SqStack(int m)
{

	base=new T[m];
	if(base==NULL)
	{
		cout<<"栈创建失败,退出!"<<endl;
		exit(1);
	}
	stacksize=m;
	top=-1;
}

template <class T>
void SqStack<T>::Push(T x)
{
	if(top==stacksize-1) throw "栈满,无法入栈";
	top++;
	base[top]=x;
	//cout<<"top:"<
}


template <class T>
T SqStack<T>::Pop()
{
	T x;
	if(top==-1) throw "栈空,不能出栈";
	x=base[top--];
	return x;
}

template <class T>
T SqStack<T>::GetTop()
{
	if(top==-1)
		throw "栈空,栈顶无元素";
	return base[top];
}

template <class T>
int SqStack<T>::StackEmpty()
{
	if(top==-1)
		return 1;
	else
		return 0;
}

template <class T>
void SqStack<T>::ClearStack()
{
	top=-1;
}

template <class T>
void SqStack<T>::StackTop()
{//返回栈顶指针
	cout<<"栈顶top= "<<top;
}

template <class T>
void SqStack<T>::StackTranverse()
{
	int i=top;
   while(i>=0)
     cout<<base[i--]<<'\t';
   cout<<endl;
 }

char pause;
 //主函数
int main()
{
	int e;
	SqStack<int> s(10);//建立容量为20、元素类型为整型的空栈
	system("cls");//执行系统命令cls,清屏
	int choice;
    do
	{//显示主菜单
		cout<<"1-元素入栈\n";
		cout<<"2-元素出栈\n";
		cout<<"3-取栈顶元素\n";
		cout<<"4-置栈空\n";
        cout<<"5-测栈空\n";
		cout<<"6-显示栈元素\n";
		cout<<"7-显示栈顶指针\n";
		cout<<"8-退出\n";
		cout<<"Enter choice:";
		cin>>choice;
		switch(choice)
			{
			case 1://入栈
				cout<<"请输入插入元素的值:";
				cin>>e;//
				cout<<endl;
				try
					{
					s.Push(e);
					}
				catch(char *err)
					{
					 cout<<err<<endl;
					 }
				cin.get(pause);
                system("pause");
				break;
	       case 2://出栈
		        try
					{
		             e=s.Pop ();
		             cout<<"出栈元素为:"<<e<<endl;
					 }
	           catch(char *err)
				   {
		            cout<<err<<endl;
					}
		       cin.get(pause);
               system("pause");
		       break;
	      case 3://获取栈顶元素
		       try
				   {
				   e=s.GetTop ();
				   cout<<"栈顶元素为:"<<e<<endl;
				   }
			   catch(char *err)
				   {
				    cout<<err<<endl;
					}
			   cin.get(pause);
			   system("pause");
			   break;
	      case 4://清空栈
		       s.ClearStack();
		       cin.get(pause);
               system("pause");
		       break;
	     case 5://测栈空
		      if(s.StackEmpty())
				  cout<<"栈空"<<endl;
		      else
			      cout<<"栈不空"<<endl;
		      cin.get(pause);
              system("pause");
		      break;
	    case 6://遍历栈
		     s.StackTranverse();
		     cin.get(pause);
             system("pause");
		     break;
		case 7://显示栈顶指针
			s.StackTop ();
			break;
		case 8://
			 cout<<"程序结束,Bye-Bye!"<<endl;
		    break;
	    default:
		     cout<<"Invalid choice\n";
		break;
		}
	cout<<endl;
	}while(choice!=8);
	return 0;
}

3.2 链队列的代码实现:

# include
using namespace std;

template <class DataType>
struct Node{
	DataType data;
	Node <DataType> *next;
};

template <class DataType>   			//在队列中同样有头结点; 
class LinkQueue{
	public:
		LinkQueue();
		~LinkQueue(){};
		void EnQueue(DataType x);
		DataType DeQueue();
		DataType GetQueue();
		int Empty(){ if(front==rear) return 1;
		        		else return 0;}
	private:
		Node<DataType> *front,*rear;
};

template <class DataType>
LinkQueue <DataType>::LinkQueue()
{
	Node<DataType> *s;
	s=new Node<DataType>;
	s->next=NULL;
	front=rear=s;

}

template <class DataType>     //根据队列的性质,入队只能从队尾; 
void LinkQueue<DataType>::EnQueue(DataType x)
{
	Node<DataType> *s;s=new Node<DataType>;
	s->next=NULL;
	s->data=x;
	rear->next=s; 			//在队的最后一个元素后面插入s 
	rear=s; 				//将rear后移;指向队尾元素; 	
}

template <class DataType> 	//根据队列的性质,出队只能从队头; 
DataType LinkQueue<DataType>::DeQueue()
{
	if(front==rear) throw "下溢"; 
	Node<DataType> *p;
	p=front->next;
	int x=p->data;
	front->next=p->next;
	if(p->next==NULL) rear=front;    //判断出队前长度是否为1;若为1 则使头尾指针相同; 
	delete p;
	return x;
}

template <class DataType> 
DataType LinkQueue<DataType>::GetQueue()
{
	return front->next->data;     //注意这里不改变front的位置;	
}

int main()
{
	LinkQueue <int>a;
	int b[6]={2,45,12,7,8,3};
	for(int i=0;i<5;i++)
	{ a.EnQueue(b[i]);
	}
	cout<<a.GetQueue()<<endl;
	cout<<a.DeQueue()<<endl;    //此时取队头与出队是一样的结果;
	cout<<a.DeQueue()<<endl;	
	return 0;
	
}

3.3 循环队列实现代码

#include//cout,cin
#include"process.h"//exit()
#include"stdio.h"//EOF,NULL
#include "iostream.h"
//循环队列类的定义
template <class DataType>
class CirQueue
{
	private:
		DataType *base;// 存储空间基址
		int front;// 队头指针
		int rear;// 队尾指针
		int queuesize;// 队容量
	public:
		CirQueue(int m);//构造空队列
		~CirQueue();// 析构函数,释放链队各结点的存储空间
		void EnQueue(DataType x);// 元素x入队
		DataType DeQueue();// 队顶元素出队
		DataType GetHead();// 取队头元素
		DataType GetLast();//取队尾元素
		int QueueEmpty(); // 判队空
		int QueueFull();//判队满
		void ClearQueue();//清空队
		void Pointer();//返回队头、队尾位置
		void QueueTranverse();//遍历队,输出队列元素
};

//循环队列类的实现
template <class DataType>
CirQueue<DataType>::CirQueue(int m)//构造函数
{//创建一空队
	base=new DataType[m];
	if(base==NULL)
	{
		cout<<"队创建失败,退出!"<<endl;
		exit(1);
	}
	front=rear=0;
	queuesize=m;
}

template <class DataType>
CirQueue<DataType>::~CirQueue()//析构函数
{//释放队列所占存储空间
	delete [] base;
	rear=0;
	front=0;
	queuesize=0;
}

template <class DataType>
void CirQueue<DataType>::EnQueue(DataType x)
{//元素入队
	if((rear+1)%queuesize==front) throw "上溢,无法入队";
	base[rear]=x;
	rear=(rear+1)%queuesize;
}

template <class DataType>
DataType CirQueue<DataType>::DeQueue()
{
	DataType x;
	if(front==rear) throw "下溢,不能出队";
	x=base[front];
	front=(front+1)%queuesize;
	return x;
}

template <class DataType>
DataType CirQueue<DataType>::GetHead()
{
	DataType x;
	if(front==rear) throw "队空,队顶无元素";
	x=base[front];
    return x;
}

template <class DataType>
DataType CirQueue<DataType>::GetLast()
{
	DataType x;
	if(front==rear) throw "队空,队顶无元素";
	x=base[rear-1];
	return x;
}


template <class DataType>
int CirQueue<DataType>::QueueEmpty()
{
	if(front==rear)
		return 1;
	else
		return 0;
}

template <class DataType>
int CirQueue<DataType>::QueueFull()
{
	if((rear+1)%queuesize==front)
		return 1;
	else
		return 0;
}

template <class DataType>
void CirQueue<DataType>::ClearQueue()
{
	front=rear=0;
}

template <class DataType>
void CirQueue<DataType>::Pointer()
{
	cout<<"队头front= "<<front<<endl;
	cout<<"队尾 rear= "<<rear<<endl;
}



template <class DataType>
void CirQueue<DataType>::QueueTranverse()
{
	int i=front;
   while(i!=rear)
   {
     cout<<base[i]<<'\t';
	 i=(i+1)%queuesize;
   }
   cout<<endl;
}



char pause;
 //主函数
int main()
{
	int e;
	CirQueue<int> q(10);
	system("cls");//执行系统命令cls,清屏
	int choice;
    do
	{//显示主菜单
		cout<<"1-元素入队\n";
		cout<<"2-元素出队\n";
		cout<<"3-取队头元素\n";
		cout<<"4-取队尾元素\n";
		cout<<"5-置队空\n";
        cout<<"6-测队空\n";
		cout<<"7-测队满\n";
		cout<<"8-显示首、尾位置\n";
		cout<<"9-输出队元素\n";
		cout<<"10-退出\n";
		cout<<"Enter choice:";

		cin>>choice;
		switch(choice)
			{
			case 1://入队
				cout<<"请输入插入元素的值:";
				cin>>e;//
				cout<<endl;
				q.EnQueue(e);
                cout<<e<<" 入队成功!"<<endl;
				cin.get(pause);
                system("pause");
				break;
	        case 2://出队
		        try
					{
		             e=q.DeQueue();
		             cout<<"出队元素为:"<<e<<endl;
					 }
	           catch(char *err)
				   {
		            cout<<err<<endl;
					}
		       cin.get(pause);
               system("pause");
		       break;
	       case 3://获取队头元素
		       try
				   {
				   e=q.GetHead();
				   cout<<"队头元素为:"<<e<<endl;
				   }
			   catch(char *err)
				   {
				    cout<<err<<endl;
					}
			   cin.get(pause);
			   system("pause");
			   break;
		   case 4://获取队尾元素
		       try
				   {
				   e=q.GetLast();
				   cout<<"队尾元素为:"<<e<<endl;
				   }
			   catch(char *err)
				   {
				    cout<<err<<endl;
					}
			   cin.get(pause);
			   system("pause");
			   break;
	       case 5://清空队
		       q.ClearQueue();
		       cin.get(pause);
               system("pause");
		       break;
	       case 6://测队空
		      if(q.QueueEmpty())
				  cout<<"队空"<<endl;
		      else
			      cout<<"队不空"<<endl;
		      cin.get(pause);
              system("pause");
		      break;
	       case 7://测队满
		      if(q.QueueFull())
				  cout<<"队满"<<endl;
		      else
			      cout<<"队不满"<<endl;
		          cin.get(pause);
                  system("pause");
		          break;
	        case 8://显示首、尾位置
				q.Pointer();
				cin.get(pause);
                system("pause");
				break;
		   case 9://遍历队
		       q.QueueTranverse();
		       cin.get(pause);
               system("pause");
		       break;
	       case 10://退出
		       break;
	       default:
		     cout<<"Invalid choice\n";
		     break;
		}
	}while(choice!=10);
	return 0;
}//end of main function

实验截图如下:
数据结构(三)——详解栈和队列及完整代码实现_第26张图片

3.4 顺序栈,两栈共享,链栈的应用

#include
using namespace std;
//栈
const int StackSize=100;
template<class DataType>
class SeqStack
{
public:
    SeqStack(){top=-1;}
    ~SeqStack(){}
    void Push(DataType x);
    DataType Pop();
    DataType GetTop(){if(top!=-1) return data[top];}
    int Empty()
	{
		if(top==-1)return 1;
		else return 0;
	}
//private:
    DataType data[StackSize];
    int top;
};
template<class DataType>//顺序栈入栈算法
void SeqStack<DataType>::Push(DataType x)
{
    if(top==StackSize-1)throw"上溢";
    data[++top]=x;
}
template<class DataType>//顺序栈出栈算法
DataType SeqStack<DataType>::Pop()
{
    if(top==-1)throw"下溢";
    DataType x=data[top--];
    return x;
}


//两栈共享空间
template<class DataType>
class BothStack
{
public:
    BothStack(){top1=-1;top2=StackSize;}
    ~BothStack(){}
    void Push(int i,DataType);
    DataType Pop(int i);
    DataType GetTop(int i);
    int Empty(int i);
private:
    DataType data[StackSize];
    int top1,top2;
};
template<class DataType>//两栈共享空间入栈算法
void BothStack<DataType>::Push(int i,DataType x)
{
    if(top1==top2-1)throw"上溢";
    if(i==1)data[++top1]=x;
    if(i==2)data[--top2]=x;
}
template<class DataType>//出栈算法
DataType BothStack<DataType>::Pop(int i)
{
    if(i==1){
        if(top1==-1)throw"下溢";
        return data[top1--];
    }
    if(i==2){
        if(top2==StackSize)throw"下溢";
        return data[top2++];
    }
}
template<class DataType>//取栈顶元素
DataType BothStack<DataType>::GetTop(int i)
{
	if(i==1){	if(top1!=-1) return data[top1];}
	if(i==2){	if(top2!=-1) return data[top2];}
}
template<class DataType>//判空操作
int BothStack<DataType>::Empty(int i)
{
	if(i==1)
	{
		if(top1==-1)
		{
			cout<<"栈1空"<<endl;
			return 1;
		}
		else
		{
			cout<<"栈1非空"<<endl;
			return 0;
		}
	}
	if(i==2)
	{
		if(top2==StackSize)
		{
			cout<<"栈2空"<<endl;
			return 1;
		}
		else
		{
			cout<<"栈2非空"<<endl;
			return 0;
		}
	}
	else
		return 0;
}
//(书上没有取栈顶元素和判空操作的代码


//链栈
template<class DataType>
struct Node
{
	DataType data;
	Node<DataType> *next;
};
template<class DataType>
class LinkStack
{
public:
    LinkStack(){top=NULL;}
    ~LinkStack(){};
    void Push(DataType x);
    DataType Pop();
    DataType GetTop(){if(top!=NULL)return top->data;}
    int Empty();
private:
    Node<DataType> *top;
};
template<class DataType>//链栈入栈算法
void LinkStack<DataType>::Push(DataType x)
{
	Node<DataType> *s;
    s=new Node<DataType>;s->data=x;
    s->next=top;top=s;
}
template<class DataType>//链栈出栈算法
DataType LinkStack<DataType>::Pop()
{
	Node<DataType> *p;
	p=new Node<DataType>;
    if(top==NULL)throw"下溢";
    DataType x=top->data;p=top;
    top=top->next;
    delete p;
    return x;
}
template<class DataType>//判空操作
int LinkStack<DataType>::Empty()
{
	if(top==NULL)
	{
		cout<<"栈为空"<<endl;
		return 1;
	}
	else
	{
		cout<<"栈非空"<<endl;
		return 0;
	}
}

int main()
{
	//顺序栈
	cout<<"顺序栈"<<endl;
	SeqStack<int> i1;//创建顺序栈i1
	cout<<"top="<<i1.top<<endl;
	i1.Push(3);
	i1.Push(2);
	i1.Push(1);//依次压入3,2,1
	cout<<"i1的栈顶元素是:"<<i1.GetTop()<<endl;
	cout<<"取走i1中元素"<<i1.Pop()<<endl;//取出栈顶元素 1,现在的栈顶元素应该是2
	cout<<"i1的栈顶元素是:"<<i1.GetTop()<<endl;
	cout<<endl;

	//两栈共享空间
	cout<<"两栈共享"<<endl;
	BothStack<char> i2;//创建两栈共享的栈i2
	i2.Push(1,'c');
	i2.Push(1,'b');
	i2.Push(1,'a');//向1中压入c,b,a
	i2.Push(2,'C');
	i2.Push(2,'B');
	i2.Push(2,'A');//向2中压入C,B,A
	cout<<"栈1的栈顶元素是:"<<i2.GetTop(1)<<endl;
	cout<<"栈2的栈顶元素是:"<<i2.GetTop(2)<<endl;
	cout<<"取走栈1中元素"<<i2.Pop(1)<<endl;
	cout<<"取走栈1中元素"<<i2.Pop(1)<<endl;
	cout<<"取走栈1中元素"<<i2.Pop(1)<<endl;
	i2.Empty(1);i2.Empty(2);
	cout<<endl;

	//链栈
	cout<<"链栈"<<endl;
	LinkStack<float> i3;//创建链栈i3
	i3.Push(3);
	i3.Push(2);
	i3.Push(1);//依次压入3,2,1
	cout<<"i3的栈顶元素是:"<<i3.GetTop()<<endl;
	i3.Empty();//判断栈是否为空
	cout<<"取走i3中元素"<<i3.Pop()<<endl;
	cout<<"取走i3中元素"<<i3.Pop()<<endl;
	cout<<"取走i3中元素"<<i3.Pop()<<endl;
	i3.Empty();
	return 0;
}

数据结构(三)——详解栈和队列及完整代码实现_第27张图片

你可能感兴趣的:(数据结构,队列,数据结构,链表,算法,线性代数)