第三章 栈和队列
1.顺序栈的实现
const int StackSize=100;
template <typename DataType>
class SeqStack{
private:
DataType data[StackSize];
int top;
public:
SeqStack(){top=-1;}
~SeqStack(){}
void push(DataType x); //入栈操作,将元素x入栈
DataType pop(); //出栈操作
DataType Gettop(); //取栈顶元素
int Empty(){return top==-1?1:0;} //判断栈是否为空
int getSize(){return top;} //返回栈的长度
};
template<typename DataType>
void SeqStack<DataType>::push(DataType x){
if(top==StackSize-1) cout<<"full";
data[++top]=x; //也可能是top++,当top指向最后一个数据元素的下一个位置时
}
template<typename DataType>
DataType SeqStack<DataType>::pop(){
DataType x;
if(top==-1) cout<<"empty";
x=data[top--];
return x;
}
template<typename DataType>
DataType SeqStack<DataType>::Gettop(){
if(top==-1) cout<<"empty";
else return data[top];
}
2.数制转换(顺序栈)
十进制数N和其他d进制数的转换是计算机实现计算的基本问题,其解决方法很多,其中一个简单算法基于下列原理:N = (N div d) * d +(N mod d)
其中div是整除运算,mod是求余运算。例如(2018)10= (3742)8= (7E2)16
int main()
{
int N,d;
cin>>N>>d;
SeqStack<int>S;
int m;
int e;
while(N>0)
{
m=N%d;
N=N/d;
S.Push(m);
}
while(S.Empty()==0)
{
e=S.Pop();
if(e>9) cout<<char(e+55);
else cout<<e;
}
}
3.括号匹配(顺序栈)
自己想的,有编译信息的错误
int main()
{
string str;
cin>>str;
SeqStack<char>S;
int i;
for(i=0;i<str.length() ;i++)
{
if(str[i]=='(' || str[i]=='[' || str[i]=='{')
{
S.Push(str[i]);
}
else if(str[i]==')' || str[i]==']' || str[i]=='}')
{
if(S.Empty()==1 )
{
cout<<"NO";
i++;
//必须有这句,来排除当遍历到最后一个i=str.length()-1时,前面没有匹配的右括号
break;
}
else S.Pop() ;
}
}
if(S.Empty() ==0) cout<<"NO";
else if(S.Empty() ==1 && i==str.length()-1) cout<<"YES";
}
4. 合法序列(顺序栈)和上一个差不多
假设以I和O分别表示入栈和出栈操作,栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,称可以操作的序列为合法序列,否则称为非法序列。写出一个算法,判定所给的操作序列是否合法。若合法,输出1,否则输出0。
int main()
{
string str;
cin>>str;
int flag;
SeqStack<char>S;
for(int i=0;i<str.length() ;i++)
{
if(str[i]=='I')
{
S.Push(str[i]);
}
else if(str[i]=='O')
{
if(S.Empty() ) flag=0;
else S.Pop() ;
}
}
if(S.Empty() ==0) flag=0;
else flag=1;
cout<<flag;
}
5.中缀表达式转后缀表达式并求值(顺序栈)
bool Number(char ch)//判断是否为数字,是则返回true
{
if(ch>='0' && ch<='9') return true;
else return false;
}
具体实现代码
#include <iostream>
#include <math.h>
#include<stdio.h>
using namespace std;
const int StackSize=100;
template <class DataType>
class SeqStack{
private:
DataType data[StackSize];
int top;
public:
SeqStack(){top=-1;}
~SeqStack(){}
void push(DataType x); //入栈操作,将元素x入栈
void pop(); //出栈操作
DataType Gettop(); //取栈顶元素
int Empty(){return top==-1?1:0;} //判断栈是否为空
int getSize(){return top;} //返回栈的长度
};
template<class DataType>
void SeqStack<DataType>::push(DataType x){
if(top==StackSize-1) cout<<"full";
data[++top]=x;
}
template<class DataType>
void SeqStack<DataType>::pop(){
if(top==-1) cout<<"empty";
top--;
}
template<class DataType>
DataType SeqStack<DataType>::Gettop(){
if(top==-1) cout<<"empty";
else
return data[top];
}
bool Number(char ch)//判断是否为数字,是则返回true
{
if(ch>='0' && ch<='9') return true;
else return false;
}
void InPut(char*& str)//接收输入的中缀表达式的函数,并简单判断是否合法
{
//cout << "Please Enter What You Want To calculation:" << endl;
while (1)
{
cin >> str;
if (Number(str[0]))//中缀表达式的第一个必定是数字,如果不是,则非法
{
break;
}
else
{
cout << "Illegal Input,Please Input Again:";
delete[] str;
}
}
}
int GetPriority(char sy)//设置各个操作符的优先级
{
switch (sy)
{
case '#':
return 0;
case '(':
return 1;
case '+':
case '-':
return 3;
case '*':
case '/':
return 5;
case ')':
return 6;
default:
return -1;
}
}
void AddSpace(char*& arr)//给转成的后缀表达式的数字和符号添加空格,区分每个字符
{
*arr = ' ';
arr++;
}
char* GetBack()//获取后缀表达式的函数
{
char* middle = new char[30];
char* back = new char[30];
char* backend = back;
InPut(middle);
SeqStack<char> s;
s.push('#');
while (*middle)
{
if (Number(*middle) || *middle == '.')//如果是数字或者小数的话,直接输出
{
*back = *middle;
back++, middle++;
}
else
{
if (Number(*(back - 1)))//只有他的上一个时数字的话,才继续给空格
//否则遇到多个操作符,则输出域会存在多个空格
{
//*back = ' ';
//back++;
AddSpace(back);
}
if (*middle == ')')//如果右括号的话,输出所有操作符直到遇到左括号,并抛弃相对应的一堆括号
{
while (s.Gettop() != '(')
{
*back = s.Gettop();
s.pop();
back++;
AddSpace(back);
}
middle++;
s.pop();//抛弃左括号
}
else if (*middle == '(')//遇到左括号,则进入栈
{
s.push(*middle); middle++;
}
else if (GetPriority(*middle) > GetPriority(s.Gettop()))//如果栈内的操作符优先级高于栈外的优先级,则入栈
{
s.push(*middle); middle++;
}
else if (GetPriority(*middle) <= GetPriority(s.Gettop()))
//如果栈内的操作符优先级低于或等于栈外的优先级,输出栈内的符号,并入栈栈外的符号
{
*back = s.Gettop();
s.pop();
s.push(*middle);
back++; middle++;
AddSpace(back);
}
}
}
while (s.Gettop() != '#')//中缀表达式遍历完成,但是=栈中还有符号存在,一一出栈输出
{
AddSpace(back);
*back = s.Gettop();
s.pop(); back++;
}
*back = '\0';
//cout << "The Back Is: " << backend << endl;
return backend;
}
double GetNumber(char*& arr)
{
//因为输出为char*,所以可能两位数以上的数字被拆开,此函数为正确得到数字
double sum[10] = { 0 }; int i = 0; double result = 0;
while (*arr != ' ')
{
sum[i] = *arr-48;
i++;
arr++;
}
int k = i - 1;
for (int j = 0; j < i; j++,k--)
{
result += (sum[j] * pow(10, k));
}
return result;
}
double Cauculate(char ch, double left, double right)//各个操作符对应的操作
{
switch (ch)
{
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
default:
return 0;
break;
}
}
double CountBack(char* back)
{
SeqStack<double> s;
while (*back)
{
if (Number(*back))//遇到数字
{
s.push(GetNumber(back));//将正确的数字入栈
}
else if (*back == ' ')
{
back++;//遇到空格跳过
}
else
{
double a = s.Gettop();
s.pop();
double b = s.Gettop();
s.pop();
s.push(Cauculate(*back, b, a));//遇到符号时,取栈顶的第二个数和第一个数求解,并入栈
back++;
}
}
while (s.getSize() >= 2)//最终栈内存在的数大于2时,继续计算,直到只剩下一个数
{
double a = s.Gettop();
s.pop();
double b = s.Gettop();
s.pop();
s.push(Cauculate(*back, b, a));
}
//返回这个数字,既是最终结果
return s.Gettop();
}
int main()
{
cout<<CountBack(GetBack())<<endl;;
return 0;
}
6.循环队列的实现
const int QueueSize=100;
template <typename DataType>
class CirQueue{
public:
CirQueue();
~CirQueue();
//循环队列是静态存储分配,在循环队列变量退出作用域时自动释放所占内存单元,因此,循环队 列无需销毁,虚构函数为空
void EnQueue(DataType x);
DataType DeQueue();
DataType GetHead();
int Empty();
void PrintQueue()
private:
DataType data[QueueSize];
int front,rear;
};
template <typename DataType>
CirQueue<DataType>::CirQueue()
{
front = rear = QueueSize-1;
//初始化一个空的循环队列只需将对头front和队尾rear同时指向数组的某一位置,一般是数组的高端
}
template <typename DataType>
void CirQueue<DataType>::EnQueue(DataType x)
{
if((rear+1)%QueueSize==front) cout<<"full"<<endl; //牺牲一个存储单元
rear=(rear+1)%MaxSize; //队尾指针在循环意义下加一
data[rear]=x; //在队尾处插入元素
}
template <typename DataType>
DataType CirQueue<DataType>::DeQueue()
{
if(rear==front) cout<<"empty"<<endl;
front=(front+1)%QueueSize; //对头在循环意义下加一
return data[front]; //返回队头元素
}
template <typename DataType>
DataType CirQueue<DataType>::GetHead()
{
if(rear==front) cout<<"empty"<<endl;
return data[(front +1)%QueueSize]; //注意不修改队头指针(front指向一个空的)
}
template <typenamae DataType>
int CirQueue<DataType>::Empty()
{
if(rear==front) return 1;
}
7.循环队列重新排列顺序栈
(exchange方法自己想的有点复杂)
设顺序栈S中有2n个元素,从栈顶到栈底的元素依次为,要求通过一个循环队列重新排列栈中元素,使得从栈顶到栈底的元素依次为。请设计算法实现该操作,要求空间复杂度和时间复杂度均是O(n)。【输入格式】栈的长度(n/2)以及元素(中间用空格隔开)
【输出格式】经过队列相应操作后的序列。
【输入样例】
3
1 2 3 4 5 6
【输出样例】6 4 2 5 3 1
提示:操作步骤:
1、将所有元素出栈并入队;
2、依次将队列元素出队,如果是偶数结点,则再入队,如果是奇数结点,则入栈;
3、将奇数结点出栈并入队;
4、将偶数结点出队并入栈;
5、将所有元素出栈并入队;
6、将所有元素出队并入栈即为所求;
#include <iostream>
#include <stack> //栈
#include <queue> //队列
using namespace std;
stack<int> seqStack;
queue<int> cirQueue;
int n;
void init(int len)
{
for(int i=0;i<2*len;++i){
int elem;
cin>>elem;
seqStack.push(elem);
}
}
void exchange()
{
int a,b,c,d,e,f;
int count=0;
for(int i=0;i<n*2;i++) //将所有元素出栈并入队
{
a=seqStack.top();
seqStack.pop();
cirQueue.push(a);
count++;
}
for(int i=0;i<n*2;i++) //依次将队列元素出队,如果是偶数结点,则再入队,如果是奇数结点,则入栈
{
b=cirQueue.front(); //取队头元素
cirQueue.pop();
if(count%2==0) cirQueue.push(b);
else seqStack.push(b);
count--;
}
for(int i=0;i<n;i++) //将奇数结点出栈并入队
{
c=seqStack.top();
seqStack.pop();
cirQueue.push(c);
}
for(int i=0;i<n;i++) //将偶数结点出队并入栈
{
d=cirQueue.front();
cirQueue.pop();
seqStack.push(d);
}
for(int i=0;i<n;i++) //将所有元素出栈并入队
{
e=seqStack.top();
seqStack.pop();
cirQueue.push(e);
}
for(int i=0;i<n*2;i++) //将所有元素出队并入栈即为所求
{
f=cirQueue.front();
cirQueue.pop();
seqStack.push(f);
}
}
void printStack()
{
while(!seqStack.empty()){
cout<<seqStack.top()<<" ";
seqStack.pop();
}
cout<<endl;
}
int main()
{
cin>>n;
init(n);
exchange();
printStack();
return 0;
}
8.循环链队列的入队和出队
假设以不带头结点的循环链表表示非空队列,并且只设一个指针指向队尾结点,但不设头指针。试设计相应的入队和出队的算法。
【输入说明】 入队次数m以及m个入队元素;(中间用空格隔开) 出队次数n;
【输出说明】执行m次入队操作和n次出队操作后,打印队列中的元素:如果队列为空则输出“Empty”。
#include <iostream>
using namespace std;
template <class DataType>
struct node{
DataType data;
node<DataType>* next;
};
template <class DataType>
class cirLinkQueue{
public:
cirLinkQueue();
cirLinkQueue(DataType a[],int n);
void enQueue(DataType elem);
bool deQueue();
void printQueue();
private:
node<DataType>* rear;
};
template <class DataType>
cirLinkQueue<DataType>::cirLinkQueue()
{
rear = NULL;
}
template <class DataType>
cirLinkQueue<DataType>::cirLinkQueue(DataType a[],int n)
{
if(n == 1){
rear = new node<DataType>;
rear->data = a[0];
rear->next = rear;
}
else{
rear = new node<DataType>;
rear->data = a[0];
rear->next = rear;
for(int i=1;i<n;++i){
node<DataType>* s = new node<DataType>;
s->data = a[i];
s->next = rear->next; //先右后左
rear->next = s;
rear = s;
}
}
}
template <class DataType>
void cirLinkQueue<DataType>::enQueue(DataType elem) //入队
{
node<DataType>* s = new node<DataType>;
s->data=elem;
if(rear==NULL)
{
rear=s;
rear->next=s;
}
else
{
s->next=rear->next;
rear->next=s;
rear=s;
}
}
template <class DataType>
bool cirLinkQueue<DataType>::deQueue() //出队
{
node<DataType>* q=NULL;
if(rear==NULL) return 0;
q=rear->next;
if(q==rear)
{
rear=NULL;
}
else
{
rear->next=q->next;
delete q;
}
return 1;
}
template <class DataType>
void cirLinkQueue<DataType>::printQueue()
{
if(rear == NULL)
cout<<"Empty"<<endl;
else{
node<DataType>* p = rear->next;
while(p != rear){
cout<<p->data<<" ";
p = p->next;
}
cout<<p->data<<endl;
}
}
int main()
{
cirLinkQueue<int> Q;
int m,n;
cin>>m;
while(m--){
int elem;
cin>>elem;
Q.enQueue(elem);
}
cin>>n;
while(n--){
bool res = Q.deQueue();
if(!res) break;
}
Q.printQueue();
return 0;
}