数据结构 - 栈和队列

数据结构 - 栈和队列

1 栈

1.1 基本概念
  • 线性结构
  • 后进先出的数据结构,(Last In First Out, LIFO)
1.2 栈的应用
1.2.1 Undo(撤销) 操作
  • 通过栈的栈顶拿到最近一次操作的元素,通过出栈删除元素
1.2.2 程序调用的系统栈
  • 程序运行过程中的调用
function A() {
1
2 B()
3    
}

function B() {
1
2 C()
3    
}

function C() {
1
2
3    
}

系统栈在执行A时,在第二步将B2 入栈,跳转执行B,在第二步将C2 入栈,跳转执行C,C执行完毕后,出栈后继续接着B2执行,B执行完毕后,再出栈接着A2执行知道程序结束

1.2.3 栈的基本操作
Stack<E>
    
void push(E) //入栈操作,放入元素
    
E pop() //出栈操作,取出元素
    
E peek() //查看栈顶元素
    
int getSize() //查看栈中元素个数
    
boolean isEmpty() //判断栈是否为空    
1.2.4 括号匹配 - 编译器
/*
	给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效 Leetcode 20 
*/

public static boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '(' || c == '[' || c == '{')
                stack.push(c);
            else {
                if (stack.isEmpty())
                    return false;
                Character top = stack.pop();
                if (c == ')' && top != '(')
                    return false;
                if (c == ']' && top != '[')
                    return false;
                if (c == '}' && top != '{')
                    return false;
            }
        }

        return stack.isEmpty();
    }

2 队列

2.1 基本概念
  • 先进先出的数据结构,FIFO
2.2 队列的基本实现
Queue<E>
    
void enqueue(E element); // 入队

E dequeue(); // 出队

E getFront(); // 查看队首元素

int getSize(); // 队列长度

boolean isEmpty(); // 判断队列是否为空
2.2.1 队列的实现方式一 基于数组
  • 基于数组实现在出队的时候时间复杂度为 O(n)
// 1. 自定义自动扩容的数组
package com.structrue.array;

public class ArrayReview<E> {
    private E[] data;

    private int size;

    public ArrayReview(int size) {
        this.size = 0;
        this.data = (E[]) new Object[size];
    }

    public ArrayReview() {
        this(10);
    }

    // 添加数据到指定索引的位置
    public void add(int index, E element) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("index out of bounds");

        for (int i = size; i > index ; i--) {
            data[i] = data[i-1];
        }

        data[index] = element;

        size++;

        if (size >= data.length*0.85) {
            resize(data.length << 1);
        }
    }

    // 尾插
    public void addLast(E element) {
        add(size, element);
    }

    // 头插
    public void addFirst(E element) {
        add(0,element);
    }

    //删除指定索引的数据并返回该数据
    public E remove(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("out of bounds");

        E e = data[index];

        for (int i = index; i < size - 1; i++) {
            data[i] = data[i+1];
        }

        data[size--] = null;

        if (size <= data.length >> 2 && data.length >> 1 != 0)
            resize(data.length >> 1);
        return e;
    }

    // 删除第一个
    public E removeFirst() {
        return remove(0);
    }

    // 删除最后一个
    public E removeLast() {
        return remove(size-1);
    }

    // 获取指定下标元素
    public E get(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("out of bounds");

        return data[index];
    }

    // 修改指定下标元素
    public void set(int index, E element) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("out of bounds");

        data[index] = element;
    }

    // 判断数组是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    // 判断数组是否包含元素
    public boolean contains(E element) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(element))
                return true;
        }

        return false;
    }

    // 根据元素查找下标
    public int find(E element) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(element))
                return i;
        }
        return -1;
    }

    // 扩容
    public void resize(int length) {
        E[] arr = (E[]) new Object[length];
        for (int i = 0; i < size; i++) {
            arr[i] = data[i];
        }
        data = arr;
    }

    // 获取最后一个
    public E getLast() {
        return data[size-1];
    }

    // 获取size
    public int getSize() {
        return size;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Capacity :"+data.length+", Size :"+size + "\n" +"[");
        for (int i = 0; i < size; i++) {
            sb.append(data[i]);
            if (i != size-1)
                sb.append(", ");
        }
        sb.append("]");
        return sb.toString();
    }
}

// 2.在自定义数组的基础上实现队列

package com.structrue.queue;

import com.structrue.array.ArrayReview;

public class ArrayQueue<E> implements Queue<E> {
    private ArrayReview<E> queue;

    public ArrayQueue() {
        this.queue = new ArrayReview<>();
    }

    public ArrayQueue(int capacity) {
        this.queue = new ArrayReview<>(capacity);
    }

    @Override
    public void enqueue(E element) {
        queue.addLast(element);
    }

    @Override
    public E dequeue() {
        return queue.remove(0);
    }

    @Override
    public E getFront() {
        return queue.getLast();
    }

    @Override
    public int getSize() {
        return queue.getSize();
    }

    @Override
    public boolean isEmpty() {
        return queue.isEmpty();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Queue : Size :"+queue.getSize()+ "\n"+ "head " +"[ ");
        for (int i = 0; i < queue.getSize(); i++) {
            sb.append(queue.get(i));
            if (i != queue.getSize()-1)
                sb.append(", ");
        }
        sb.append("] tail");

        return sb.toString();
    }
}

2.2.2 队列的实现方式二 基于循环队列
// 循环队列

package com.structrue.queue;

public class LoopQueue<E> implements Queue<E> {
	
    private E[] data;
	// 通过定义头指针和尾指针来实现循环,尾指针指向数组中下一个空位置
    private int head, tail;
	// 记录队列中的元素个数
    private int size;
	
    // 指定队列容量初始化
    public LoopQueue(int capacity) {
        // 数组的实际长度为容量+1,因为规定head和tail相等时队列为空,所以当数组只剩最后一个时认为容量已满
        this.data = (E[]) new Object[capacity+1];
        this.head = this.tail = 0;
        this.size = 0;
    }
	
    // 无参默认容量为10
    public LoopQueue() {
        this(10);
    }

    @Override
    public void enqueue(E element) {
        // 判断容量是否已满,(tail+1) % data.length 表示在循环下的下一个位置,如果下一个位置为head则表明队列中容量已满
        if ((tail+1) % data.length == head)
            // 扩容扩大两倍
            resize(getCapacity() << 2);
		// 新元素入队在队尾位置
        data[tail] = element;
        // 尾指针向后移动
        tail = (tail + 1) % data.length;
        size++;
    }

    @Override
    public E dequeue() {
        // 判断队列是否为空
        if (isEmpty())
            throw new IllegalArgumentException("Empty queue!");
		// 获取队首元素
        E e = data[head];
        // 出队,将队首元素置空
        data[head] = null;
        // 头节点向后移动一位
        head = (head + 1) % data.length;
        size --;
        // 判断出队后队列是否需要缩容,当实际元素个数小于队列容量的1/4时
        if (size <= getCapacity() >> 2 && getCapacity() >> 1 !=0)
            // 缩容为1/2
            resize(getCapacity() >> 1);

        return e;
    }

    @Override
    public E getFront() {
        if (isEmpty())
            throw new IllegalArgumentException("empty queue!");
        return data[head];
    }

    @Override
    public int getSize() {
        return size;
    }
	// 当头尾指针相同时则队列为空
    @Override
    public boolean isEmpty() {
        return head == tail;
    }
	// 获得数队列的实际容量(为内部数组length-1)
    public int getCapacity() {
        return data.length-1;
    }

    public void resize(int capacity) {
        // 根据新容量新建一个数组
        E[] arr = (E[]) new Object[capacity+1];
        
        for (int i = 0; i < size; i++) 
            // 将原队列中元素从head结点开始对应放入新数组0下标开始
            arr[i] = data[(i+head) % data.length];
        

        data = arr;
        head = 0;
        tail = size;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("LoopQueue : Size :" + size + "\n" + "[");
        for (int i = head; i != tail ; i = (i+1) % data.length) {
            sb.append(data[i]);
            if ((i+1) % data.length != tail)
                sb.append(", ");
        }
        sb.append("]");
        return sb.toString();
    }
}

posted @ 2021-02-28 22:55  Pengc931482  阅读(75)  评论(0)    收藏  举报