数据结构篇——队列

队列的特点:先入先出,就好像饭堂排队打饭的排的队一样,排第一的先拿到饭去打菜,跑得快,拿第一有饭吃,跑得慢。。。。

操作:插入,在队尾插入元素,就好像在饭堂打饭需要按序排队。

           删除,删除队首的元素,就好像在饭堂拿到饭的人,不能老是在第一站着位置。

实现:

class Queue{
    
    List<Integer> list;
    int index;  //记录队首的位置
    // 初始化队列
    public Queue(){
        list = new ArrayList<>();
        index = 0;
    }

    // 实现入队操作
    public boolean enQueue(int value){
        // 队列满了后就不能再加入元素了
        list.add(value);
    }

    // 实现删除操作
    public boolean remove(){
       if(isEmpty) return false;
        index++;
        return true;
    }
    
    public int Front(){
        return list.get(index);
    }


    // 判断是否为空
    publi boolean isEmpty(){
        return index >= list.size();
    }

}

基于 链表 实现的队列:它可以创建任意数据类型的队列。

public class Queue<Item>{
    private Node first;   // 指向最早添加结点的链接
    private Node last;    // 指向最近添加结点的链接
    private int N;     // 结点的个数

    // 定义结点的嵌套类
    public class Node{
        Item item;
        Node next;
    }

    public boolean isEmpty(){
        return fisrt == null;
    }

    public int size(){ return N;}
    
    public void enqueu(Item item){
        Node oldlast = last;
        last = new Node();
        last.item = item;
        last.next = null;
        if(isEmpty()) first = last;
        else oldlast.next = last;
    }

    public Item dequeue(){
        Item item = first.item;
        first = first.next;
        if(isEmpty()) last = null;
        N--;
        return item;
    }
}

 

缺点:如果队列头指针移到队列的中间位置,那么前面的空间就白白浪费了,这时候就循环队列就应运用而生了。

循环队列:设置两个指针 head,tailhead 记录队列的队首的指针的位置和 tail 记录队尾指针的位置,如果 tail 到队列的尾部的时候,如果队列的前面还有位置,那么可以将元素存储到前面去,这时候将 tail 的值更新即,此时 tail 的值是小于 head 的值的。

优点:极大的利用了空间。

实现:同时也是 leetcode.622 的一道题:设计循环队列,重点是判空,答案中用的是 head == -1,其实也可以用 head == tail

队列满的条件:(tail + 1)%size = head。

class myQueue(){
     
    int[] data;
    int head;
    int tail;
    int size;
    public myQueue(int k){
        data = new int[k];
        head = -1;
        tail = -1;
        size = k;
    }

    // 入队操作
    public boolean enQueue(int value){
        if(isFull()) return false;
        if(isEmpty()){ head = 0;}
        tail = (tail+1) % size;
        data[tail] = value;
        return true; 
    }

    // 出队操作
    public boolean deQueue(){
        if(isEmpty()) return false;
        // 清空将下标置为 1
        if(tail == head){head = -1;tail = -1;return true;}
        head = (head+1) % size;
        return true;
    }

    // 获取队首元素
    public int Front(){
        if(isEmpty()) return false;
        return data[head];
    }

    //  获取队尾元素
    public int Rear(){
        if(isEmpty()) return false;
        return data[tail];
    }

    // 判断队列是否为空
    public boolean isEmpty(){
        return head == -1;
    }

    // 判断队列满了没
    public boolean isFull(){
        return (tail+1) % size == head;
    }

}

java 内置库的实现:不用重复造轮子了。

class myQueue{
    
    public static void main(string[] args){
        Queue<Integer> queue = new linkedList<>();
        System.out.println("队首元素" + queue.peek());
        
        queue.offer(5);
        queue.offer(4);
        queue.offer(3);
        
        // 删除队首元素,而 peek 只是返回队首元素,不删除。
        queue.poll();
        
        System.out.println("队首元素" + queue.peek());
        System.out.println("队列的长度:"+queue.size());

    }    


}

队列在其他知识的运用:

1.可用在操作系统中的进程调度的算法,先来先服务,只考虑了等待时间,未考虑运行时间,因为如果是一个运行时间较短的后来,那么刚好碰到前面的长作业,需要将长作业运行完,才能执行下一步,不利于短作业的实现。

2.操作系统中的页面淘汰策略淘汰在内存里面停留时间最长的页面,实现简单,但对于特定序列的页面效率低下。

3.实现生产者-消费者模型:当队列为空的时候,从队头取数据会被阻塞,因为没有数据可取,直到有了数据才能返回。

而如果队列已经满了的话,那么那么插入数据的操作就会被阻塞,直到队列中有空位置,才继续插入,然后返回。

4.当线程池没有空闲线程的时候,新的任务请求线程,那么一般有两种处理策略:直接拒绝,让他排队去。

而这时,如果是用链表实现请求任务的队列,那么可以实现一个无限排队的队列,针对对时间敏感的系统,基于链表实现是不合适的,而如果用数组实现,那么如果超出数组的界限的时候,将会被拒绝,这种对响应时间敏感的更合适,但是设置一个合理的长度,却是个问题。

参考:

算法第四版中队列的链表实现

leetcode 中队列的篇章

极客时间数据结构与算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值