“栈”与“队列”呢点事(二)

230 阅读3分钟
攻无不克,“栈”无不胜。
知彼知己,百“栈”不殆。

本文分享了一下栈的实现原理,以及一个简单的应用场景-简易计算器。

所有源码均已上传至github:链接

基于数组实现的顺序栈 

1.首先需要初始化数组,申请一个大小为capacity的内存空间

	public ArrayStack(int capacity) {
		arrays = new int[capacity];
		size = capacity;
		count = 0;
	}

2.入栈

	public boolean push(int num) {
		// 这里当数组空间不够时,入栈失败,暂不扩容
		if (count == size)
			return false;
		arrays[count] = num;
		++count;
		return true;
	}

3.出栈

	public int pop() {
		// 栈空
		if (count == 0)
			return -1;//-1表示没有数据
		int res = arrays[count - 1];
		--count;
		return res;
	}

4.测试结果

ps:按数字大小顺序压栈



基于链表实现链式栈

链式栈则不需要像数组呢样在重载的构造方法初始化,直接声明即可

1.入栈

	public void push(int num) {
		Node node = new Node(num, null);
		if (head != null) {
			// 倒序插入,为出栈做准备
			node.next = head;
		}
		head = node;
	}

2.出栈

	public int pop() {
		if (head == null)
			return -1;// -1表示栈空
		int res = head.data;
		head = head.next;
		return res;
	}

3.测试结果(与顺序栈保持一致)



应用场景之简易计算器

分析

本次基于栈的简易计算器仅包含加减乘除等四则元素,比如计算 7-1+2*3+12/2。对于这个运算来讲 ,只是就是一个表达式求值的过程,对人来讲,口算都能算出来,可是对计算机来讲,这个表达式很难理解,具体应该怎么实现呢?

规则:这里和常规数学运算符一样,先乘除后加减,不包含括号,输入值为正整数。

具体实现如下

1.我们可以把该运算通过声明两个栈来实现。一个栈valStack用来保存值,一个栈calStack用来保存运算符。

process中的for循环从左往右依次遍历,当遇到数字的时候入栈valStack,遇到运算符的时候,先别忙入栈calStack,要先与栈B的栈顶元素进行比较,如果比栈顶元素优先级高,则入栈calStack,如果优先级低或者相同,则从栈valStack里取两个值,然后进行计算,再压入栈valStack。

当for循环执行完毕的时候,valStack栈的值的数量应该是比calStack的值得数量多一。

在while循环里将剩余的操作做完,直到一方为空。

最后清空栈即可。

	public void process(String str) {
//		这里不做非空检验,默认传入的值一定正确有效
		String[] strs = str.split(" ");
		for (int i = 0; i < strs.length; i++) {
			if (isNumber(strs[i])) {// 数字
				valStack.push(Integer.valueOf(strs[i]));
			} else {// 运算符
				calDeal(strs[i]);
			}
			print();
		}
		while (!valStack.isEmpty() && !calStack.isEmpty()) {
			String cal = calStack.pop();
			Integer fInteger = valStack.pop();
			Integer sInteger = valStack.pop();
			result = calulate(cal, sInteger, fInteger);
			valStack.push(result);
			print();
		}
		valStack.clear();
		calStack.clear();
	}

2.该方法就是当遇到操作符时开始判断是入栈还是计算

	private void calDeal(String opt) {
		//出栈
		String calStar;
		if (!calStack.isEmpty()) {
			while (!calStack.isEmpty()) {
				calStar = calStack.pop();
				if (!compareOperator(opt, calStar)) {
					Integer p = valStack.pop();
					Integer q = valStack.pop();
					result = calulate(calStar, q, p);
					valStack.push(result);
				}else {
					calStack.push(calStar);
					calStack.push(opt);
					break;
				}
			}
		}
		if (calStack.isEmpty()) {
			calStack.push(opt);
		}
	}

3.计算方法

	private Integer calulate(String opt, Integer p, Integer q) {
		switch (opt) {
		case "+":
			return p + q;
		case "-":
			return p - q;
		case "*":
			return p * q;
		case "/":
			return p / q;
		default:
			break;
		}
		return null;
	}

4.比较操作符的优先级

	private boolean compareOperator(String curCal, String tarCal) {
		switch (tarCal) {
		case "+":
		case "-":
			if ("-".equals(curCal) || "+".equals(curCal)) {
				return false;
			}
			return true;
		case "*":
		case "/":
			return false;
		default:
			break;
		}
		return true;
	}

测试结果

ps:该测试结果同时也将两个栈的变化打印出来,一目了然


扩展

下一篇则关于队列的具体实现和解析。

end

您的点赞和关注是对我最大的支持,谢谢!