栈和队列

1 栈(Stack) 是一种 特殊的线性表, 其只允许在固定的一端进行插入和删除元素操作.

(1) 进行数据插入和删除操作的一端称为 栈顶, 另一端称为 栈底. 栈中的元素遵循先进后出的原则.
(2) 栈一般用 数组 实现. (定义一个数组和栈中 有效元素的个数)
(3) 标准库中的栈Stack的 入栈push(), 出栈pop(), 取栈顶元素peek() 操作都是在栈顶进行的操作.

public class MyStack {
    //管理一些int元素即可,也不考虑扩容问题
    private int[] array=new int[100];
    private int size=0;  //栈中存在多少个有效元素
    //入栈
    public void push(int i){
        array[size]=i;
        size++;
    }
    //取栈顶元素(最后进来的那个元素)
    public int peek(){
        return array[size-1];
    }
    //出栈
    public int pop(){
        int ret=array[size-1];
        size--;
        return ret;
    }
}

2 队列(Queue) 只允许在一端进行插入数据操作, 在另一端进行删除数据操作的特殊线性表,队列具有先进先出特点.

(1) 入队列: 进行插入操作的一端称为队尾. 出队列:进行删除操作的一端称为队头.
(2) 队列一般由 数组 或 链表 实现.
(3) 标准库中入队列offer(), 出队列poll(),取队首元素peek().

(4) 由 数组 实现队列.(定义一个 数组, head, hail, 及有元素的个数 size.
[head, tail) 有效元素的范围. tail++ 之后如果超出了数组的有效范围, 就从头开始)

public class MyQueueByArray {
    private int[] array=new int[100];
    // [head, tail) 有效元素的范围. 注意, tail 可能在 head 之前
    private int head=0;
    private int tail=0;
    private int size=0;//元素个数
    public void offer(int val){
        if(size==array.length){
            //队列满了,无法继续插入
            return;
        }
        // 得保证这个操作下标不能越界
        array[tail]=val;
        tail++;
        // tail++ 之后如果超出了数组的有效范围, 就从头开始
        if(tail>=array.length){
            tail=0;
        }
        size++;
    }
    public Integer poll(){
        if(size==0){
            return null;
        }
        Integer ret=array[head];
        head++;
        if(head>=array.length){
            head=0;
        }
        size--;
        return ret;
    }
    public Integer peek(){
        if(size==0){
            return null;
        }
        return array[head];
    }
}

(5) 由 链表 实现队列.

public class MyQueueByLinkedList {
  static class Node{
      public int val;
      Node next=null;
      public Node(int val){
          this.val=val;
      }
  }
    private Node head=null;
    private Node tail=null;
此处我按照尾部入队列, 头部出队列的方式实现
     public void offer(int val){
         Node newNode=new Node(val);
         if(head==null){
             head=newNode;
             tail=newNode;
             return;
         }
         //当前如果不是空链表
         tail.next=newNode;
         tail=tail.next;
     }
    public Integer poll(){
         //如果当前队列就是空队列, 再去 poll 显然不科学
        if(head==null){
            //如果出队列失败,返回一个错误值
            return null;
        }
        int ret=head.val;
        head=head.next;
        if(head==null){     
            tail=null;
        }
        return ret;
    }
    public Integer peek(){
         if(head==null){
             return null;
         }
         return head.val;
    }
}

3 循环队列: 能更有效的利用资源空间,通常由 数组 实现.
(1) 队列中 有效元素 的长度有两种情况:
head在前tail在后时, 有效元素为2 3 4.
head在后,tail在前时, 有效元素为4 5 6 7 8 1.

(2) 前者当head和tail重合时, 就是 空队列.
后者重合时, 就是一个 满队列.

在这里插入图片描述
4 双端队列(Deque): 两端 都可以进行入队列和出队列操作的队列.

5 栈和队列的相互实现.

(1) 两个队列实现一个栈.
入栈, A 队列负责入栈, 按照正常入队列存放元素, B是辅助队列.
出栈, 把A中的元素按照出队列放到B中, 直到剩一个元素. 最后把这一个元素出队列. 然后 交换AB队列.
取栈顶元素, 和出栈一样, 只是把最后那一个元素也要加入到B, 然后 交换AB.
判断栈是空, AB都为空, 栈才是空.

public class MyStackBy2Queue {
    private Queue<Integer> A=new LinkedList<>();
    private Queue<Integer> B=new LinkedList<>();
    public void push(int x){    
        A.offer(x);
    }
    public Integer pop(){
        if(empty()){
            return null;
        }
        while(A.size()>1){
            Integer front=A.poll();
            B.offer(front);
        }
        int ret=A.poll();
        swapAB();
        return ret;
    }
    private void swapAB(){
        Queue<Integer> tmp=A;
        A=B;
        B=tmp;
    }
    public Integer top(){
        if(empty()){
            return null;
        }
        while (A.size() > 1) {
            Integer front = A.poll();
            B.offer(front);
        }
        int ret = A.poll();
        B.offer(ret);   // top 和 pop 唯一的区别就是这句话
        swapAB();
        return ret;
    }
    public boolean empty(){
        return A.isEmpty()&&B.isEmpty();
    }
}

(2) 两个栈实现一个队列.
入队列, 先把一个栈中的元素倒到另一个栈中, 然后把目标元素进行入栈.
出队列, 先把一个栈中的元素倒到另一个栈中, 然后出栈.
取队首元素, 先把一个栈中的元素倒到另一个栈中, 然后取栈顶元素.
判断队列为空, 两个栈都为空时队列才为空.

public class MyQueueBy2Stack {
    private Stack<Integer> A=new Stack<>();
    private Stack<Integer> B=new Stack<>();
    public void push(int x){
        while (!B.isEmpty()){
            int tmp=B.pop();
            A.push(tmp);
        }
        A.push(x);
    }
    public Integer pop(){
        if(empty()){
            return null;
        }
        while (!A.isEmpty()){
            int tmp=A.pop();
            B.push(tmp);
        }
        return B.pop();
    }
    public Integer peek(){
        // 1. 如果为空, 就直接返回
        if (empty()) {
            return null;
        }
        while (!A.isEmpty()) {
            int tmp = A.pop();
            B.push(tmp);
        }
        return B.peek();
    }
    public boolean empty() {
        return A.isEmpty() && B.isEmpty();
    }
}

6 判断题中的有关 栈的顺序问题. 如果是从小到大按序入栈的话, 可以把字母变成数字, 出现 大小中 的顺序的选项即为不可能出现的情况.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值