数据结构-栈(三)
一、栈的定义
- 栈(stack)是一种只能在同一端进行插入或删除操作的线性表。
- 表中允许进行插入、删除操作的一端称为栈顶(top),表的另一端称为栈底(bottom)。
- 栈的插入操作通常称为进栈或入栈(push),栈的删除操作通常称为退栈或出栈(pop)。
栈的特点:
- 后进先出,即后进栈的元素先出栈。 - 每次进栈的元素都作为新栈顶元素,每次出栈的元素只能是当前栈顶元素。 - 栈也称为后进先出表。
二、顺序栈
顺序栈基本算法实现
public class Stack_arr<E> {
/**
* 顺序栈的初始容量(常量)
*/
final int initcapacity = 10;
/**
* 存放顺序栈的容量
*/
private int capacity;
/**
* 存放顺序栈中元素
*/
private E[] data;
/**
* 存放栈顶指针
*/
private int top;
public Stack_arr() {
data = (E[]) new Object[initcapacity];
capacity = initcapacity;
top = -1;
}
/**
* 改变栈容量
*
* @param newcapacity
*/
private void updatecapacity(int newcapacity) {
E[] newdata = (E[]) new Object[newcapacity];
for (int i = 0; i < top; i++)
newdata[i] = data[i];
capacity = newcapacity;
data = newdata;
}
//栈的基本运算算法
/**
* 进栈
*
* @param e
*/
public void push(E e) {
top++;
if (top == capacity) {
updatecapacity(top + top / 2);
}
this.data[top] = e;
}
/**
* 出栈,返回栈顶元素
*/
public E pop() {
if (top == -1) {
return null;
} else {
E e = this.data[top];
top--;
return e;
}
}
/**
* 查看栈顶元素,返回当前的栈顶元素
*/
public E peek() {
if (top == -1) {
return null;
} else {
return this.data[top];
}
}
/**
* 判断栈是否为空,若空栈返回真;否则返回假
*/
public boolean empty() {
return top == -1;
}
}
三、链栈
链栈基本算法实现
public class Stack_link<E>{
private static class Node<E>{
E item;
Node<E> next;
public Node(E item, Node<E> next) {
this.item = item;
this.next = next;
}
}
/**
* 存放栈顶指针
*/
private Node<E> head;
public Stack_link() {
this.head = new Node<>(null,null);
}
//栈的基本运算算法
/**
* 进栈
*
* @param e
*/
public void push(E e) {
Node<E> pNode = new Node<>(e,head.next);
head.next = pNode;
}
/**
* 出栈,返回栈顶元素
*/
public E pop() {
if(this.empty()){
return null;
}
E e = head.next.item;
head.next = head.next.next;
return e;
}
/**
* 查看栈顶元素,返回当前的栈顶元素
*/
public E peek() {
if(this.empty()){
return null;
}
return head.next.item;
}
/**
* 判断栈是否为空,若空栈返回真;否则返回假
*/
public boolean empty() {
return head.next == null;
}
}
四、栈的常见应用
1、括号匹配
设计一个算法利用顺序栈检查用户输入的表达式中括号是否配对(假设表达式中可能含有圆括号、中括号和大括号)。并用相关数据进行测试。
import java.util.Stack;
public class TestStack {
public static void main(String[] args) {
String str = "({)}";
String str1 = "{[()]}";
String str2 = "[]{}()";
System.out.println(str+"配对:"+isMatch(str));
System.out.println(str1+"配对:"+isMatch(str1));
System.out.println(str2+"配对:"+isMatch(str2));
}
public static boolean isMatch(String string) {
Stack<Character> stack = new Stack<>();
int i = 0;
while(i<string.length()) {
char ch = string.charAt(i);
if(ch == '{' || ch == '(' ||ch == '[' ) {
stack.push(ch);
}else if (ch == ')') {
if(stack.peek() == '(' ) {
stack.pop();
}
}else if (ch == '}') {
if(stack.peek() == '{' ) {
stack.pop();
}
}else if (ch == ']') {
if(stack.peek() == '[' ) {
stack.pop();
}
}
i++;
}
return stack.empty();
}
}
2、逆波兰表达式
逆波兰表达式
ps:逆波兰表达式是一种利用栈来进行运算的数学表达式
\[9+(3-1) \ast 3+10 \div 2 \\标准四则运算表达式—中缀表达式\\ 9\,\,3\,\,1-3*+ 10\,\,2/+ \\ 算机采用的—后缀表达式:逆波兰表达式 \]
中缀表达式---> 后缀表达式
import java.util.Stack;
public class TestStack {
public static void main(String[] args) {
String exp = "9+(3-1)*3+10/2";
String convert = convert(exp);
System.out.println(convert);
}
/**
* 将中缀表达式转换为后缀表达式
* @param str
* @return
*/
public static String convert(String str) {
Stack<Character> stack = new Stack<>();
StringBuffer sb = new StringBuffer();
char ch;
char e;
int i = 0;
while (i < str.length()) {
ch = str.charAt(i);
if (ch == '(') {
stack.push(ch);
} else if (ch == ')') {
while (!stack.empty() && stack.peek() != '(') {
//所有运算符出栈
e = stack.pop();
sb.append(e);
}
stack.pop();//(出栈
} else if (ch == '+' || ch == '-') {
while (!stack.empty() && stack.peek() != '(') {
e = stack.pop();
sb.append(e);
}
stack.push(ch);
} else if (ch == '*' || ch == '/') {
while (!stack.empty() && stack.peek() != '('
&& (stack.peek() == '*' || stack.peek() == '/')) {
e = stack.pop();
sb.append(e);
}
stack.push(ch);
} else {
while (ch>='0'&&ch<='9'){
sb.append(ch);
i++;
if(i<str.length()){
ch = str.charAt(i);
}else{
break;
}
}
i--;
sb.append("#");
}
i++;
}
while (!stack.empty()) {
e = stack.pop();
sb.append(e);
}
return sb.toString();
}
}
后缀表达式计算
import java.util.Stack;
public class TestStack {
public static void main(String[] args) {
String exp = "9+(3-1)*3+10/2";
String convert = convert(exp);
System.out.println("后缀表达式:"+convert);
Double calculate = calculate(convert);
System.out.println("计算值:"+calculate);
}
/**
* 后缀表达式计算
* @param suffixExp
* @return
*/
public static Double calculate(String suffixExp){
Stack<Double> stack = new Stack<>();
//操作数1
Double a;
//操作数2
Double b;
//运算结果
StringBuffer sb;
int i = 0;
while (i<suffixExp.length()){
char ch = suffixExp.charAt(i);
if(ch>='0'&&ch<='9'){
sb = new StringBuffer();
while (ch>='0'&&ch<='9'){
sb.append(ch);
i++;
ch=suffixExp.charAt(i);
}
// System.out.println(sb);
double v = Double.parseDouble(sb.toString());
sb = null;
stack.push(v);
}else if(ch=='+'){
b = stack.pop();
a = stack.pop();
stack.push(a+b);
}else if(ch=='-'){
b = stack.pop();
a = stack.pop();
stack.push(a-b);
}else if(ch == '*'){
b = stack.pop();
a = stack.pop();
stack.push(a*b);
}else if(ch=='/'){
b = stack.pop();
a = stack.pop();
stack.push(a/b);
}
i++;
}
return stack.peek();
}
}