java之队列基础知识及实现

队列:只允许在一端进行插入操作(队尾),在另一端进行删除操作(队头)。因此具有先进先出的特性。

注:数据结构中的队列跟我们日常排队所产生的队列相似,都是从队尾进入队列,从队头出队列。

 

 下面是分别用链表和顺序表实现的队列基本操作。

1、链表:因为单链表的尾部需要通过遍历链表来找到该结点,而队列的入队操作又需要频繁的在链表的尾部插入数据,因此需要一个tail(尾部结点的引用)来指向链表的最后一个结点,每次直接访问tail引用的值就可以进行入队操作,其时间复杂度为O(1)。

 1 public class MyQueue {
 2     // 链表实现队列
 3     static class Node{
 4         int val;
 5         Node next;
 6         Node(int val){
 7             this.val = val;
 8             next = null;
 9         }
10     }
11     Node head = null;
12     Node tail = null;
13     public void push(int val){
14         Node tmp = new Node(val);
15         if(head == tail){
16             head = tmp;
17             tail = tmp;
18         }else{
19             tail.next = tmp;
20             tail = tail.next;
21         }
22     }
23     public Integer pop(){
24         if(head == null)
25             return null;
26         int number = head.val;
27         if(head == tail){
28             head = null;
29             tail = null;
30             return number;
31         }
32         head = head.next;
33         return number;
34     }
35     public Integer top(){
36         if(head == null)
37             return null;
38         return head.val;
39     }
40 }

注:与上一篇栈不同的是,结点的结构类我定义成了静态内部类,若不加static关键字修饰,则没有办法创建这个类的实例对象,加入static关键字则表示该内部类与MyQueue类相关而不是与MyQueue的实例对象有关。

2、顺序表:因为顺序表是一块已经开辟好大小的空间,进行常规的入队出队操作必定会产生下面的现象:

 

 此时再入队一个元素4,队尾指针会指向顺序表后面的一块空间,再进行入队操作的时候就会产生数组访问越界的异常,其解决办法就是将其看作是一个首尾相接的环状空间,即我们所说的循环队列:

 

循环队列有一个缺点就是判空和判满的时候都是head == tail,没有办法很好的判断是满还是空,针对于这个问题,有两种常用的解决办法:

(1)牺牲一个元素的空间。队尾指向最后一个元素的下一个位置,当 head == tail 时则表示队列为空,若(tail +1)%data.length == head 时则表示队列为满。

(2)创建一个整型变量size,用来记录队列中的元素个数,当 size == data.length 时,则表示队列满了;size == 0 则表示队列为空。

我习惯上使用第二种方法解决这个问题,其代码如下:

public class MyQueue {
    private int[] data = new int[100];
    private int head = 0;
    private int tail = 0;
    private int size;
    public void push(int val){
        if(size == data.length){
            int[] newdata = new int[size+15];
            for(int i = 0; i<data.length;i++){
                newdata[i] = data[i];
            }
            data = newdata;
        }
        data[tail] = val;
        tail = (tail+1)%data.length;
    }
    public Integer pop(){
        if(size == 0)
            return null;
        int number = data[head];
        head = (head+1)%data.length;
        return number;
    }
    public Integer top(){
        if(size == 0)
            return null;
        return data[head];
    }
}

 

 

ps:若有不正确的地方或有什么疑问,欢迎提出,一起探讨~

posted @ 2021-03-09 11:04  一帆小白  阅读(339)  评论(0编辑  收藏  举报