第三章:线性结构之栈和队列
栈
1.栈的定义:只允许在一端插入和删除 的线性表。 允许插入和删除的一端称为栈顶 (top),另一端称栈底(bottom) 。
2.栈的特点:后进先出 (LIFO) 。
1 2 3 4 5 6 7 8 9 10 11 12
| template <class T> //此程序放入stack.h class Stack { public: Stack( ){ }; virtual void Push(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; }; 栈
|
顺序栈
基于数组的存储表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <assert.h> //P89程序3.2 #include <iostream.h> #include “stack.h” const int stackIncrement=20; template <class T> class SeqStack : public Stack<T> { private: T *elements; int top; int maxSize; void overflowProcess(); public: SeqStack(int sz =50); ~SeqStack() { delete []elements; } void Push(const T& x); bool Pop(T& x); bool getTop(T& x); bool IsEmpty() const { return top == -1; } bool IsFull() const { return top == maxSize-1; } int getSize( )const {return top+1 ; } void makeEmpty( ){top=-1 ; } };
template <class T> void SeqStack<T>::overflowProcess() {
T *newArray = new T[maxSize+stackIncrement]; if(newArray==NULL){cerr<<“失败”<<endl; exit(1); } for (int i = 0; i <= top; i++) newArray[i] = elements[i]; maxSize += stackIncrement ; delete [ ]elements; elements = newArray; }; template <class T> void SeqStack<T>::Push(const T& x) {
if (IsFull() == true) overflowProcess(); elements[++top] = x; }; template <class T> bool SeqStack<T>::Pop(T& x) {
if (IsEmpty() == true) return false; x = elements[top--]; return true; }; template <class T> bool SeqStack<T>::getTop(T& x) { if (IsEmpty() == true) return false; x = elements[top]; return true; };
|
双栈共享一个栈空间
两个栈共享一个数组空间V[maxSize]
设立栈顶指针数组 t[2] 和栈底指针数组 b[2]
t[i]和b[i]分别指示第 i 个栈的栈顶与栈底
初始 t[0] = b[0] = -1, t[1] = b[1] = maxSize
栈满条件:t[0]+1 == t[1] //栈顶指针相遇
栈空条件:t[0] = b[0]或t[1] = b[1] //退到栈底
链式栈
基于链表的存储表示
链式栈不需要附加头结点,因为栈是特殊的线性表,只能在栈顶(即链表头部)插入或删除,所以 不需要附加头结点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| template <class T> class LinkedStack : public Stack<T> { private: LinkNode<T> *top; void output(ostream& os, StackNode <T> *ptr); public: LinkedStack( ) : top(NULL) { } ~LinkedStack( ) { makeEmpty( ); } void Push(T x); bool Pop(T& x); bool getTop(T& x) const; bool IsEmpty( ) const { return top == NULL; } int getSize( )const; void makeEmpty(); friend ostream& operator << (ostream& os, LinkedStack<T>& s) { }
};
template <class T> int LinkedStack<T>::getSize( )const{ LinkNode<T> *p=top; int k=0; while(p!=NULL) {k++; p=p->link;} return k; }
template <class T> void LinkedStack<T>::makeEmpty( ) {
LinkNode<T> *p; while (top != NULL) { p = top; top = top->link; delete p; } };
template <class T> void LinkedStack<T>::Push(const T& x) {
top = new StackNode<T> (x, top);
assert (top != NULL);
};
template <class T> bool LinkedStack<T>::Pop(T& x) { if (IsEmpty() == true) return false; LinkNode<T> *p = top; top = top->link; x = p->data; delete p; return true; };
template <class T> bool LinkedStack<T>::getTop(T& x) const { if (IsEmpty() == true) return false; x = top->data; return true; };
template <class T> ostream& operator << (ostream& os, LinkedStack<T>& s) { //从栈顶开始逐个输出 os<<“栈中元素个数=”<<s.getSize( )<<endl; StackNode<T> *p=s.top; //书上S.top应为s.top int i=0; while(p!=NULL) { os<<++i<<“:”<<p->data<<endl; p=p->link;} return os; }
//链式栈类操作-递归输出 template <class T> void LinkedStack<T>::output(ostream& os, StackNode<T> *ptr) { int i=1; //递归输出栈中所有元素(沿链逆向输出) if (ptr != NULL) { if (ptr->link != NULL) output(os, ptr->link, i++); os << i << “ : ” << ptr->data << endl; //递归结束条件ptr->link != NULL, //输出最后一个元素,然后沿链逐个返回输出 } };
|
栈的应用:括号匹配
如从左向右扫描,则每个右括号将与最近遇到的未匹配的左括号匹配。
把从左向右扫描到的左括号放入栈中,在后续扫描中遇到右括号时,就将它与栈顶的左括号 (如果存在)相匹配,同时在栈顶删除该左括号。
分析可能出现的不匹配的情况
1.到目前左括号少即:到来的是右括号而栈中无左括号在等待(栈是空的)
2.到结束右括号少。即:栈中还有左括弧没等到和它相匹配的右括弧
算法的设计思想
1)凡出现左括弧,则进栈;
2)凡出现右括弧,首先检查栈是否空若栈空,则表明“右括弧”多了,不匹配,否则“左括弧出栈”;
3)表达式检验结束时,若栈空,则匹配正确 否则说明左括弧多了,不匹配。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void PrintMatchedPairs(char* expression){ Stack<int> s(maxLength); int j, length=strlen(expression); for ( int i=1; i<length; i++) { if ( expression[i-1]==‘(’ ) s.Push(i); else if ( expression[i-1]==‘)’ ) { if ( s.Pop(j)==true ) cout<<j<<“与”<<i<<“匹配”<<endl; else cout<<“没有与”<<i<<“匹配的左括号”<<endl; } while ( s.IsEmpty( )==false ) { s.Pop(j); cout <<“没有与”<<j<<“匹配的左括号”<<endl; } }
|
栈的应用:表达式求值
一个表达式由操作数(亦称运算对象)、操作符(亦称运算符)和分界符组成。
算术表达式有三种表示:
中缀(infix)表示 <操作数> <操作符> <操作数>,如 A+B;
前缀(prefix)表示 <操作符> <操作数> <操作数>,如 +AB;
后缀(postfix)表示 <操作数> <操作数> <操作符>,如 AB+;
表达式
中缀表达式 a + b * ( c - d ) - e / f
后缀表达式 a b c d - * + e f / -
前缀表达式 - + a * b – c d / e f
结论
1)操作数之间的相对次序不变
2)运算符之间的的相对次序不同
3)前缀式的运算规则为:
连续出现的两个操作数和在它们之前且紧靠它们的运算符 构成一个最小表达式;
4)后缀式的运算规则为:
运算符在式中出现的顺序恰为表达式的运算顺序; 每个运算符和在它之前出现且紧靠它的两个操作数构成一个最小 表达式;
算术表达式运算规则
运算规则:
先左后右,先乘除后加减,先括弧内后括弧外 。
例如:4+2*3-10/5=4+6-10/5=10-10/5= 10-2=8
4 2 3 * + 10 5 / - = 8
实现方法讲解:
中缀表达式直接求值法
借助于栈:OPND栈和OPTR栈
操作数入OPND栈,算符入OPTR栈
中缀变后缀表达式求值:
运算符顺序变化,需存储“等待中” 的运算符
需将当前运算符与等待中最后一个运算符比较
如何从中缀表达式求得后缀式?
利用堆栈存储“等待中”的运算符实现中缀变后缀表达式,为了实现这种转换,需要考虑各操作符在栈 内和栈外的优先级
对原表达式中出现的每一个运算符是否即刻 进行运算取决于在它后面出现的运算符
如果它的优先数“高或等于”后面的运算, 则它的运算先进行,
否则就得等待在它之后出现的所有优先数高 于它的“运算”都完成之后再进行。
从原表达式求得后缀式的规则为 :
1) 设立运算符栈;
2) 设表达式的结束符为“#”,预设运算符栈 的栈底为“#”;
3) 若当前字符是操作数,则直接发送给后缀式;
4) 若当前字符为运算符且优先数高于栈顶运算 符,则进栈,否则退出栈顶运算符发送给后 缀式;
5) 若当前字符是结束符,则自栈顶至栈底依次 将栈中所有运算符发送给后缀式;
注意:
一般作为相同运算符,先出现的比后出现的 优先级高;
先出现的运算符优先级低于“(”,高于“)”;
优先权相等的仅有“(”和“)”、“#”。
#:作为表达式结束符,通常在表达式之前 加一“#”使之成对,当出现“#”=“#”时,表 明表达式求值结束,“#”的优先级最低。
任意相继出现的算符θ1和θ2,都要比较优先权 关系。 一般任意两个相继出现的两个算符θ1和θ2之间 的优先关系至多有下面三种之一: θ1<θ2 θ2的优先权高于θ1 θ1=θ2 二者优先权相等 θ1>θ2 θ2的优先权低于θ1
中缀式转换为后缀式的算法 :
(isp叫做栈内(in stack priority)优先数; icp叫做栈外(in coming priority)优先数。操作符优先数相等的情况只出现在括号配对或 栈底的“#”号与输入流最后的“#”号配对时。)
操作符栈初始化,将符号‘#’进栈。然后读 入中缀表达式字符流的首字符ch。
重复执行以下步骤,直到栈为空,停止循 环。
若ch是操作数直接输出,读入下一个字 符ch。
若ch是操作符,判断ch的优先级icp和位 于栈顶的操作符op的优先级isp:
若 icp(ch) > isp(op),令ch进栈,读入下一 个字符ch。
若 icp(ch) < isp(op),退栈并输出。
若 icp(ch) == isp(op),退栈但不输出,若 退出的是“(”号读入下一个字符ch。
算法结束,输出序列即为所需的后缀表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void postfix ( expression e ) { stack<char> s; char ch, op; s.Push ( ‘#’ ); cin.Get ( ch ); while ( ! s.IsEmpty( ))
if ( isdigit ( ch ) ) { cout << ch; cin.Get ( ch ); } else { if ( isp ( s.GetTop( ) ) < icp ( ch ) ) c { s.Push ( ch ); cin.Get ( ch ); } else if ( isp ( s.GetTop( ) ) > icp ( ch ) ) { s.Pop(op); cout << op; } else { s.Pop(op); if ( op == ‘(’ ) cin.Get ( ch ); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Calculator { public: Calculator(int sz):s(sz){}; void Run(); void Clear(); private: Stack<double> s; void AddOperand(double value) ; bool Get2Operands(double& left,double& right); oid DoOperator(char op); }; void Calculator :: Run ( ) { char ch; double newoperand; while ( cin >> ch, ch != ‘#’ ) { switch ( ch ) { case ‘+’ : case ‘-’ : case ‘*’ : case ‘/’ : DoOperator ( ch ); break; default : cin.putback ( ch ); cin >> newoperand; AddOperand ( newoperand ); } }
|
栈的应用:递归
递归的定义
若一个对象部分地包含它自己,或用它自己 给自己定义, 则称这个对象是递归的;若 一个过程直接地或间接地调用自己, 则称这 个过程是递归的过程。
函数间的的执行
1 .操作系统中,当一个函数调用另一个函数,需先完成:
1) 将所有的实在参数、返回地址等信息传递给被调用函数保存
2) 为被调用函数的局部变量分配存储区;
3) 将控制转移到被调用函数的入口。
2 .从被调用函数返回调用函数之前,应该完成:
1) 保存被调函数的计算结果;
2) 释放被调函数的数据区;
3) 依照被调函数保存的返回地址将控制转移到调用函数
递归函数的概念
直接或间接地调用自身的函数称为递归函数。 从递归函数的执行过程看,递归函数设计时必须 有一个出口,直接处理, 从而结束对自身的调用。
构成递归的条件
不能无限制地调用本身, 必须有一个出口,直接处理。
递归定义包括两项,一是边界条件:描述递归终止时问题的求解 ;二是递归函数:将问题分解为与原问题性质相同,但 规模较小的问题。只有具备了这两个要素,递归函数才能在有限次计算后得出结果。
递归设计:自顶向下、逐步分解的策略
解决递归问题的策略是把一个规模比较大的 问题分解为一个或若干规模比较小的问题, 子问题应与原问题做同样的事情,且更为简 单;分别对这些比较小的问题求解,再综合 它们的结果,从而得到原问题的解。
以下三种情况常常用到递归方法
定义是递归的
数据结构是递归的
问题的解法是递归的
1 2 3 4 5 6 7 8 9 10
| void p(参数1) { if(数据为递归出口) 操作; else{ 操作; p(参数2); 操作; } }
|
递归过程改为非递归过程
递归过程简洁、易编、易懂。但递归过程效率低,重复计算多,改为非递 归过程的目的是提高效率 。
单向递归或尾递归可直接用迭代实现其非递归 过程(尾递归是单项递归的特例)
其他情形必须借助栈实现非递归过程
1 2 3 4 5 6 7 8 9 10 11 12
|
long FibIter(long 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; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
void recfunc(int A[ ], int n) { if (n >= 0) { cout << A[n] << “ ”; n--; recfunc(A, n); } }
void sterfunc(int A[ ], int n) {
while (n >= 0) { cout << "value " << A[n] << endl; n--; } }
|
递归与回溯
回溯法也常称为试探法。这种方法将问题的 候选解按某种顺序逐一检验,当发现当前解 不可能是解时,可以沿搜索路径回退到前一 结点,沿另一分支继续搜索,直到搜索到问题 的解,或搜完全部分支没有解存在为止。
回溯法常使用递归进行试探,或使用栈帮助向前试探。
迷宫问题
迷宫是一个矩形区域,有一个入口和一个出口,其内 部设置了许多不能穿越的墙壁,对从入口到出口的前 进道路上形成了许多障碍.若能正确的绕过障碍,则从入口到出口存在一条穿越 迷宫的路线。
前进方向:北、东北、东、东南 南、西南、西、西北 .
走步规则:首先从东开始,按照 顺时针方向搜索下一步可 能前进的位置 .
数据结构设计
1 用二维数组Maze[m+2][p+2]表示迷宫
若元素Maze[i][j]==1,表示该位置上是障碍。
若元素Maze[i][j]==0,表示该位置上是通路。
2 用二维数组mark[m+2][p+2]标志已走过 的路途,防止走老路。
初始化时,所有元素都是没走过的,设为0。
当行进到迷宫的某个位置[i][j]时,就将对应的 mark[i][j]置为1;
当前点的下一个试探位置 从当前位置Maze[i][j]出发,可能的前进方向有8个,用一 维数组move[8]表示。其数组元素为结构类型数据:
1 2 3 4 5 6 7 8
| struct offsets { int a, b; char *dir }
offsets move[8]={ {-1,0,"N"},{-1,1,"NE"}, {0,1,"E"}, { 1,1,"SE"}, {1,0,"S"},{1,-1,"SW" {0,-1,"W"},{-1,1,"NW"} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int SeekPath(int x,int y) { int i,g,h; char *d; if(x==m && y==n) return 1; for(i=0;i<8;i++) { g=x+move[i].a; h=y+move[i].b; d=move[i].dir; if(Maze[g][h]==0&&mark[g][h]==0) { mark[g][h]=1; if(SeekPath(g, h)) { cout<<“(“<<g<<“,”<<h<<“),”<<“direction”<<move[i].dir<< “,”; return 1; } } } if(x==1&&y==1) cout<<“no path in Maze”<<endl; Return 0; }
|
n皇后问题
在 n 行 n 列的国际象棋棋盘上,若两个皇后位于 同一行、同一列、同一对角线上,则称为它们为 互相攻击。n 皇后问题是指找到这 n 个皇后的互 不攻击的布局。
8皇后问题:在8X8格的国际象棋上摆放八个皇后,使 其不能互相攻击,即任意两个皇后都不能处于同一行、 同一列或同一斜线上,问有多少种摆法?
解题思路
安放第 i 行皇后时,需要在列的方向从 0 到 n-1 试探 ( j = 0, …, n-1 )
在第 j 列安放一个皇后: 如果在列、对角线方向有其它皇后,则 出现攻击,撤消在第 j 列安放的皇后。如果没有出现攻击,在第 j 列安放的皇 后不动,递归安放第 i+1行皇后。
设置数组 col [n] :col[i] 标识第 i 列是否安放了皇后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| void Queen(int i) { if (i>n) 输出棋盘布局; else for (int j = 1; j <= n; j++) { if (第 i 行第 j 列没有攻击) { 在第 i 行第 j 列安放皇后; Queen(i+1); } } }
void queen(int k) { if(k>n) {sum++ ;
cout<<"the solution of "<<sum <<endl; for(int i=1;i<=n;i++) {for(int j=1;j<=n;j++) if (x[i]==j) cout<<"* " ; else cout<<"0 "; cout<<endl ; } cout<<endl; } else for(int j=1;j<=n;j++) { x[k]=j; if(place(k)) queen(k+1); }} place(int t)
{ for(int i=1;i<t;i++) if((x[i]==x[t])|| (abs(i-t)==abs(x[i]-x[t])) ) return false ; return true; } Int sum=0; int main() { int n; cout<<"请输入皇后的数目"<<endl; cin>>n; int *x=new int[n+1] ; for(int i=0;i<=total;i++) x[i]=0; queen(1) ; cout<<"the result of nqueen is :"<<sum<<endl; delete [] x ; return 0; }
|
队列
队列是只允许在一端删除,在另一端插入 的线性表
允许删除的一端叫做队头(front),允许插 入的一端叫做队尾(rear)。
特性:先进先出(FIFO, First In First Out)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| template <class E> class Queue { public: Queue() { }; ~Queue() { }; virtual bool EnQueue(const E& x) = 0; virtual bool DeQueue(E& x) = 0; virtual bool getFront(E& x) = 0; virtual bool IsEmpty() const = 0; virtual bool IsFull() const = 0;
template <class E> class SeqQueue : public Queue<E> { int rear, front; E *elements; int maxSize; …….
};
|
队列的进队和出队原则
进队时先将新元素按 rear 指示位置加入, 再将队尾指针加一 rear = rear + 1。
队尾指针指示实际队尾的后一位置。
出队时按队头指针指示位置取出元素,再将 队头指针进一 front = front + 1,
队头指针指示实际队头位置。
队满时再进队将溢出出错(假溢出) ;
解决假溢出的办法之一:将队列元素存放数 组首尾相接,形成循环(环形)队列。
循环队列
队列存放数组被当作首尾相接的表处理。
为了防止队头、队尾指针加1产生假溢出,可用语言 的取模(余数)运算实现。
队列初始化:front = rear = 0; 队头指针进1: front = (front+1) % maxSize;
队尾指针进1: rear = (rear+1) % maxSize;
队空条件:front == rear;
队满条件:(rear+1) % maxSize == front (看示例)
通过牺牲一个存储空间来实现(课本上的方案)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| template <class E> class SeqQueue : public Queue<E> { int rear, front; E *elements; int maxSize; public: SeqQueue(int sz = 10); ~SeqQueue() { delete[ ] elements; } bool EnQueue(const E &x); bool DeQueue(E& x); bool getFront(E& x); void makeEmpty() { front = rear = 0; } bool IsEmpty() const { return front == rear; } bool IsFull() const { return ((rear+1)% maxSize == front); } int getSize() const { return (rear-front+maxSize) % maxSize; } };
template <class E> SeqQueue<E>::SeqQueue(int sz): front(0), rear(0), maxSize(sz) { elements = new E[maxSize]; assert ( elements != NULL ); }; template <class E> bool SeqQueue<E>::EnQueue(const E& x) {
if (IsFull() == true) return false; elements[rear] = x; rear = (rear+1) % maxSize; return true; }; template <class E> bool SeqQueue<E>::DeQueue(E& x) {
if (IsEmpty() == true) return false; x = elements[front]; front = (front+1) % maxSize; return true; }; template <class E> bool SeqQueue<E>::getFront(E& x) const { if (IsEmpty() == true) return false; x = elements[front]; return true; };
|
链式队列
队头在链头,队尾在链尾。
链式队列在进队时无队满问题,但有队空问 题。
队空条件为 front == NULL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
template <class E> struct LinkNode { E data; LinkNode<E> *link; public: LinkNode(const E& d , LinkNode<E>* next =null) : data(d), link(next) { } }; template <class E> class LinkedQueue { private: LinkNode<E> *front, *rear; public: LinkedQueue() : rear(NULL), front(NULL) { } ~LinkedQueue(MakeEmpty()); bool EnQueue(const E& x); bool DeQueue(E& x); bool GetFront(E& x); void MakeEmpty(); bool IsEmpty() const { return front == NULL; } }; template <class E> void LinkedQueue<E>::makeEmpty() { LinkNode<E> *p; while (front != NULL) { p = front; front = front->link; delete p; } }; template <class E> bool LinkedQueue<E>::EnQueue(const E& x) {
if (front == NULL) { front = rear = new LinkNode<E> (x); if (front == NULL) return false; } else { rear->link = new LinkNode<E> (x); if (rear->link == NULL) return false; rear = rear->link; } return true; }; template <class E> //如果队列不空,将队头结点从链式队列中删去 bool LinkedQueue<E>::DeQueue(E& x) { if (IsEmpty() == true) return false; LinkNode<E> *p = front; x = front->data; front = front->link; delete p; return true; }; template <class E> bool LinkedQueue<E>::GetFront(E& x) { if (IsEmpty() == true) return false; x = front->data; return true; };
|
队列的应用:打印杨辉三角形
算法逐行打印二项展开式 (a + b)i 的系数
每行的第i个元素,等于上一行的第i个元素和 它的前驱项相加的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <stdio.h> #include <iostream.h> #include "queue.h" void YANGHVI(int n) { Queue q(n+2); q.MakeEmpty(); q.EnQueue(1); q.EnQueue(1); int s = 0, t; for (int i = 1; i <= n; i++) { cout << endl; q.EnQueue(0); for (int j = 1; j <= i+2; j++) { q.DeQueue(t); q.EnQueue(s + t); s = t; if (j != i+2) cout << s << ' '; } }}
|
优先级队列
每次从队列中取出的是具 有最高优先权的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <assert.h> #include <iostream.h> #include <stdlib.h> template <class E> class PQueue { private: E *pqelements; int count; int maxPQSize; void adjust(); public: PQueue(int sz = 50); ~PQueue() { delete [ ] pqelements; } bool Insert(E x); bool RemoveMin(E& x); bool GetFront(E& x); void MakeEmpty() { count = 0; } bool IsEmpty() const { return count == 0; } bool IsFull() const { return count == maxPQSize; } int Length() const { return count; } };
template <class E> PQueue<E>::PQueue(int sz) { maxPQSize = sz; count = 0; pqelements = new E[maxPQSize]; assert (pqelements != NULL); } template <class E> bool PQueue<E>::Insert(E x) { if (IsFull() == true) return false; pqelements[count++] = x; adjust(); return true; } template <class E> void PQueue<E>::adjust() { E temp = pqelements[count-1]; for (int j = count-2; j >= 0; j--) if (pqelements[j] <= temp) break; else pqelements[j+1] = pqelements[j]; pqelements[j+1] = temp; } template <class E> bool PQueue<E>::RemoveMin(E& x) { if (IsEmpty()) return false; x = pqelements[0]; for (int i = 1; i < count; i++) pqelements[i-1] = pqelements[i]; count--; return true; } template <class E> bool PQueue<E>::GetFront (E& x) { if (IsEmpty() == true) return false; x = pqelements[0]; return true; }
|