3 min read

只允许在末端进行插入和删除的线性表。栈的实现有顺序栈和链式栈两种。下面只讨论链式栈。

#类定义

链式栈的栈顶在链表的表头。

#include <iostream.h>
#include "LinkedList.h"
#include "stack.h"
template <class T>
class LinkedStack: public Stack<T> {
	public:
		LinkedStack(): top(NULL) {}
		~LinkedStack() {
			makeEmpty();
		};
		void Push(const T& x);
		bool Pop(T& x);
		bool getTop(T& x) const;
		bool IsEmpty() const {
			return (top == NULL) ? true : false;
		}
		int getSize() const;
		void makeEmpty();
		friend ostream& operator << (ostream& os, SeqStack<T>& s);
		
	private:
		LinkNode<T> *top;
};

template <class T>
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 LinkNode<T>(x, top);
	assert(top != NULL);
};

template <class T>
void 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>
int LinkedStack<T>::getSize() const {
	LinkNode<T> *p = top;
	int k = 0;
	while (top != NULL) {
		top = top->link;
		k++;
	}
	return k;
};

template <class T>
ostream& operator << (ostream& os, LinkedStack<T>& s) {
	os << "栈中元素个数为" << s.getSize() << endl;
	LinkNode<T> *p = S.top;
	int i = 0;
	while (p != NULL) {
		os << ++i << ":" << p->data << endl;
	}
	return os;
};

#应用

##括号匹配

#include <iostream.h>
#include <string.h>
#include <stdio.h>
#include "stack.h"
const int maxLength = 100;
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 << "没有与第" << i << "个左括号匹配的右括号" << endl;
	}
}

##表达式计算

用后缀表示计算表达式的值只用一个栈,而前缀表示和中缀表示同时需要两个栈,所以编译程序一般使用后缀表示求解表达式的值。

###后缀表示计算表达式的值

#include <math.h>
#include <stack.h>
#include <iostream.h>
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);
		void DoOperator(char op);
};

void Calculator::DoOperator(char op) {
	double left, right, value;
	int result;
	result = Get2Operands(left, right);
	if (result == true) {
		switch (op) {
			case '+':
				value = left + right;
				s.Push(value);
				break;
			case '-':
				value = left - right;
				s.Push(value);
				break;
			case '*':
				value = left * right;
				s.Push(value);
				break;
			case '/':
				if (right == 0.0) {
					cerr << "Divide by 0" << endl;
					Clear();
				} else {
					value = left / right;
					s.Push(value);
				}
				break;
		}
	} else {
		Clear();
	}
};

bool Calculator::Get2Operands(double& left, double& right) {
	if (s.IsEmpty() == true) {
		cerr << "缺少右操作数" << endl;
		return false;
	}
	s.Pop(right);
	if (s.IsEmpty() == true) {
		cerr << "缺少左操作数" << endl;
		return false;
	}
	s.Pop(left);
	return true;
};

void Calculator::AddOperand(double value) {
	s.Push(value);
};

void Calculator::Run() {
	char ch;
	double newOperand;
	while (cin >> ch, ch != '#') {
		switch (ch) {
			case '+':
			case '-':
			case '*':
			case '/':
				DoOperator(ch);
				break;
			default:
				cin.putback(ch);
				AddOperand(newOperand);
		}
	}
};

void Calculator::Clear() {
	s.makeEmpty();
}

###中缀表示转换为后缀表示

各操作符的优先级如下表所示:

| 操作符ch | # | ( | *, /, % | +, - | ) | | isp | 0 | 1 | 5 | 3 | 6 | | icp | 0 | 6 | 4 | 2 | 1 |

isp叫做栈内优先数(in stack priority),icp叫做栈外优先数(in coming priority)。左括号的icp最高,但当它进入栈后,其isp变得极低,以便括号内的其它操作符进栈。其它操作符进栈后优先数都升1,这是为了相同优先级的操作符能自左向右计算。

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);
				}
			}
		}
	}
};

该算法对输入表达式只进行一次自左向右的扫描,对每个操作数只执行一次输出,对每个操作符,进栈和退栈各一次。