数据结构02-栈与队列
一、栈
栈是限定仅在表尾进行插入和删除操作的线性表。允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出的线性表。
栈的应用:逆波兰表达式。
1.栈的实现
栈有两种实现方式:数组和链表。
使用数组实现比较复杂,需要限定大小,会出现栈溢出的问题。android源码的Stack就是用数组实现的。
使用链表实现比较简单,不会限定大小,内存占用较高。
这两种方式的增删改查效率接近。
2.栈的链式实现
栈顶添加元素:
public void add(E e) {
LinkedTable.Node<E> node = new LinkedTable.Node<E>(e, first);
first = node;
size++;
}
栈顶删除元素:
public E pop() {
if (first == null) {
return null;
}
E e = first.item;
first = first.next;
size--;
return e;
}
二、逆波兰表达式
1.定义
逆波兰表达式又叫做后缀表达式。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法,按此方法,每一运算符都置于其运算对象之后,故称为后缀表示。
2.用途
逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)(c+d)转换为ab+cd+。
3.实现
将中缀表达式转化为后缀表达式,需要通过栈实现,将字符入栈时需要遵循以下规则:
- 如果是数字,直接取出
- 如果栈顶为空,直接入栈
- 如果是加减乘除,则与栈顶比较,优先级高于栈顶,直接入栈;优先级低于栈顶,先把栈顶出栈,然后与新的栈顶比较;直到优先级高于栈顶,然后入栈;
- 如果是'(‘,直接入栈;
- 如果是’)’,则与栈顶比较,优先级高于栈顶,直接入栈;优先级低于栈顶,先把栈顶出栈,然后与新的栈顶比较;直到栈顶为'(‘,把'(‘出栈;
/**
* @param expStr 中缀表达式
* @return 后缀表达式
*/
public static String getSuffixExpression(String expStr) {
//添加结束符号')'
char[] expChars = (expStr + Type.RSP.name).toCharArray();
Stack<Character> stack = new Stack<Character>();
StringBuffer stringBuffer = new StringBuffer();
for (char c : expChars) {
//如果是运算符
if (Type.isSymbol(c)) {
Character top = stack.get();
if (top == null) {
stack.add(c);
} else if (c == Type.LSP.name) {
stack.add(c);
//如果优先级低于栈顶
} else if (Type.compareTo(top, c) >= 0) {
while (Type.compareTo(top, c) >= 0) {
//添加分隔符
stringBuffer.append(star);
//取出栈顶元素
stringBuffer.append(stack.pop());
top = stack.get();
if (top == null) {
break;
}
//如果插入的时')',则遇到'('就一起出栈
if (top.charValue() == Type.LSP.name && c == Type.RSP.name) {
stack.pop();
break;
}
}
if (c != Type.RSP.name) {
stack.add(c);
}
} else {
stack.add(c);
}
//添加分隔符
if (c != Type.LSP.name && c != Type.RSP.name) {
stringBuffer.append(star);
}
} else {
stringBuffer.append(c);
}
}
return stringBuffer.toString();
}
通过工具类判断运算符的优先级:
/**
* 运算符号
*/
public static enum Type {
ADD('+', 1), MIN('-', 1), MUL('*', 2), DIV('/', 2), LSP('(', 0), RSP(')', 0);
//运算符名称
public char name;
//运算符优先级
public int index;
Type(char name, int index) {
this.name = name;
this.index = index;
}
/**
* 获取运算符号的优先级
*
* @param c
* @return
*/
public static int getID(char c) {
for (Type type : values()) {
if (type.name == c) {
return type.index;
}
}
return -1;
}
/**
* 判断是不是运算符号
*
* @param c 字符
* @return
*/
public static boolean isSymbol(char c) {
for (Type type : values()) {
if (type.name == c) {
return true;
}
}
return false;
}
/**
* 比较优先级
*
* @param a
* @param b
* @return
*/
public static int compareTo(char a, char b) {
return getID(a) - getID(b);
}
}
4.计算
将后缀表达式计算出结果时,也需要用到栈:
/**
* @param expStr 后缀表达式
* @return 计算结果
*/
public static long countSuffixExpression(String expStr) {
long result = 0;
if (Tool.isEmpty(expStr)) {
return result;
}
String[] array = expStr.split(Character.toString(star));
Stack<String> stack = new Stack<String>();
for (String s : array) {
char c = s.charAt(0);
//如果是运算符就计算
if (Type.isSymbol(c)) {
String a = stack.pop();
String b = stack.pop();
if (!Tool.isEmpty(a) && !Tool.isEmpty(b)) {
//先取出来的数放到运算符后面
BigDecimal bigA = new BigDecimal(b);
BigDecimal bigB = new BigDecimal(a);
BigDecimal bigC = null;
//做加法运算
if (c == Type.ADD.name) {
bigC = bigA.add(bigB);
//做减法运算
} else if (c == Type.MIN.name) {
bigC = bigA.subtract(bigB);
//做乘法运算
} else if (c == Type.MUL.name) {
bigC = bigA.multiply(bigB);
//做除法运算
} else if (c == Type.DIV.name) {
bigC = bigA.divide(bigB, 0, BigDecimal.ROUND_UP);
}
//运算结果入栈
stack.add(bigC.toString());
}
//如果是字符串,就入栈
} else {
stack.add(s);
}
}
result = new BigDecimal(stack.get()).longValue();
return result;
}
三、队列
队列是只允许在一端进行插入操作、而在另一端进行删除操作的线性表。插入的一端称为队尾,删除的一端称为队头。
1.实现
队列也有两种实现:数组和链表。
数组实现:出队复杂度高0(n);容易假溢出。
链表实现:实现简单,内存较高。
注:假溢出是指队列的头部还有空位,尾部已经满了,不再再往尾部插入元素,造成溢出的假象。
2.常见的队列
循环队列
头尾相接的顺序存储结构的队列。解决了假溢出的问题。
双端队列(Deque)
一种具有栈和队列性质的数据结构。双端队列中的元素限定从表的两端插入和删除。
应用:LinkedList/ArrayDeque/ LinkedBlockingDeque(阻塞的双向队列)
优先级队列
优先级队列和通常的栈和队列一样,只不过里面的每一个元素都有一个”优先级”,在处理的时候,首先处理优先级最高的。如果两个元素具有相同的优先级,则按照他们插入到队列中的先后顺序处理。
应用:MessageQueue
最后
数据结构与算法专题:https://www.jianshu.com/nb/25128590
喜欢请点赞,谢谢!