栈的应用
后缀表达式
中缀表达式转换成后缀表达式
需要通过栈和线性表来实现,把格式化后的中缀表达式字符串一一取出,字符若为数字直接放入线性表,若为操作符时,并且栈为空则直接放入,栈不为空时,与栈顶运算符的优先级进行比较,若当前运算符优先级小,则入栈,否则将栈顶运算符弹出并放入线性表中,直到栈为空或栈顶运算符优先级小于当前运算符,再将当前运算符入栈,最后输出线性表。
public static String infixToSuffix(String express) {
//操作符栈
ArrayStack<String> opStack = new ArrayStack<>();
//后缀表达式的线性表
ArrayList<String> suffixList = new ArrayList<>();
express = insert(express);
String[] tokens = express.split(" ");
for (String token : tokens) {
if (token.length() == 0) {
continue;
}
//判断操作符
if (isOperator(token)) {
/*
什么时候操作符进栈
栈为空
栈顶为(
栈顶为操作符,且优先级比当前操作符小
什么时候操作符出栈
栈顶操作符的优先级 >= 当前操作符
*/
while (true) {
if (opStack.isEmpty() || opStack.peek().equals("(") || priority(opStack.peek()) < priority(token)) {
opStack.push(token);
break;
}
suffixList.add(opStack.pop());
}
} else if (token.equals("(")) {
opStack.push(token);
} else if (token.equals(")")) {
while (!opStack.peek().equals("(")) {
suffixList.add(opStack.pop());
}
opStack.pop();
} else if (isNumber(token)) {
suffixList.add(token);
} else {
throw new IllegalArgumentException("非法字符");
}
}
while (!opStack.isEmpty()) {
suffixList.add(opStack.pop());
}
//数字和操作符进行拼接
StringBuilder sb = new StringBuilder();
for (int i = 0; i < suffixList.size(); i++) {
sb.append(suffixList.get(i));
sb.append(" ");
}
return sb.toString();
}
private static int priority(String peek) {
if (peek.equals("+") || peek.equals("-")) {
return 0;
}
if (peek.equals("*") || peek.equals("/")) {
return 1;
}
return -1;
}
private static boolean isNumber(String token) {
return token.matches("\\d+");
}
private static boolean isOperator(String token) {
return token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/");
}
后缀表达式计算器
private static int evaluateSuffix(String expression) {
ArrayStack<Integer> stack = new ArrayStack<>();
String[] tokens = expression.split(" ");
for (String token : tokens) {
if (token.length() == 0) {
continue;
}
if (isNumber(token)) {
stack.push(new Integer(token));
} else {
processAnOperator(stack, token);
}
}
return stack.pop();
}
private static boolean isNumber(String token) {
return token.matches("\\d+");
}
private static void processAnOperator(ArrayStack<Integer> stack, String token) {
int num1 = stack.pop();
int num2 = stack.pop();
if (token.equals("+")) {
stack.push(num2 + num1);
} else if (token.equals("-")) {
stack.push(num2 - num1);
} else if (token.equals("*")) {
stack.push(num2 * num1);
} else {
stack.push(num2 / num1);
}
}
进制转换
十进制转十六进制
public class DecToHex {
public static void main(String[] args) {
int num = 654321;
ArrayStack<String> stack = new ArrayStack<>();
while (num != 0) {
int a = num % 16;
if (a < 10) {
stack.push(a + "");
} else {
stack.push((char) (a + 55) + "");
}
num /= 16;
}
StringBuilder sb = new StringBuilder();
while (!stack.isEmpty()) {
sb.append(stack.pop());
}
System.out.println(sb.toString());
}
}
十六进制转十进制
public class HexToDec {
public static void main(String[] args) {
String hex = "9FBF1";
ArrayStack<Character> stack = new ArrayStack<>();
for (int i = 0; i < hex.length(); i++) {
stack.push(hex.charAt(i));
}
int sum = 0;
int m = 0;
while (!stack.isEmpty()) {
char c = stack.pop();
sum += getNumber(c) * Math.pow(16, m);
m++;
}
System.out.println(sum);
}
private static int getNumber(char c) {
if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F')) {
throw new IllegalArgumentException("非法字符");
}
if (c >= '0' && c <= '9') {
return c - '0';
} else {
return c - 'A' + 10;
}
}
}
判断括号是否合法
使用ascII码判断
private static void solition01() {
String str = "{()}[]<>{}";
ArrayStack<Character> stack = new ArrayStack<>();
for(int i = 0; i < str.length(); i++){
char c = str.charAt(i);
if(stack.isEmpty()){
stack.push(c);
}else{
char top = stack.peek();
if(top - c == -2 || top - c == -1){
stack.pop();
}else{
stack.push(c);
}
}
}
System.out.println(stack.isEmpty());
}
使用HashMap判断
private static void solition02() {
String str = "{{()}[]<>}";
HashMap<Character,Character> map = new HashMap<>();
map.put('[',']');
map.put('(',')');
map.put('{','}');
map.put('<','>');
ArrayStack<Character> stack = new ArrayStack<>();
for(int i = 0; i < str.length(); i++){
char c = str.charAt(i);
if(stack.isEmpty()){
stack.push(c);
}else{
char top = stack.peek();
if(map.containsKey(top) && c == map.get(top)){
stack.pop();
}else{
stack.push(c);
}
}
}
System.out.println(stack.isEmpty());
}
回文判断
private static void solition01() {
String str = "上海自来水来自海上";
ArrayStack<Character> stack = new ArrayStack<>();
for(int i = 0;i < str.length(); i++){
if(str.length() % 2 ==1 && i == str.length() / 2){
continue;
}
char c = str.charAt(i);
if(stack.isEmpty()){
stack.push(c);
}else {
if(c != stack.peek()){
stack.push(c);
}else{
stack.pop();
}
}
}
System.out.println(stack.isEmpty());
}
用栈实现队列
class QueueImplByStack<E> implements Queue<E>{
private ArrayStack<E> stack1;
private ArrayStack<E> stack2;
public QueueImplByStack(){
stack1 = new ArrayStack<>();
stack2 = new ArrayStack<>();
}
@Override
public int size() {
return stack1.size();
}
@Override
public void offer(E element) {
stack1.push(element);
}
@Override
public E poll() {
if(isEmpty()){
throw new IllegalArgumentException("栈为空");
}
while(stack1.size() != 1){
stack2.push(stack1.pop());
}
E ret = stack1.pop();
while (!stack2.isEmpty()){
stack1.push(stack2.pop());
}
return ret;
}
@Override
public E peek() {
if(isEmpty()){
throw new IllegalArgumentException("栈为空");
}
while(stack1.size() != 1){
stack2.push(stack1.pop());
}
E ret = stack1.peek();
while (!stack2.isEmpty()){
stack1.push(stack2.pop());
}
return ret;
}
@Override
public boolean isEmpty() {
return stack1.isEmpty();
}
@Override
public void clear() {
stack1.clear();
}
@Override
public Iterator<E> iterator() {
return stack1.iterator();
}
@Override
public String toString() {
return stack1.toString();
}
}
双端栈的实现
双端栈是指将一个线性表的两端当做栈底分别进行入栈和出栈操作
public class ArrayDoubleEndStack<E> implements Iterable<E> {
//左端栈的栈顶
private int ltop;
//右端栈的栈顶
private int rtop;
//存储元素的容器
private E[] data;
//数组容器的默认容量
private static int DEFAULT_CAPACITY = 10;
public ArrayDoubleEndStack() {
data = (E[]) new Object[DEFAULT_CAPACITY];
ltop = -1;
rtop = data.length;
}
public void pushLeft(E element) {
if (ltop + 1 == rtop) {
resize(data.length * 2);
}
data[++ltop] = element;
}
public void pushRight(E element) {
if (ltop + 1 == rtop) {
resize(data.length * 2);
}
data[--rtop] = element;
}
private void resize(int newLen) {
E[] newData = (E[]) new Object[newLen];
//复制左端栈
for (int i = 0; i <= ltop; i++) {
newData[i] = data[i];
}
//复制右端栈
int index = rtop;
for (int i = newLen - sizeRight(); i < newLen; i++) {
newData[i] = data[index++];
}
//rtop += data.length;
rtop = newLen - sizeRight();
data = newData;
}
public E popLeft() {
if (isLeftEmpty()) {
throw new IllegalArgumentException("左栈为空");
}
E ret = data[ltop--];
if (sizeRight() + sizeLeft() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
resize(data.length / 2);
}
return ret;
}
public E popRight() {
if (isRightEmpty()) {
throw new IllegalArgumentException("右栈为空");
}
E ret = data[rtop++];
if (sizeRight() + sizeLeft() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
resize(data.length / 2);
}
return ret;
}
public E peekLeft() {
if (isLeftEmpty()) {
throw new IllegalArgumentException("左栈为空");
}
return data[ltop];
}
public E peekRight() {
if (isRightEmpty()) {
throw new IllegalArgumentException("右栈为空");
}
return data[rtop];
}
public boolean isLeftEmpty() {
return ltop == -1;
}
public boolean isRightEmpty() {
return rtop == data.length;
}
public int sizeLeft() {
return ltop + 1;
}
public int sizeRight() {
return data.length - rtop;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
if (isLeftEmpty() && isRightEmpty()) {
sb.append(']');
return sb.toString();
}
for (int i = 0; i <= ltop; i++) {
sb.append(data[i]);
if (i == ltop && isRightEmpty()) {
sb.append(']');
return sb.toString();
} else {
sb.append(',');
}
}
for (int i = rtop; i < data.length; i++) {
sb.append(data[i]);
if (i == data.length - 1) {
sb.append(']');
} else {
sb.append(',');
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return new DoubleStackIterator();
}
class DoubleStackIterator implements Iterator {
private ArrayList<E> list;
private Iterator<E> it;
public DoubleStackIterator() {
list = new ArrayList();
for (int i = 0; i <= ltop; i++) {
list.add(data[i]);
}
for (int i = rtop; i < data.length; i++) {
list.add(data[i]);
}
it = list.iterator();
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public Object next() {
return it.next();
}
}
}
队列的实现
队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表
- 我们把允许删除的一端称为队首,插入的一端称为队尾
- 不含任何元素的队列称为空队列
- 队列是一种先进先出的线性表
- 队列本身是一个线性表,其数据元素具有线性关系,只不过它是一种特殊的线性表
- 队列的插入操作叫做入队
- 队列的删除操作叫做出队
队列接口的定义
public interface Queue<E> extends Iterable<E>{
public int size();
public void offer(E element);
public E poll();
public E peek();
public boolean isEmpty();
public void clear();
}
队列ArrayQueue的实现
public class ArrayQueue<E> implements Queue<E> {
private ArrayList<E> list;
public ArrayQueue() {
list = new ArrayList<>();
}
@Override
public int size() {
return list.size();
}
@Override
public void offer(E element) {
list.add(list.size(), element);
}
@Override
public E poll() {
return list.remove(0);
}
@Override
public E peek() {
return list.get(0);
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public void clear() {
list.clear();
}
@Override
public Iterator iterator() {
return list.iterator();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (o instanceof ArrayQueue) {
ArrayQueue other = (ArrayQueue) o;
return list.equals(other.list);
}
return false;
}
@Override
public String toString() {
return list.toString();
}
}
队列的应用
文件夹遍历
广度优先遍历
public class DirectoryTraversal {
public static void main(String[] args) {
File dir = new File("文件路径");
fun1(dir);
}
private static void fun1(File dir) {
ArrayQueue<File> queue = new ArrayQueue<>();
System.out.println(dir.getName());
queue.offer(dir);
while (!queue.isEmpty()){
File file = queue.poll();
System.out.println('['+file.getName()+']');
File[] files = file.listFiles();
for(File f : files){
if(f.isFile()){
System.out.println(f.getName());
}else{
queue.offer(f);
}
}
}
}
用队列实现栈
class QueueImplByStack<E> implements Queue<E>{
private ArrayStack<E> stack1;
private ArrayStack<E> stack2;
public QueueImplByStack(){
stack1 = new ArrayStack<>();
stack2 = new ArrayStack<>();
}
@Override
public int size() {
return stack1.size();
}
@Override
public void offer(E element) {
stack1.push(element);
}
@Override
public E poll() {
if(isEmpty()){
throw new IllegalArgumentException("栈为空");
}
while(stack1.size() != 1){
stack2.push(stack1.pop());
}
E ret = stack1.pop();
while (!stack2.isEmpty()){
stack1.push(stack2.pop());
}
return ret;
}
@Override
public E element() {
if(isEmpty()){
throw new IllegalArgumentException("栈为空");
}
while(stack1.size() != 1){
stack2.push(stack1.pop());
}
E ret = stack1.peek();
while (!stack2.isEmpty()){
stack1.push(stack2.pop());
}
return ret;
}
@Override
public boolean isEmpty() {
return stack1.isEmpty();
}
@Override
public void clear() {
stack1.clear();
}
@Override
public Iterator<E> iterator() {
return stack1.iterator();
}
@Override
public String toString() {
return stack1.toString();
}
}
循环队列的实现
- 创建队头指针Front和队尾指针Rear,并让两个指针随着元素的变化而变化
- 当队头指针或 队尾指针达到尾部时,再后移可重新指向表头,进行循环
- 将一个空间预留出来不存任何元素,尾指针始终指向这个null空间
此时队列满的条件为**(Rear+1)%nFront**;队列空的条件为**RearFront**
public class ArrayLoopQueue<E> implements Queue<E> {
//存储数据的容器
private E[] data;
//队首指针
private int front;
//队尾指针
private int rear;
//元素个数(f < r r-f; r < f r+L-f)
private int size;
//默认容量
private static int DEFAULT_CAPACITY = 10;
public ArrayLoopQueue(){
data = (E[]) new Object[DEFAULT_CAPACITY + 1];
front = 0;
rear = 0;
}
@Override
public int size() {
return size;
}
@Override
public void offer(E element) {
if((rear + 1) % data.length == front){
resize(data.length * 2 - 1);
}
data[rear] = element;
rear = (rear + 1) % data.length;
size++;
}
@Override
public E poll() {
//是否为空
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
E ret = data[front];
front = (front + 1) % data.length;
size--;
if(size <= (data.length - 1) / 4 && data.length - 1 > DEFAULT_CAPACITY){
resize(data.length / 2 + 1);
}
return ret;
}
private void resize(int newlen) {
E[] newData = (E[]) new Object[newlen];
int index = 0;
for(int i = 0; i != rear; i = (i + 1) % data.length){
newData[index++] = data[i];
}
data = newData;
front = 0;
rear = index;
}
@Override
public E element() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
return data[front];
}
@Override
public boolean isEmpty() {
return rear == front;
}
@Override
public void clear() {
data = (E[]) new Object[DEFAULT_CAPACITY];
size = 0;
front = 0;
rear = 0;
}
@Override
public Iterator iterator() {
return new ArrayLoopQueueIterator();
}
class ArrayLoopQueueIterator implements Iterator<E>{
private int cur = front;
@Override
public boolean hasNext() {
return cur != rear;
}
@Override
public E next() {
E ret = data[cur];
cur = (cur + 1) % data.length;
return ret;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
if(isEmpty()){
sb.append(']');
return sb.toString();
}
for(int i = front; i != rear; i = (i + 1) % data.length){
sb.append(data[i]);
if((i + 1) % data.length ==rear){
sb.append(']');
}else
sb.append(',');
sb.append(' ');
}
return sb.toString();
}
@Override
public boolean equals(Object o) {
if(o == null) return false;
if(this == o) return true;
if(o instanceof ArrayLoopQueue){
ArrayLoopQueue<E> other = (ArrayLoopQueue<E>) o;
if(size != other.size){
return false;
}
int i = front;
int j = other.front;
while (i != rear){
if(data[i].equals(other.data[j])){
return false;
}
i = (i + 1) % data.length;
j = (j + 1) % other.data.length;
}
return true;
}
return false;
}
}
双端队列
双端队列的定义
双端队列是限定插入和删除操作在表的两端进行的线性表,是一种具有队列和栈的性质的数据结构
双端队列的接口定义
public interface Deque<E> extends Queue<E>{
public void addFirst(E element);
public void addLast(E element);
public E removeFirst();
public E removeLast();
public E getFirst();
public E getLast();
}
双端队列的实现
public class ArrayDeque<E> implements Deque<E>, Stack<E> {
private E[] data;
private int front;
private int rear;
private int size;
private static int DEFAULT_CAPACITY = 10;
public ArrayDeque() {
data = (E[]) new Object[DEFAULT_CAPACITY + 1];
front = 0;
rear = 0;
size = 0;
}
@Override
public void addFirst(E element) {
if((rear + 1) % data.length == front){
resize(data.length * 2 - 1);
}
front = (front - 1 +data.length) % data.length;
data[front] = element;
size++;
}
@Override
public void addLast(E element) {
if((rear + 1) % data.length == front){
resize(data.length * 2 - 1);
}
data[rear] = element;
rear = (rear + 1) % data.length;
size++;
}
private void resize(int newlen) {
E[] newData = (E[]) new Object[newlen];
int index = 0;
for(int i = 0; i != rear; i = (i + 1) % data.length){
newData[index++] = data[i];
}
data = newData;
front = 0;
rear = index;
}
@Override
public E removeFirst() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
E ret = data[front];
front = (front + 1) % data.length;
size--;
if(size <= (data.length - 1) / 4 && data.length - 1 > DEFAULT_CAPACITY){
resize(data.length * 2 - 1);
}
return ret;
}
@Override
public E removeLast() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
rear = (rear - 1 + data.length) % data.length;
E ret = data[rear];
size--;
if(size <= (data.length - 1) / 4 && data.length - 1 > DEFAULT_CAPACITY){
resize(data.length * 2 - 1);
}
return ret;
}
@Override
public E getFirst() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
return data[front];
}
@Override
public E getLast() {
if(isEmpty()){
throw new IllegalArgumentException("队列为空");
}
return data[(rear - 1 + data.length) % data.length];
}
@Override
public int size() {
return size;
}
@Override
public void offer(E element) {
addLast(element);
}
@Override
public E poll() {
return removeFirst();
}
@Override
public E element() {
return getFirst();
}
@Override
public E peek() {
return getLast();
}
@Override
public boolean isEmpty() {
return size == 0 && front == rear;
}
@Override
public void push(E element) {
addLast(element);
}
@Override
public E pop() {
return removeLast();
}
@Override
public void clear() {
E[] data = (E[]) new Object[DEFAULT_CAPACITY + 1];
front = 0;
rear = 0;
size = 0;
}
@Override
public Iterator<E> iterator() {
return new ArrayDequeIterator();
}
class ArrayDequeIterator implements Iterator<E>{
private int cur = front;
@Override
public boolean hasNext() {
return cur != rear;
}
@Override
public E next() {
E ret = data[cur];
cur = (cur + 1) % data.length;
return ret;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
if(isEmpty()){
sb.append(']');
return sb.toString();
}
for(int i = front; i != rear; i = (i + 1) % data.length){
sb.append(data[i]);
if((i + 1) % data.length ==rear){
sb.append(']');
}else
sb.append(',');
sb.append(' ');
}
return sb.toString();
}
}