队列和堆栈分顺序和链式队列和堆栈,我感觉没什么好归纳的,不难。队列先入先出,堆栈先入后出。队列还有循环队列。和堆排序结合后还有优先队列(实际应用比较多)。还有一些经典的应用,如中缀转后缀,后缀的计算等用到了堆栈,然后二叉树的一些遍历也经常用到队列和堆栈。简单的说都是对顺序储存结构(比如说数组)和链式储存结构(比如说链表)进行了一次封装,然后给了这些储存结构一些新的性质。最后还是那句话,只要思路掌握了,具体实现大可以写出水平写出风格!
一,队列:
template <class T>
class Queue
{
protected:
int front,rear;
T *data;
int maxsize;
public:
Queue ( int sz = 10 ){
rear= front=0;
maxsize=sz;
data=new T[maxsize];
};
~Queue ( ) {
delete [ ] data;
}
void Enq ( T & item );
int Outq( T & item);
void MakeEmpty ( );
int IsEmpty ( );
int IsFull ( );
};
template <class T>
void Queue<T>::Enq( T & item )
{
assert ( !IsFull ( ) ); //先决条件断言
data[ rear] = item; //加入新元素
rear++;
}
template <class T>
int Queue<T>::Outq( T & item)
{
if ( IsEmpty ( ) ) return 0; //
item=data[front];
front++;
return 1;
}
template <class T>
int Queue<T>::IsEmpty ( )
{
if (front==rear)
{
return 1;
}
else
{
return 0;
}
}
template <class T>
int Queue<T>::IsFull( )
{
if (rear==maxsize)
{
return 1;
}
else
{
return 0;
}
}
template <class T>
void Queue<T>::MakeEmpty()
{
rear=front=0;
}
二,堆栈:
class Stack
{
protected:
int top; //栈顶指针
Type *elements; //栈元素数组
int maxSize; //栈最大容量
public:
Stack ( int sz = 10 ); //构造函数
~Stack ( ) { delete [ ] elements; }
void Push ( Type & item ); //进栈
int Pop( Type & item); //出栈
Type GetTop ( ); //取栈顶
void MakeEmpty ( ) { top = -1; } //置空栈
int IsEmpty ( ) const { return top == -1; }
int IsFull ( ) const
{ return top == maxSize-1; }
};
template <class Type>
Stack<Type> ::Stack ( int s ) : top (-1), maxSize (s)
{
elements = new Type[maxSize];
assert ( elements != NULL ); //断言
}
template <class Type>
void Stack<Type> ::Push ( Type & item )
{
assert ( !IsFull ( ) ); //先决条件断言
elements[++top] = item; //加入新元素
} ;
template <class Type>
int Stack<Type> ::Pop (Type &Item )
{
if ( IsEmpty ( ) ) return 0; //栈空不退栈
Item=elements[top];
top--;
return 1; //退出栈顶元素
}
template <class Type>
Type Stack<Type>::GetTop ( )
{
assert ( !IsEmpty ( ) ); //先决条件断言
return elements[top]; //取出栈顶元素
}
三,堆栈的应用——中缀转后缀并计算
//具体规则为:在中序序列中遇到数值,直接放到后缀序列中遇到“(”入栈,遇到比“)”出栈直到和他相对应的“(”,
//并将“(”也出栈,
//把除括号外的运算符放后缀到序列中。对于其他运算符,
//遇到比栈顶元素大的运算符入栈,遇到比栈顶元素小的,将栈顶元素出栈,直到栈顶运算符比当前运算符优先级小,并将当
//前运算符入栈,直到中缀序列结束。最后将栈内运算符放到后缀序列中。
void operation(char* exp1)//中缀转后缀
{
int i=0;
int pos1=0,pos2=0;
char *exp2;
exp2=new char[100];
char temp;
Stack<char> s2(100);//通过栈正确输出运算符顺序
char first='#';
s2.Push(first);
while(exp1[pos1]!='#')
{
if(judgenum(exp1[pos1]))
{
exp2[pos2]=exp1[pos1];
pos2++;
pos1++;
}
else
{
char sign=judgeop(s2.GetTop(),exp1[pos1]);
switch(sign)
{
case '>':s2.Push(exp1[pos1]),pos1++;break;
case '=':s2.Pop(temp),pos1++;break;
case '<':
{
s2.Pop(temp);
exp2[pos2]=temp;
pos2++;
break;
}
}
}
}
while(s2.Pop(temp))
{
exp2[pos2]=temp;
pos2++;
}
cout<<"后缀表达式为:";
while(exp2[i]!='#')
{
cout<<exp2[i]<<" ";
i++;
}
cout<<endl;
cout<<"结果为:";
Result(exp2);
cout<<endl;
delete[]exp2;
}
char judgeop(char o1,char o2)//优先级比较
{
switch(o1)
{
case '#':return '>';
case '+':{switch(o2)
{
case '*':
case '/':
case '(':return '>';
case '+':
case '-':
case ')':return '<';
}}
case '-':
{
switch(o2)
{
case '*':
case '/':
case '(':return '>';
case '+':
case '-':
case ')':return '<';
}
}
case '*':
{
switch(o2)
{
case '(':return '>';
case '*':
case '/':
case '-':
case '+':
case ')':return '<';
}
}
case '/':
{
switch(o2)
{
case '(':return '>';
case '*':
case '/':
case '+':
case '-':
case ')':return '<';
}
}
case '(':
{
switch(o2)
{
case '+':
case '-':
case '*':
case '/':
case '(':return '>';
case ')':return '=';
}
}
}
}
double operate(double a,double b,char c)//单个运算符的计算
{
switch(c)
{
case '+':return (a+b);
case '-':return (a-b);
case '*':return (a*b);
case '/':return (a/b);
}
}
//将后序序列中元素入栈,当遇到运算符时出栈两个元素和运算符进行运算,将结果入栈,如此连续
//到序列运算完成,,,,
void Result(char *exp1)//计算后缀表达式
{
Stack<double> s1(100);
int pos=0;
double temp1,temp2;
double result=0;
while(exp1[pos]!='#')
{
if (exp1[pos]>=48&&exp1[pos]<=57)
{
double d=(double)(exp1[pos]-48);
s1.Push(d);
pos++;
}
else
{
s1.Pop(temp1);
s1.Pop(temp2);
result=operate(temp2,temp1,exp1[pos]);
s1.Push(result);
pos++;
}
}
s1.Pop(result);
cout<<result<<endl;
}
四,队列的应用:
//队列的应用:根据关系划分子集,
void divisition(int r[9][9],int n)
{
int *q,*temp,*s;
q=new int[n];
temp=new int[n];
s=new int[n];
Queue<int> que(20);
int set=0,i,k,per=1;
for (k=1;k<=n;k++)//第一次将所有元素入队
{
que.Enq(k);
}
do
{
que.Outq(i);
if (i<=per)//如果当前值比前一个小的话说明一个子集排完,开始排下一个子集
{
set++;//子集数加一
s[i]=set;
for(k=1;k<=n;k++)
temp[k]=r[i][k];
per=i;
}
else
{
if (temp[i]!=0)//冲突,重新入队,等待下一次排列
{
que.Enq(i);
}
else
{
s[i]=set;//不冲突,赋值为当前子集数
for (k=i+1;k<=n;k++)
{
temp[k]=temp[k]+r[i][k];//增加当前值的冲突关系
}
}
per=i;//标记当前值,和下一个比较
}
} while (!que.IsEmpty());
cout<<"元素 :";
for(int i=1;i<=9;i++)
cout<<i<<" ";
cout<<endl;
cout<<"所属子集:";
for(int i=1;i<=n;i++)
cout<<s[i]<<" ";
delete []q;
delete []s;
delete []temp;
}