数据结构之栈和队列的实现

1. 分析:

1. 栈的特点是先进后出
2. 栈就好比一个箱子,先放进去的东西,被压在了箱子底部,需要上面的东西拿出来之后下面的东西才能拿出来。
3. 队列的特点是先入先出
4. 队列就好比排队买票,先排队的先买票,我可不会给你插队的
5. 队列(Queue)是限定只能在一端插入、另一端删除的线性表。允许删除的一端叫做队头(front),允许插入的一端叫做队尾(rear),没有元素的队列称为“空队列”。

2. 栈

1). 定义一个Stack接口

public interface Stack <E>{

    void push(E e);
    E pop();
    E peek();
    boolean isEmpty();
    int size();
}    
2). 定义一个具体实现类ArrayStack

这里是基于前一篇定义的可变长度数组实现的,因为逻辑一样
public class ArrayStack<E> implements Stack<E>{

    private Array<E> array;

    public ArrayStack(){
        this(10);
    }

    public ArrayStack(int capacity){
        array = new Array<>(capacity);
    }

    //入栈
    @Override
    public void push(E e) {
        array.addFirst(e);
    }

    //出栈
    @Override
    public E pop() {
        return array.removeFirst();
    }

    @Override
    public E peek() {
        return array.getFirst();
    }

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

    @Override
    public int size() {
        return array.size();
    }

    public int getCapacity(){
        return array.getCapacity();
    }

    public String toString(){

        StringBuilder sb = new StringBuilder();
        sb.append("ArrayStack size ").append(size());
        sb.append(", capacity ").append(getCapacity());
        sb.append("\n");
        sb.append("[");
        for (int i = 0; i < size(); i++) {
            sb.append(array.get(i));
            if(i != size() - 1){
                sb.append(", ");
            }
        }
        sb.append("]");
        sb.append("\n");
        return sb.toString();
    }
}

3). 栈的实例

给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串,判断字符串是否有效。

有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

示例 1:
输入: "()[]{}"
输出: true

示例 2:
输入: "(]"
输出: false

分析:
只要是‘{,[,(’就入栈,不是就出栈,然后进行比较,
如果是匹配的,最后栈一定是空的


public 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;
        }else{
            char pop = stack.pop();
            if(c == ']' && pop != '[')
                return false;
            if(c == '}' && pop != '{')
                return false;
            if(c == ')' && pop != '(')
                return false;
        }
    }
    return stack.isEmpty();
}

3. 队列

1)定义一个队列的接口Queue

public interface Queue<E>{

    void enqueue(E e);
    E dequeue();
    E front();
    int size();
    boolean isEmpty();
}
2)定义一个具体的实现类,实现Queue接口
也是基于前一篇定义的可变长度数组实现的,因为逻辑一样

public class ArrayQueue<E> implements Queue<E>{

    private Array<E> array;

    public ArrayQueue(int capacity) {
        array = new Array<>(capacity);
    }

    public ArrayQueue() {
        array = new Array<>();
    }

    //入队 队尾入
    @Override
    public void enqueue(E e) {
        array.addLast(e);
    }

    //出队 对头出
    @Override
    public E dequeue() {
        return array.removeFirst();
    }

    //获取对头的元素
    @Override
    public E front() {
        return array.getFirst();
    }

    @Override
    public int size() {
        return array.size();
    }

    public int getCapacity(){
        return array.getCapacity();
    }

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

    public String toString(){

        StringBuilder sb = new StringBuilder();
        sb.append("ArrayQueue size ").append(size());
        sb.append(", capacity ").append(getCapacity());
        sb.append("\n");
        sb.append("front [");
        for (int i = 0; i < size(); i++) {
            sb.append(array.get(i));
            if(i != size() - 1){
                sb.append(", ");
            }
        }
        sb.append("] tail");
        return sb.toString();
    }
}

3. 循环队列

1) 构造方法
private E[] data;
//对头
private int front;
//队尾
private int tail;
private int size;
public LoopQueue(int capacity){
    data = (E[]) new Object[capacity + 1] ;
    front = 0;
    tail = 0;
    size = 0;
}

public LoopQueue(){
    this(10);
}
2) 入队 对尾插入

@Override
public void enqueue(E e) {

    if((tail + 1) % data.length == front){
         //扩容
        resize(getCapacity() * 2);
    }
    data[tail] = e;
    //因为是循环队列 所以对data.length取余
    tail = (tail + 1) % data.length;
    size++;
}
3)出队 对头删除
@Override
public E dequeue() {
    if(isEmpty())
        throw new IllegalArgumentException("数据是空的");
    E temp = data[front];
    data[front] = null;
    //对头出 循环队列 所以对data.length取余
    front = (front + 1) % data.length;
    size --;
    if(size == getCapacity() / 4 && getCapacity() / 2 != 0){
         //减少容量
        resize(getCapacity() / 2);
    }
    return temp;
}
4)获取对头元素

@Override
public E front() {
    if(isEmpty())
        throw new IllegalArgumentException("数据是空的");
    return data[front];
}
5) 扩容

private void resize(int newCapacity) {
    E[] newData = (E[]) new Object[newCapacity + 1] ;
    for (int i = 0; i < size; i++) {
         //这里需要注意 front可能不是0 然后需要对data.length取余,循环去取data里面的元素
        newData[i] = data[(i + front) % data.length];
    }
    data = newData;
    //扩容后 对头要重置为0
    front = 0;
    //队尾是队列的size
    tail = size;
}

4. 小结

其实主要也是针对数组的操作,不过对于循环队列需要注意取余

5.联系方式

QQ:1509815887
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值