线性表是具有相同特性数据元素的一个有限序列,
该序列中所含元素的个数叫做线性表的长度。
栈是一种只能在一端进行插入或删除的 操作受限的 线性表 。
自己实现
import java.util.EmptyStackException;
public class MyStack<E> {
private static final int DEFAULT_CAPACITY = 10;
private static final int MAX_CAPACITY = Integer.MAX_VALUE-8;
//属性
private E[] list;
private int top = -1;
//构造方法
public MyStack(){
list = (E[])new Object[DEFAULT_CAPACITY];
}
public MyStack(int initialCapacity){
checkCapacity(initialCapacity);
list = (E[])new Object[initialCapacity];
}
private void checkCapacity(int initialCapacity) {
if(initialCapacity <0 || initialCapacity> MAX_CAPACITY){
throw new IllegalArgumentException("initialCapacity = "+ initialCapacity );
}
}
//方法
public void push(E e){
if(top==list.length-1){
//如果需要扩容
int newLength = calculateCapacity();
grow(newLength);
}
list[++top] =e;
}
//计算容量
private int calculateCapacity(){
if(list.length ==MAX_CAPACITY) throw new RuntimeException("too long");
int newLength = list.length+(list.length>>1);
if(newLength<0 ||newLength>MAX_CAPACITY){
newLength = MAX_CAPACITY;
}
return newLength;
}
private void grow(int newLength){
E[] tempList = (E[])new Object[newLength];
for (int i = 0; i <top ; i++) {
tempList[i] = list[i];
}
list = tempList;
}
public E pop(){
if(isEmpty()) throw new EmptyStackException();
E e = list[top];
list[top--] =null;
return e;
}
public boolean isEmpty(){
return top == -1;
}
public E peek(){
if(isEmpty()) throw new EmptyStackException();
return (E)list[top];
}
}
public class MyStack<E> {
//属性
private Node top;
//Node
private static class Node{
Object data;
Node next;
public Node(Object data){
this.data = data;
}
public Node(Object data, Node next){
this.data =data;
this.next = next;
}
}
public void push(E e){
top = new Node(e, top);
}
public E pop(){
if(isEmpty()) {
throw new EmptyStackException();
}
E topData = (E)top.data;
top = top.next;
return topData;
}
public E peek(){
if(isEmpty()){
throw new EmptyStackException();
}
return (E)top.data;
}
public boolean isEmpty(){
return top ==null;
}
}
思路:遍历字符串,将一个个字符压入栈中
再一个个出栈,并且拼接成字符串
public class MyStackDemo1 {
public static void main(String[] args) {
String s = "ABC";
s = reverse(s);
System.out.println(s);
}
public static String reverse(String original){
MyStack<Character> stack = new MyStack();
for (int i = 0; i <original.length() ; i++) {
stack.push(original.charAt(i));
}
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty()){
sb.append(stack.pop());
}
return sb.toString();
}
}
/*
括号匹配问题
思路: 遍历字符串
遇到左括号,直接将对应的右括号入栈
遇到右括号,判断此时栈是否为空,
是: 返回false
否:出栈一个元素与右括号进行比较
相同:继续遍历
不相同 返回false
遍历完字符串,判断栈是否为空
是:true
否:false
*/
public class MyStackDemo2 {
public static void main(String[] args) {
String s = "public static void main(String[] args)"; // 待检查字符串
System.out.println(judge(s));
}
public static boolean judge (String s ){
MyStack stack = new MyStack();
for (int i = 0; i< s.length(); i++){
//如果是左括号,入栈
char c = s.charAt(i);
if(c == '(') stack.push(')');
if(c == '[') stack.push(']');
if(c == '{') stack.push('}');
if(c==')' || c ==']' || c =='}' ){
if(stack.isEmpty()) {
return false;
}
if((char)stack.pop() != c) return false;
}
}
return stack.isEmpty();
}
}
中缀表达式求值
可以先转成后缀表达式,再对后缀表达式求值;也可以同时进行
public class MyStackDemo3 {
public static void main(String[] args) {
String exp = "12+4-3*4+5-23+1";
System.out.println(calculate(exp));
}
public static int calculate(String exp){
// 利用两个栈 分别存储操作数 和 操作符
MyStack<Integer> stackNum = new MyStack();
MyStack<Character> stackOp = new MyStack();
int result; //num1、num2存储操作数,result存储计算结果
int n =0; //保存每个数字
for (int i = 0; i < exp.length() ; i++) {
char c = exp.charAt(i);
//如果c是操作数
if(Character.isDigit(c)) { // Character.isDigit(chr ch) 判断是否是数字
n = n * 10 + Integer.parseInt(String.valueOf(c)); //将 单个数字字符保存
} else {
if (n != 0) {
stackNum.push(n);
n = 0;
}
//如果遇到操作符 当操作符栈非空时,
while (!stackOp.isEmpty()) {
//如果非空,与操作符栈顶元素进行比较
if (getPriority(c)>getPriority(stackOp.peek())) { //如果优先级大于栈顶元素,则将其入操作符栈
stackOp.push(c);
break; //退出循环
} else {
//如果优先级小于或等于栈顶元素,则出栈,进行计算
result = com(stackNum.pop(), stackOp.pop(), stackNum.pop());
//将计算结果压入操作数栈中
stackNum.push(result);
}
}
//如果操作符栈为空,直接入栈
if (stackOp.isEmpty()) stackOp.push(c);
}
}
//如果最后一个字符是数字,未入栈
if(n!=0) stackNum.push(n);
//for循环结束,说明表达式遍历完毕,
// 但是此时StackNUm和StackOp中可能还有剩余元素,需要继续计算完
return remainderCom(stackNum,stackOp);
}
//计算栈中剩余的操作数
private static int remainderCom(MyStack<Integer> stackNum, MyStack<Character> stackOp) {
while(!stackOp.isEmpty()){
stackNum.push(com(stackNum.pop(),stackOp.pop(),stackNum.pop()));
}
//将栈顶元素返回 ,为最终结果
return stackNum.pop();
}
//根据优先级判断能否出栈计算
private static int getPriority(char c) {
if(c=='+' || c=='-')
return 0;
else
return 1;
}
//注意运算次序,num2先出栈,num1后出栈
private static int com(int num2, char op, int num1) {
System.out.println(num1+" " + op +" "+ num2);
if(op=='+') return num1+num2;
if(op=='-') return num1-num2;
if(op=='*') return num1*num2;
if(op=='/') {
if (num2==0){
throw new ArithmeticException();
}else {
return num1/num2;
}
}
return Integer.MIN_VALUE;
}
}
leet-code 用栈实现队列
/*
思路:
push: 添加元素都是在s1中添加,并且用front标识队头元素。
pop: 出队列是从s2中出队列,如果s2是空的,就将s1中的元素倒入s2中。
peek: 如果s2是空的,就返回s1中标识的front, 否则返回s2的栈顶元素
empty: 两个栈都为空, 队列才为空
*/
public class MyQueue<E> {
Deque<E> s1 = new LinkedList<>();
Deque<E> s2 = new LinkedList<>();
E front;
public void push(E e) {
if(s1.isEmpty()) {
front = e;
}
s1.push(e);
}
public E pop() {
if(s2.isEmpty()) {
while(!s1.isEmpty()) {
s2.push(s1.pop());
}
}
return s2.pop();
}
public E peek() {
if(s2.isEmpty()) {
return front;
}
return s2.peek();
}
public boolean empty() {
return s1.isEmpty() && s2.isEmpty();
}
}