栈和队列

栈定义:只允许在表的末端进行插入和删除的线性表。栈是后进先出。
栈的抽象数据类型有两种典型的存储表示:基于数组的存储表示的顺序栈和基于链表的存储表示的链式栈。

栈的类定义:

const int maxSize=50;
enum bool{false,true};
template<class T>
class Stack{
public:
	Stack(){};
	virtual void Push(const T& x)=0;
	virtual bool Pop(T& x)=0;
	virtual bool getTop(T& x) const=0;
	virtual bool IsEmpty() const=0;
	virtual bool IsFull() const=0;
	virtual int getSize() const=0;
}

顺序栈

在顺序栈的声明中用顺序表定义它的存储空间。当前栈顶位置由数组下标指针top指示(这里的指针其实就是标记数组下标的一种表示)。

顺序栈的类定义:

#include <assert.h>
#include <iostream.h>
#include "stack.h"
const int stackIncerament = 20;//栈溢出时扩展空间的增量
template <class T>
class SeqStack: public Stack<T>{
public:
	SeqStack();
	~SeqStack(){delete[]elements;}
	void Push(const T& x);
	bool Pop(T& x);
	bool getTop(T& x);
	bool IsEmpty()const {return (top==-1)?true:false;}
	bool IsFull()const {return (top==maxSize-1)?true:false;}
	int getSize() const {return top+1;}
	void MakeEmpty() {top=-1;}
	friend ostream& operator<<(ostream& os,SeqStack<T>& s){...}
private:
	T *elements;
	int top;
	int maxSize;
	void overflowProcess();
};

链式栈

链式栈是线性表的链接存储表示。采用链式栈来表示一个栈,便于结点的插入与删除。在程序中同时使用多个栈的情况下,用链接表示不仅能够提高效率,还可以达到共享存储空间的目的。
链式栈的栈顶在链表的表头,因此,新结点的插入和栈顶结点的删除在链表的表头,即栈顶进行。

栈的应用——表达式的计算

算术表达式的后缀表示:<操作数><操作数><操作符>例如 AB+。只需要一个栈,而前缀和后缀需要用两个栈。

C++中操作符的运算优先级

优先级1234567
操作符单目—,!*,/,%+,-<,<=,>,>===,!=&&||

利用后缀表示求解表达式的值时,从左向右顺序地扫描表达式,并使用一个栈暂存扫描到的操作数或计算结果。
后缀表示计算表达式值的过程:顺序扫描表达式的每一项,然后根据它的类型做如下相应操作:如果该项是操作数,则将其压入栈中;如果该项是操作符<op>,则连续从栈中退出两个操作数Y和X,形成运算指令X< op >Y,并将计算结果重新压入栈中。当表达式的所有项都扫描并处理完后,栈顶存放的就是最后的计算结果。

利用栈将中缀表示转换为后缀表示
操作符在栈内和栈外优先数表(isp是栈内优先数,icp是栈外优先数)

操作符ch#(*,/,%+,-)
isp01532
icp06421

算法描述:

  • 操作符栈初始化,将结束符#进栈。然后读入中缀表达式字符流的首字符ch。

  • 重复执行以下操作,直到遇到ch=‘#’,同时栈顶的操作符也是‘#’,停止循环。
    a. 若ch是操作数直接输出,读入下一个字符ch。
    b. 若ch是操作符,判断ch的优先级icp和当前位于栈顶的操作符op的优先级isp:

    • 若icp(ch) > isp(op),令ch进栈,读取下一个字符ch。
    • 若icp(ch)<isp(op),退栈并输出。
    • 若icp(ch)==isp(op),退栈但不输出,若退出的是’('号读入下一个字符ch。

    c. 算法结束

算法实现:

void postfix(expression e){
	Stack<char> s;
	char ch = '#',ch1,op;
	s.Push(ch);
	cin.Get(ch);//读入一个字符
	while(s.IsEmpty()==false && ch!='#')
		if(isdigit(ch) {cout<<ch; cin.Get(ch);}
		else{
			s.getTop(ch1);
			if(isp(ch1)<icp(ch)){
				s.Push(ch);
				cin.Get(ch);}
			else if(isp(ch1)>icp(ch)){
				s.Pop(op);
				cout<<op;}
			else{
				s.Pop(op);//优先数相等出现在括号配对或者栈底‘#’与输入流最后的‘#’匹配
				if(op=='(') cin.Get(ch);
				}
			}
		}

栈与递归

3种用到递归的方法:

  1. 定义时递归的。例如阶乘
  2. 数据结构是递归的。例如链表
  3. 问题的解法是递归的。例如汉诺塔

汉诺塔

将n个盘子从A移到C中。如果n=1,则将这个盘子直接从A柱移到C柱,否则,执行以下3步:

  1. 用C柱做过渡,将A柱上的(n-1)个盘子移到B柱上;
  2. 将A柱上最后一个盘子直接移到C柱上;
  3. 用A柱当做过渡,将B柱上的(n-1)个盘子移到C柱上。

算法:

#include<iostream.h>
#include<string.h>
void Hanoi(int n,String A,string B,string C){//将n个盘子从A移到C
	if(n==1)
		cout<<“move top disk from peg” << A << "to peg" << C <<end;
	else{
		Hanoi(n-1,A,C,B);//将n-1个盘子从A移到B,借助C柱
		cout<<"Move top disk from peg" << A <<"to peg" << C <<endl;//最后一个移到C柱
		Hanoi(n-1,B,A,C);//将B柱n-1个盘子移到C柱
		}
}

用栈实现递归过程的非递归算法

斐波那契数列。
递归过程:

long Fib(long n){
	if(n<=1) return n;
	else return Fib(n-1)+Fib(n-2);

用栈帮助求解斐波那契的非递归算法:

struct Node{//用栈记录回退路径,tag=1是向左递归,tag=2是向右递归
	long n;
	int tag;
};

long Fibnacci(long n){
	Stack<Node> S; Node *w; long sum=0;
	do{
		while(n>1){w->n = n; w->tag=1; S.push(w); n--;}
		sum = sum+n;
		while(S.IsEmpty()==false){
			S.Pop(w);
			if(w->tag==1){
				w->tag=2;S.push(w);n=w->n-2;break;}
			}
		}while(S.IsEmpty()==false);
		return sum;
	};

迭代法计算斐波那契数列:

long FibIter(long n){//计算第n项斐波那契数列
	if(n<=1) return n;
	long twoback=0; oneback=1; Current;
	for (int i=2; i<=n; ++i){
		Current=twoback+oneback;
		twoback=oneback;
		oneback=Current;
		}
	return Current;
};

队列

队列是另一种限定存取位置的线性表。只允许在表的一端插入,在另一端删除,允许插入的一端叫做队尾,允许删除的一端叫做队头,具有先进先出特点。

循环队列

基于数组的存储表示。设置两个指针front和rear,分别指示队列的队头和队尾位置。
每当加入一个新元素时,先将新元素添加到rear所指位置,再让队尾指针rear进1;如果要退出队头元素,应当首先把front所指位置上的元素值记录下来,再让队头指针front进1,最后把记录下的元素值返回。

为了避免假溢出,利用循环队列。当front和rear进到maxSize-1,再前进一个位置就自动到0,这可以利用除法取余的运算来实现。
队头指针进1:front=(front+1)%maxSize;
队尾指针进1:rear=(rear+1)%maxSize;
判断队空条件,用(rear+1)%maxSize == front,让rear指到front的前一位置就认为队已满。所以在队满情形实际空了一个元素位置。在循环队列中,最多只能存放maxSize-1个元素。

链式队列

基于单链表的一种存储表示。队列的队头指针指向单链表的第一个结点,队尾指针指向单链表的最后一个结点。
应用:杨辉三角等

优先队列

每次从队列中取出的应是具有最高优先权元素。

双端队列

可以在队列的两端进行插入和删除。可以基于数组或者链表表示。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值