数据结构之队列

45 篇文章 0 订阅

1.概念

队列:只允许再一段进行插入数据的操作,再另一端进行删除数据的操作。队列具有先进先出FIFO(First In First Out)入队操作:进行插入操作的一段称为队尾,出队列:进行删除操作的一端称为队头

2.队列的使用

在Java中,Queue是一个接口,底层是通过链表来实现的,真正的实现这个接口的是LinkedList

注意】Queue是一个接口,在实例化时必须实例化LinkedList的对象,因此LinkedList实现了Queue接口

接下来看一下Queue常用的方法:

//队列常用的方法
public class Test {
    public static void main(String[] args) {
        Queue<Integer> q = new LinkedList<>();
        System.out.println("======================入队操作======================");
        q.offer(1);
        q.offer(2);
        q.offer(3);
        q.offer(4);
        q.offer(5);
        System.out.println(q);
        System.out.println("=====================获取队头元素====================");
        System.out.println(q.peek());
        System.out.println("===================从队头出队========================");
        System.out.println(q.poll());
        System.out.println(q);
        System.out.println("===================检测是否为空======================");
        System.out.println(q.isEmpty());
        System.out.println("===================输出元素个数======================");
        System.out.println(q.size());
        
    }
}

3.队列的模拟实现

队列中既可以储存元素,那底层肯定有储存元素的空间,通过前面线性表的学习,我们有两种数据结构可以选择:顺序结构 和 链式结构 。那么我们思考:队列的实现是用顺序结构好,还是线性结构好?

我们这里只用顺序结构来实现一下(顺序结构相对较难)

3.1循环队列

1.我们发现如果数组实现队列,如果进行出队操作,是从头出,这回导致前面的空间被释放后无法使用的问题。

2.我们设置一个循环队列,让其循环往复,这样就能使用被出队的空间了。

3.但是这样也会出现问题,如果元素被存满了,head=last,跟原先空的情况一样了。

4.我们可以采取两种方法:设置一个size空出一个空间不存放,如果是下图这个样子,我们就认为它是满的。

3.2代码

package Demo;

/**
 * Describe:简单模拟实现单端队列
 * User:lenovo
 * Date:2023-01-11
 * Time:15:39
 */
public class MyQueue {
    int[] array;
    int length;
    int head;
    int last;

    public MyQueue() {
        array = new int[8];
        head = 0;
        last = 0;
        length = 8;
    }

    //入队
    public void offer(int val) {
        if((last + 1) % length == head) {
            throw new RuntimeException("空间已满");
        }
        array[last] = val;
        last = (last + 1) % length;//防治下标超出范围;
    }
    //出队
    public int poll() {
        if(last == head) {
            throw new NullPointerException("数组为空");
        }
        if(head < length - 1) {
            head++;
            return array[head - 1];
        }else {
            head = 0;
            return array[length - 1];
        }
    }

    //获取队首元素
    public int peek() {
        if(last == head) {
            throw new NullPointerException("数组为空");
        }
        return array[head];
    }

    //获取有效元素个数
    public int size() {
        if(last > head || last == head) {
            return last - head;
        }else {
            return last + length - head;
        }
    }

    //判断是否为空
    public boolean isEmpty() {
        return head == last;
    }

    //测试
    public static void main(String[] args) {
        MyQueue q = new MyQueue();
        q.offer(1);
        q.offer(2);
        q.offer(3);
        q.offer(4);
        q.offer(5);
        q.offer(6);
        q.offer(7);
        //q.offer(8);
        System.out.println("==================查看队首元素================");
        System.out.println(q.peek());
        System.out.println("==================出队=======================");
        System.out.println(q.poll());
        System.out.println(q.peek());
        System.out.println();
        System.out.println("==================检测能否入队========================");
        q.offer(99);
        System.out.println("==================全部出队===========================");
        System.out.println(q.poll());
        System.out.println(q.poll());
        System.out.println(q.poll());
        System.out.println(q.poll());
        System.out.println(q.poll());
        System.out.println(q.poll());
        System.out.println(q.poll());
        //System.out.println(q.poll());

        System.out.println("==================元素个数==========================");
        System.out.println(q.size());
        System.out.println("==================检测是否为空=======================");
        System.out.println(q.isEmpty());
    }
}

4.双端队列(deque)(全称double ended queue)

双端队列是指两端都能够入队和出队操作的队列。Deque是一个接口,使用时必须要创建LinkedList的对象。

在实际的工程中,使用Deque接口比较多,栈和队列均可以使用该接口。

5.题目

  1. 使用两个队列实现一个后入先出的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

  • void push(int x) 将元素 x 压入栈顶。

  • int pop() 移除并返回栈顶元素。

  • int top() 返回栈顶元素。

  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

class MyStack {
    private Queue<Integer> q1;
    private Queue<Integer> q2;

    public MyStack() {
        q1 = new LinkedList<Integer>();
        q2 = new LinkedList<Integer>();
    }

    public void push(int x) {
        if(q2.isEmpty()) {
            q1.offer(x);
        }else {
            q2.offer(x);
        }
    }

    public int pop() {
        if(!q1.isEmpty()) {
            int size = q1.size();
            while(size - 1 > 0) {
                q2.offer(q1.poll());
                size--;
            }
            return q1.poll();
        }else if(!q2.isEmpty()) {
            int size = q2.size();
            while(size - 1 > 0) {
                q1.offer(q2.poll());
                size--;
            }
            return q2.poll();
        }
        return 0;

    }

    public int top() {
        if(!q1.isEmpty()) {
            int size = q1.size();
            while(size - 1 > 0) {
                q2.offer(q1.poll());
                size--;
            }
            int ret = q1.poll();
            q2.offer(ret);
            return ret;
        }else if(!q2.isEmpty()) {
            int size = q2.size();
            while(size - 1 > 0) {
                q1.offer(q2.poll());
                size--;
            }
            int ret = q2.poll();
            q1.offer(ret);
            return ret;
        }
        return 0;
    }

    public boolean empty() {
        return q1.isEmpty() && q2.isEmpty();

    }

    
}
  • 首先创建两个队列;

  • 入队时,那个队列有元素,入哪个队;如果都没元素,入q1;

  • 出队的时候,我们要的是队尾的元素;我们让有元素的队列中的元素,出队,入队到另一个队列,直到原队列剩余一个元素。然后原队列出队操作,返回这个值;

  • 两个队列都为空,返回空。

2.使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

void push(int x) 将元素 x 推到队列的末尾

int pop() 从队列的开头移除并返回元素

int peek() 返回队列开头的元素

boolean empty() 如果队列为空,返回 true ;否则,返回 false

//使用栈表示队列
class MyQueue {
    Stack<Integer> s1;
    Stack<Integer> s2;

    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }

    public void push(int x) {
        while(!s1.empty()) {
            s2.push(s1.pop());
        }
        s2.push(x);
        while(!s2.empty()) {
            s1.push(s2.pop());
        }
    }

    public int pop() {
        if(s1.isEmpty()) {
            return 0;
        }
        return s1.pop();

    }

    public int peek() {
        if(s1.isEmpty()) {
            return 0;
        }
        int val = s1.peek();
        return val;

    }

    public boolean empty() {
        return s1.empty();

    }
}
  • 创建两个栈,s1表示出队的顺序,s2表示入队的顺序;

  • 如果要入栈,把s1的元素转移到s2中,新的元素再放入s2,再将s2的全部元素转移到s1为出队的顺序;

  • 入队和出队和查看队首就很好写了,同样判断是否为空也很好写了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值