【玩转数据结构 从入门到进阶2学习笔记】栈和队列

39 篇文章 0 订阅
18 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
可以先来看看栈的应用,上图是程序调用的系统栈,箭头方向指明了程序运行顺序,我们运行到A2时把它压入栈,接着跳到B,执行到B2时再把它压入栈,再执行C,执行完C,我们可以看栈顶,是B2,我们跳回B2继续执行,B执行完后再看栈顶,是A2,跳回A2继续执行,A执行完后,栈空,程序结束,从这可以看出栈在程序调用问题上给出了很好的解决方法。

栈的基本实现

我们要如何实现一个栈呢,其实很简单,只要实现以下几个方法
在这里插入图片描述
栈有推入,拿出操作,peek操作是查询并获取栈顶元素,还有获取栈内元素个数和判断是否为空,所以我们可以利用之前自己封装的数组,实现这个栈接口,

public class ArrayStack <E> implements Stack<E> {
    Array<E> array;

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

    public  ArrayStack(){
        array=new Array<>();
    }
    @Override
    public  int getSize(){
        return array.getSize();
    }

    @Override
    public  boolean isEmpty(){
        return array.isEmpty();
    }
    @Override
    public  void push(E e){//栈是先进后出,所以要往后添加元素
        array.addLast(e);
    }

    @Override
    public E pop(){
        return array.removeLast();
    }

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

    public int getCapicity(){
        return array.getCapacity();
    }
    @Override
    public String toString(){
        StringBuilder res=new StringBuilder();
        res.append("Stack:");
        res.append("[");
        for(int i=0;i<array.getSize();i++){
            res.append(array.get(i));
            if (i!=array.getSize()-1){
                res.append(",");
            }
        }
        res.append("] top");
        return res.toString();
    }
}

测试用例:

 ArrayStack<Integer> arr=new ArrayStack<>();
        for(int i=0;i<10;i++){
            arr.push(i);
            System.out.println(arr);
        }

栈的另一个应用–括号匹配

这也是LeetCode第20题,
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

这里可以利用栈来实现,遍历字符串,遇到三种左括号则压入栈,否则,判断栈是否为空,为空则返回false;接着再判断栈顶元素是否为左括号对应的右括号,最后返回栈是否为空,不为空表明字符串有效

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

数组队列

在这里插入图片描述
队列与栈比较相似,但队列是先进先出的结构,我们可以同样实现Queue接口中的五个方法,以此实现一个基本的数组队列,

public interface Queue<E> {
    int getSize();
    boolean isEmpty();
    void enqueue(E e);
    E dequeue();
    E getFront();
}
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 int getSize(){
        return array.getSize();
    }
    @Override
    public  boolean isEmpty(){
        return array.isEmpty();
    }
    @Override
    public  void enqueue(E e){
         array.addLast(e);
    }
    @Override
    public  E dequeue(){
        return array.removeFirst();
    }
    @Override
    public  E getFront(){
        return array.getFirst();
    }
    public  int getCapacity(){
        return  array.getCapacity();
    }

    @Override
    public  String toString(){
        StringBuilder res=new StringBuilder();
        res.append("Queue:");
        res.append("Front [");
        for(int i=0;i<array.getSize();i++){
            res.append(array.get(i));
            if (i!=array.getSize()-1){
                res.append(",");
            }
        }
        res.append("] Tail");
        return res.toString();
    }
}

循环队列

循环队列在方法上的实现与数组队列不同,所以需要重新自己写,需要定义两个头front和尾tail,其中tail指的是最后一个元素后面一个位置
循环队列队满和队空的要求分别为
front =tail,表示队空
(tail+1)%data.length=front, 表示队满,在这里有意识的浪费一个capacity,tail所指位置不放元素;

public class LoopQueue<E> implements  Queue<E> {
    private  E[] data;
    private  int front,tail;
    private  int size;

    public  LoopQueue(int capacity){
        data=(E[])new Object[capacity+1];
        front=0;
        tail=0;
        size=0;
    }
       public LoopQueue(){
        this(10);
    }

  @Override
    public int getSize(){
        return size;
    }

    public  int getCapacity(){//获取容量大小为队列长度-1;因为有一个位置为空
        return data.length-1;
    }
    @Override
    public  boolean isEmpty(){
        return front==tail;
    }

入队操作,这里的扩容与动态数组相似

  @Override
    public  void enqueue(E e){
        if ((tail+1)%data.length==front){//判断是否队满,若满,则需扩容
            resize(2*getCapacity());
        }
        data[tail]=e;
        tail=(tail+1)%data.length;
        size++;
    }

扩容操作,将原数组内容复制到新数组中,不过要注意复制过程,新数组的0号位对应原数组的front位置,还要采用循环方式

    public void resize(int newCapacity){
        E [] newData=(E [])new Object[newCapacity+1];
        for (int i=0;i<size;i++){
            newData[i]=data[(i+front)%data.length];
        }
        data=newData;
        front=0;
        tail=size;
    }

出队,这里要先判断是否为空,同样这里出队只需将front的值变为null,front往后移一位,如果队列元素过少,需减小容量,提高性能这一步的时间复杂度为O(1),而数组队列在这一步时间复杂度为O(n)

@Override
    public  E dequeue(){

        if (isEmpty()){
            throw  new IllegalArgumentException("dequeue fail");
        }

        E ret=data[front];
        data[front]=null;
        front=(front+1)%data.length;
        size--;
        if (size==getCapacity()/4){
            resize(getCapacity()/2);
        }
        return ret;
    }

  @Override
    public  String toString(){
        StringBuilder res=new StringBuilder();
        res.append(String.format("Queue:size=%d,capacity=%d\n",size,getCapacity()));
        res.append("front [");
        for (int i=front;i!=tail;i=(i+1)%data.length){
            res.append(data[i]);
            if ((i+1)%data.length!=tail){
                res.append(",");
            }
        }
        res.append("] tail");
        return res.toString();
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术的小小林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值