栈实现后缀表达式
只需要用一个栈就可以实现(后缀表达式没有括号存在),用来存放数字,但凡遇到操作符就进行计算,如下图:
首先把数字放入栈中,遇到操作符就进行计算,先放入数字10,20,2,然后遇到了“/”所以拿出来数字2和20,进行运算,然后将运算结果再次压入栈中,以此类推,遍历表达式,得到最终结果为28。
栈实现后缀表达式代码
package p2.线性结构;
public class SuffixCalculator {
public static void main(String[] args) {
String infixExpression = "(10+20/2*3)/2+8";
String suffixExpression = InfixToSuffix.infixToSuffix(infixExpression);
int result = evaluateSuffix(suffixExpression);
System.out.println(result);
}
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 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 if (token.equals("/")) {
stack.push(num2 / num1);
}
}
private static boolean isNumber(String token) {
return token.matches("\\d+");
}
}
结果返回:28.
用栈进行进制转换
十进制转十六进制:
将十进制数除以16分别得到对应的余数,将余数存在事先定义好的余数栈中,从下到上拼起来,只需要把栈中结果出栈即可得到结果。
代码部分:
public classDecToHex{
public static void main(String[] args){
int sum = 654321;
ArrayStack<String> stack = new ArrayStack<>();
while(num != 0){
int a = num % 16;
if(a < 10){
stack.push(element:a + "");
}else{
syack.push(element(char)(a + 55) + "");
}
num /= 16;
}
StringBuilder sb = new StringBuilder();
while(!stack.ismpty()){
sb.append(stack.pop());
}
System.out.println(sb.toString());
}
}
返回结果:9FBF1
反过来做十六机制转换十进制:
每次从栈中取出一个十六进制数分别乘以16的对应下标次方,最后相加即可。
代码部分:
public HexToDwc{
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 mi = 0;
while(!stack.isEmpty()){
char c = stack.pop();
sum = sum + getNumber(c) * Math.pow(16,mi);
mi++;
}
System.out.println(sum);
}
private static int getNumber(char c){
if(!(c >= '0' && c <= 'A' && c <= 'F')){
throw new IllrgalGrgumentException("wrong char!");
}
if(c >= '0' && c <= '9'){
return c - '0';
}else{
return c - 'A' + 10;
}
}
}
返回结果:654321.
判断回文:偶数个全部都需要遍历,奇数个把中间值独立出来即可。
先进栈判断后进的对象与栈顶是否相同,若相同,则弹出,知道全部遍历结束,若结束后栈为空,则说明是回文数。
public class JudgingPalindrome{
public static void main(String[] agrs){
solution();
}
private static void solution(){
String text = "我是谁是我";
ArrayStack<Character> stack = new ArrayStack<>();
for(int i = 0;i < text.length(); i++){
char c = text.charAt(i);
if(stack.isEmpty()){
stack.push(c);
}else{
if(c != stack.peek()){
stack.push(c);
}else{
stack.pop();
}
}
}
}
}
括号匹配:
public class MatchBracket {
public static void main(String[] args) {
solution01();
solution02();
}
private static void solution02() {
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(']')) {
stack.pop();
} else {
stack.push(c);
}
}
}
System.out.println(stack.isEmpty());
}
private static void solution01() {
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 == -1 || top - c == -2) {
stack.pop();
} else {
stack.push(c);
}
}
}
System.out.println(stack.isEmpty());
}
}
返回:true
双端栈的定义:是指将一个线性表的两端当做栈底分别进行入栈和出栈操作,主要利用了栈的“栈底位置不变,而栈顶位置动态变化”的特性。
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 = newLen - sizeRight();
data = newData;
}
public E popLeft() {
if (isLeftEmpty()) {
throw new IllegalArgumentException("left stack is null");
}
E ret = data[ltop--];
if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
resize(data.length / 2);
}
return ret;
}
public E popRight() {
if (isRightEmpty()) {
throw new IllegalArgumentException("right stack is null");
}
E ret = data[rtop++];
if (sizeLeft() + sizeRight() <= data.length / 4 && data.length > DEFAULT_CAPACITY) {
resize(data.length / 2);
}
return ret;
}
public E peekLeft() {
if (isLeftEmpty()) {
throw new IllegalArgumentException("left stack is null");
}
return data[ltop];
}
public E peekRight() {
if (isRightEmpty()) {
throw new IllegalArgumentException("right stack is null");
}
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 ArrayDoubleEndStackIterator();
}
class ArrayDoubleEndStackIterator implements Iterator<E> {
private ArrayList<E> list;
private Iterator<E> it;
public ArrayDoubleEndStackIterator() {
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 E next() {
return it.next();
}
}
}
队列的定义:队列是只允许在一端进行插入操作,r而在另一端进行删除操作的线性表,我们把允许删除的一端称为对首(front),插入的一端称为队尾(rear),不含任何数据元素的队列称为空队列。
// 队列是一种先进先出(First in Last Out)的线性表,简称FIFO.
// 队列的插入操作叫做入队,队列的删除操作叫做出队。
Queue队列接口的定义:
public interface Queue<E> extends Iterable<E> {
public void offer(E element);
public E poll();
public E element();
public boolean isEmpty();
public void clear();
public int size();
}
public class ArrayQueue<E> implements Queue<E> {
private ArrayList<E> list;
public ArrayQueue() {
list = new ArrayList<>();
}
@Override
public void offer(E element) {
list.add(list.size(), element);
}
@Override
public E poll() {
return list.remove(0);
}
@Override
public E element() {
return list.get(0);
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public void clear() {
list.clear();
}
@Override
public int size() {
return list.size();
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public String toString() {
return list.toString();
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
if (o instanceof ArrayQueue) {
ArrayQueue other = (ArrayQueue) o;
return list.equals(other.list);
}
return false;
}
}
文件夹遍历:
public class DirectoryTraversal {
public static void main(String[] args) {
File dir = new File("C:\\Users\\HENG\\Desktop\\DS");
ArrayLoopQueue<File> queue = new ArrayLoopQueue<>();
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);
}
}
}
}
}
用栈来实现队列:
public class StackToQueue {
public static void main(String[] args) {
QueueImplByStack<Integer> queue = new QueueImplByStack<>();
for (int i = 1; i <= 5; i++) {
queue.offer(i);
}
System.out.println(queue);
System.out.println(queue.poll());
System.out.println(queue);
}
}
class QueueImplByStack<E> implements Queue<E> {
private ArrayStack<E> stackA;
private ArrayStack<E> stackB;
public QueueImplByStack() {
stackA = new ArrayStack<>();
stackB = new ArrayStack<>();
}
@Override
public void offer(E element) {
stackA.push(element);
}
@Override
public E poll() {
if (isEmpty()) {
throw new IllegalArgumentException("queue is null");
}
while (stackA.size() != 1) {
stackB.push(stackA.pop());
}
E ret = stackA.pop();
while (!stackB.isEmpty()) {
stackA.push(stackB.pop());
}
return ret;
}
@Override
public E element() {
if (isEmpty()) {
throw new IllegalArgumentException("queue is null");
}
while (stackA.size() != 1) {
stackB.push(stackA.pop());
}
E ret = stackA.peek();
while (!stackB.isEmpty()) {
stackA.push(stackB.pop());
}
return ret;
}
@Override
public boolean isEmpty() {
return stackA.isEmpty();
}
@Override
public void clear() {
stackA.clear();
}
@Override
public int size() {
return stackA.size();
}
@Override
public Iterator<E> iterator() {
return stackA.iterator();
}
@Override
public String toString() {
return stackA.toString();
}
}
用队列实现栈:
public class QueueToStack {
public static void main(String[] args) {
StackImplByQueue<Integer> stack = new StackImplByQueue<>();
System.out.println(stack);
for (int i = 1; i <= 5; i++) {
stack.push(i);
}
System.out.println(stack.toString());
System.out.println(stack.pop());
System.out.println(stack);
}
}
class StackImplByQueue<E> implements Stack<E> {
private ArrayQueue<E> queueA;
private ArrayQueue<E> queueB;
public StackImplByQueue() {
queueA = new ArrayQueue<>();
queueB = new ArrayQueue<>();
}
@Override
public int size() {
if (queueA.isEmpty() && queueB.isEmpty()) {
return 0;
} else if (!queueA.isEmpty()) {
return queueA.size();
} else {
return queueB.size();
}
}
@Override
public boolean isEmpty() {
return queueA.isEmpty() && queueB.isEmpty();
}
@Override
public void push(E element) {
if (queueA.isEmpty() && queueB.isEmpty()) {
queueA.offer(element);
} else if (!queueA.isEmpty()) {
queueA.offer(element);
} else {
queueB.offer(element);
}
}
@Override
public E pop() {
if (isEmpty()) {
return null;
}
E ret = null;
if (!queueA.isEmpty()) {
while (queueA.size() != 1) {
queueB.offer(queueA.poll());
}
ret = queueA.poll();
} else {
while (queueB.size() != 1) {
queueA.offer(queueB.poll());
}
ret = queueB.poll();
}
return ret;
}
@Override
public E peek() {
if (isEmpty()) {
return null;
}
E ret = null;
if (!queueA.isEmpty()) {
while (queueA.size() != 1) {
queueB.offer(queueA.poll());
}
ret = queueA.poll();
queueB.offer(ret);
} else {
while (queueB.size() != 1) {
queueA.offer(queueB.poll());
}
ret = queueB.poll();
queueA.offer(ret);
}
return ret;
}
@Override
public void clear() {
queueA.clear();
queueB.clear();
}
@Override
public Iterator<E> iterator() {
if (isEmpty()) {
return queueA.iterator();
} else if (!queueA.isEmpty()) {
return queueA.iterator();
} else {
return queueB.iterator();
}
}
@Override
public String toString() {
if (isEmpty()) {
return "[]";
} else if (!queueA.isEmpty()) {
return queueA.toString();
} else {
return queueB.toString();
}
}
}
回顾总结:
队列的顺序存储结构本身是由ArrayList实现的,在数据元素入队的时候,相当在ArrayList表尾添加元素,在数据元素出队的时候,相当于ArrayList表头删除元素,
很明显,入队的时间复杂度是O(1),出队的时间复杂度是O(n),线性表增删数据元素时间复杂度都是O(n),但是这个是按平均算的,队列的出队时间复杂度O(n),可不是平均算的,因为每次出队都是O(n);
三种优化方法
方法一:让对头指针和队尾指针一样随着数据元素的变化而移动
这样子出队和入队的操作都是O(1),但是Rear指针就不能再继续后移,浪费了一定的空间。
优化方法二:当队尾或队头指针到达尾部时,如需后移可重新指向表头。
解决了空间的浪费,
队列满的条件 (Rear+1)%nFront
队列空的条件 (Rear+1)%nFront
方法三:将一个空间预留出来不存任何元素,尾指针始终指向这个null空间
队列满的条件 (Rear+1)%nFront
队列空的条件 RearFront
循环队列代码:
public class ArrayLoopQueue<E> implements Queue<E> {
private E[] data;
private int front;
private int rear;
private int size;
private static int DEFAULT_CAPACITY = 10;
public ArrayLoopQueue() {
data = (E[]) new Object[DEFAULT_CAPACITY + 1];
front = 0;
rear = 0;
size = 0;
}
@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("queue is null");
}
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 = front; 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("queue is null");
}
return data[front];
}
@Override
public boolean isEmpty() {
return front == rear;
}
@Override
public void clear() {
data = (E[]) new Object[DEFAULT_CAPACITY];
size = 0;
front = 0;
rear = 0;
}
@Override
public int size() {
return size;
}
@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;
}
@Override
public Iterator<E> 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;
}
}
}
双端队列的定义
双端队列(double ended queue ,deque)是限定插入和删除操作在表的两端进行的线性表是一种具有队列和栈的性质的数据结构。
双端队列空时:front == rear
双端队列满时:(rear + 1) % len == fron
Deque双端队列接口的定义:
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 int size(); public boolean isEmpty(); public void clear();}
ArrayDeque类:
public class ArrayDeque implements Dequeue, Stack {
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++;
}
private void resize(int newLen) {
E[] newData = (E[]) new Object[newLen];
int index = 0;
for (int i = front; i != rear; i = (i + 1) % data.length) {
newData[index++] = data[i];
}
data = newData;
front = 0;
rear = index;
}
@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++;
}
@Override
public E removeFirst() {
if (isEmpty()) {
throw new IllegalArgumentException("queue is null");
}
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 null;
}
@Override
public E reomveLast() {
if (isEmpty()) {
throw new IllegalArgumentException("queue is null");
}
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("queue is null");
}
return data[front];
}
@Override
public E getLast() {
if (isEmpty()) {
throw new IllegalArgumentException("queue is null");
}
return data[(rear - 1 + data.length) % data.length];
}
@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 reomveLast();
}
@Override
public void clear() {
E[] data = (E[]) new Object[DEFAULT_CAPACITY];
front = 0;
rear = 0;
size = 0;
}
@Override
public int size() {
return size;
}
@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 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;
}
}
}
asd