《算法导论》笔记 第10章 10.1 栈和队列
【笔记】
栈:后进先出 LIFO
队列:先进先出 FIFO
template<typename ITEM> class stack { private: ITEM S[MAXN]; int tp; public: stack() { tp = 0; } bool empty() { return tp == 0; } void push(ITEM x) { if (tp == MAXN) throw "stack overflow"; S[tp++] = x; } ITEM top() { if (tp == 0) throw "stack empty"; return S[tp-1]; } void pop() { if (tp == 0) throw "stack underflow"; tp--; } int size() { return tp; } }; template<typename ITEM> class queue { private: ITEM Q[MAXN]; int head,tail; int sz; public: queue() { head = tail = sz = 0; } bool empty() { return sz == 0; } void push(ITEM x) { if (sz == MAXN) throw "queue overflow"; Q[tail++] = x; sz++; if (tail == MAXN) tail = 0; } ITEM front() { if (sz == 0) throw "queue empty"; return Q[head]; } void pop() { if (sz == 0) throw "queue underflow"; head++; sz--; if (head == MAXN) head = 0; } int size() { return sz; } };
【练习】
10.1-1 说明对一个储存在数组S[1..6]中的、初始为空的栈S,依次执行PUSH(S,4),PUSH(S,1),PUSH(S,3),POP(S),PUSH(S,8)以及POP(S)操作后的结果。
4 1 3
4 1
4 1 8
POP返回3
10.1-2 说明如何用一个数组A[1..n]来实现两个栈,使得两个栈中的元素总数不到n时,两者都不会发生上溢。注意PUSH和POP操作的时间应为O(1)。
两个栈分别用A[1]和A[n]做栈底,PUSH操作时,向中间插入元素,当两个栈元素总数为n时数组满,发生上溢。
10.1-3 说明对一个存储在数组Q[1..6]中的、初始为空的队列Q,依次执行ENQUEUE(Q,4),ENQUEUE(Q,1),ENQUEUE(Q,3),DEQUEUE(Q),ENQUEUE(Q,8)以及DEQUEUE(Q)操作后的结果。
4
4 1
4 1 3
1 3
1 3 8
DEQUEUE(Q)返回4
10.1-4 重写ENQUEUE和DEQUEUE,使之能处理队列的下溢和上溢。
见代码。
10.1-5 栈的插入和删除操作都是在一端进行的,而队列的插入和删除确是在两头进行的。另有一种双端队列,其两端都可以做插入和删除操作。对于一个用数组构造的双端队列,请写出四个在两端进行插入和删除操作的过程,要求运行时间都为O(1)。
template <typename ITEM> class deque { private: ITEM D[MAXN]; int head,tail; int sz; public: deque() { head = tail = 0; sz = 0; } bool empty() { return sz == 0; } ITEM front() { if (sz == 0) throw "deque empty"; return D[head]; } ITEM back() { if (sz == 0) throw "deque empty"; return D[tail-1]; } void push_front(ITEM x) { if (sz == MAXN) throw "deque overflow"; if (head == 0) head = MAXN; head--; sz++; D[head] = x; } void push_back(ITEM x) { if (sz == MAXN) throw "deque overflow"; D[tail++] = x; sz++; if (tail == MAXN) tail = 0; } void pop_front() { if (sz == 0) throw "deque underflow"; head++; if (head == MAXN) head = 0; sz--; } void pop_back() { if (sz == 0) throw "deque underflow"; if (tail == 0) tail = MAXN; tail--; sz--; } int size() { return sz; } };
10.1-6 说明如何用两个栈来实现一个队列,并分析有关队列操作的运行时间。
template <typename ITEM> class queuebytwostack{ private: stack<ITEM> stkin; stack<ITEM> stkout; void readyToPop() { while (!stkin.empty()) { stkout.push(stkin.top()); stkin.pop(); } } public: bool empty() { if (stkin.empty()&&stkout.empty()) return true; return false; } void push(ITEM x){ try { stkin.push(x); } catch (const char *e) { throw e; } } ITEM front() { try { if (stkout.empty()) readyToPop(); return stkout.top(); } catch (const char *e) { throw e; } } void pop() { try { if (stkout.empty()) readyToPop(); stkout.pop(); } catch (const char *e) { throw e; } } int size() { return stkin.size()+stkout.size(); } };PUSH O(1)
POP O(n)
10.1-7 说明如何用两个队列来实现一个栈,并分析有关栈操作的运行时间。
template <typename ITEM> class stackbytwoqueue { private: queue<ITEM> que[2]; int p; public: stackbytwoqueue() { p = 0; } bool empty() { if (que[0].empty()&&que[1].empty()) return true; return false; } void push(ITEM x) { try { que[p].push(x); } catch (const char *e) { throw e; } } ITEM top() { try { int sz = que[p].size(); ITEM res; for (int i=1;i<=sz;i++) { if (i==sz) res = que[p].front(); que[p^1].push(que[p].front()); que[p].pop(); } p^=1; return res; } catch (const char *e) { throw e; } } void pop() { try { int sz = que[p].size(); for (int i=1;i<=sz-1;i++) { que[p^1].push(que[p].front()); que[p].pop(); } que[p].pop(); p^=1; } catch (const char *e) { throw e; } } int size() { return que[p].size()+que[p^1].size(); } };PUSH O(1)
POP O(n)