什么是队列(基础概念/顺序队列/链式队列/动态扩容/循环队列)含示例代码

定义

如何理解“队列”

什么是队列(基础概念/顺序队列/链式队列/动态扩容/循环队列)含示例代码_第1张图片

  • 队列是一个操作受限的线性表
  • 具有先进先出的性质
  • 跟「栈」一样,分为顺序队列和链式队列

用数组实现的顺序队列和用链表实现的链式队列

  • 主要要关注队满和队空条件
  • 线性队列 > 队满:tail == n | 队空(没有数据):head == tail
  • 链式队列 > 队满:无界 | 队空:head.next = tail
  • 线性队列的数据搬迁:当队满时,可以进行数据搬迁来利用空余的数组空间

动态扩容

什么是队列(基础概念/顺序队列/链式队列/动态扩容/循环队列)含示例代码_第2张图片

  • 跟顺序链表一样,顺序队列也可支持动态扩容
  • 如果在每次出队时,进行数据搬迁,则出队的时间复杂度就会变为 O(n)。
  • 为了避免上述情况,只需要在入队空间不足时,进行数据搬迁即可

 

使用循环队列避免数据搬移操作

扩容时的数据搬迁操作,会导致 O(n) 的时间复杂度

什么是队列(基础概念/顺序队列/链式队列/动态扩容/循环队列)含示例代码_第3张图片

  • 循环队列将数组看成是一个「环」,主要关注其中的队满条件
  • 对满:(head + 1) % n == tail
  • 队空:head == tail

 

特殊队列:阻塞队列和并发队列

什么是队列(基础概念/顺序队列/链式队列/动态扩容/循环队列)含示例代码_第4张图片  什么是队列(基础概念/顺序队列/链式队列/动态扩容/循环队列)含示例代码_第5张图片

  • 阻塞队列:典型的生产者 - 消费者模型。
    • 就是在队列为空的时候,从队头取数据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回。
  • 并发队列:多线程情况下,线程安全的队列

 

实现

顺序队列

public class ArrayQueue implements Queue {

    private final String[] queue;
    private final int capacity;
    private int head;
    private int tail;

    public ArrayQueue(int capacity) {
        this.capacity = capacity;
        queue = new String[capacity];
    }

    @Override
    public boolean enqueue(String item) {
        if (capacity == tail) return false;
        queue[tail++] = item;
        return true;
    }

    @Override
    public String dequeue() {
        if (head == tail) return null;
        return queue[head++];
    }

    public static void main(String[] args) {
        ArrayQueue queue = new ArrayQueue(5);
        Assert.assertNull(queue.dequeue());

        queue.enqueue("item1");
        queue.enqueue("item2");
        Assert.assertEquals("item1", queue.dequeue());
        Assert.assertEquals("item2", queue.dequeue());

        Assert.assertNull(queue.dequeue());
    }
}

链式队列

public class LinkedQueue implements Queue {

    private ListNode tail = null;
    private ListNode head = null;
    private int size;

    @Override
    public boolean enqueue(String item) {
        ListNode newNode = new ListNode(item);
        if (size == 0) {
            head = newNode;
            tail = newNode;
        } else {
            this.tail.next = newNode;
            this.tail = this.tail.next;
        }
        size++;
        return true;
    }

    @Override
    public String dequeue() {
        if (size == 0) return null;
        String val = head.val;
        head = head.next;
        size--;
        return val;
    }

    public static void main(String[] args) {
        LinkedQueue queue = new LinkedQueue();
        Assert.assertNull(queue.dequeue());

        Assert.assertTrue(queue.enqueue("item1"));
        Assert.assertTrue(queue.enqueue("item2"));
        Assert.assertEquals("item1", queue.dequeue());
        Assert.assertEquals("item2", queue.dequeue());

        Assert.assertNull(queue.dequeue());
    }
}


class ListNode {
    String val;
    ListNode next;

    ListNode(String x) {
        val = x;
    }
}

动态扩容

public class DynamicArrayQueue implements Queue {
    private final String[] queue;
    private final int capacity;
    private int head;
    private int tail;

    public DynamicArrayQueue(int capacity) {
        this.capacity = capacity;
        queue = new String[capacity];
    }

    /**
     * 会在容量不足时,进行数据搬迁
     */
    @Override
    public boolean enqueue(String item) {
        if (capacity == tail) {
            //队列是满的,没法搬迁
            if (head == 0) return false;
            for (int i = head; i < tail; i++) {
                queue[i - head] = queue[head];
            }
            //tail = 长度 head = 队头
            tail = tail - head;
            head = 0;
        }
        queue[tail++] = item;
        return true;
    }

    @Override
    public String dequeue() {
        if (head == tail) return null;
        return queue[head++];
    }

    public static void main(String[] args) {
        Queue queue = new DynamicArrayQueue(3);
        Assert.assertNull(queue.dequeue());

        Assert.assertTrue(queue.enqueue("item1"));
        Assert.assertEquals("item1", queue.dequeue());
        Assert.assertTrue(queue.enqueue("item2"));
        Assert.assertEquals("item2", queue.dequeue());
        Assert.assertTrue(queue.enqueue("item3"));
        Assert.assertEquals("item3", queue.dequeue());
        Assert.assertTrue(queue.enqueue("item4"));
        Assert.assertEquals("item4", queue.dequeue());
    }
}

循环队列

public class CycleArrayQueue implements Queue {

    private final String[] queue;
    private final int capacity;
    private int head;
    private int tail;

    public CycleArrayQueue(int capacity) {
        this.capacity = capacity;
        queue = new String[capacity];
    }

    @Override
    public boolean enqueue(String item) {
        //队满条件 (head + 1) % n == tail
        if ((head + 1) % capacity == tail) return false;
        queue[tail] = item;
        tail = (tail + 1) % capacity;
        return true;
    }

    @Override
    public String dequeue() {
        //队空 head == tail
        if (head == tail) return null;
        String value = queue[head];
        head = (head + 1) % capacity;
        return value;
    }

    public static void main(String[] args) {
        CycleArrayQueue queue = new CycleArrayQueue(5);
        Assert.assertNull(queue.dequeue());

        Assert.assertTrue(queue.enqueue("item1"));
        Assert.assertEquals("item1", queue.dequeue());
        Assert.assertTrue(queue.enqueue("item2"));
        Assert.assertEquals("item2", queue.dequeue());
        Assert.assertTrue(queue.enqueue("item3"));
        Assert.assertEquals("item3", queue.dequeue());
        Assert.assertTrue(queue.enqueue("item4"));
        Assert.assertEquals("item4", queue.dequeue());

    }
}

 

你可能感兴趣的:(算法)