06-java实现队列

06-java实现队列

本人git https://github.com/bigeyes-debug/Algorithm

一丶队列

  • 队列是特殊的线性结构,只能在头尾两端操作
  • 队尾入队,队头出队,
  • FIFO
  • 队列可以用动态数组和双向链表实现
  • 优先使用双向链表,主要在头尾进行操作

二丶队列的接口设计(和之前的线性结构类似)

public class Queue<E> {
    // 使用双向链表实现队列
    private List<E> list = new LinkedList<>();
    // 元素的数量
    public int size();
    // 是否为空
    public boolean isEmpty();
    // 入队
    public void enQueue(E element);
    // 出队
    public E deQueue();
    // 获取队列的头元素
    public E front();
}

三丶队列的实现

public class Queue<E> {
    private List<E> list = new LinkedList<>();
	
    public int size() {
        return list.size();
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    public void enQueue(E element) {
        list.add(element);
    }

    public E deQueue() {
        return list.remove(0);
    }

    public E front() {
        return list.get(0);
    }
}

四丶双端队列

  • 双端队列,头可以入队出队,尾可以入队出队

五、双端队列的接口设计&实现

public class Deque<E> {
    private List<E> list = new LinkedList<>();
	
    // 元素的数量
    public int size() {
        return list.size();
    }
    // 是否为空
    public boolean isEmpty() {
        return list.isEmpty();
    }
    // 从队头出队
    public E deQueueFront() {
        return list.remove(0);
    }
    // 从队头入队
    public void enQueueFront(E element) {
        list.add(0, element);
    }
    // 从队尾入队
    public void enQueueRear(E element) {
        list.add(element);
    }
    // 从队尾出队
    public E deQueueRear() {
        return list.remove(list.size() - 1);
    }
    // 获取队列的头元素
    public E front() {
        return list.get(0);
    }
    // 获取队列的尾元素
    public E rear() {
        return list.get(list.size() - 1);
    }
}

六丶循环队列

  • 队列内部实现也可以用动态数组实现,并且将各项接口优化到O(1)的时间复杂度, 这个用数组实现并优化之后的队列就叫做: 循环队列。

七、循环队列的接口设计

public class CircleQueue<E> {
    // 记录第0个元素的索引
    private int front;
    // 当前队列存储的元素个数
    private int size;
    // 用来存储元素的数组
    private E[] elements;
    // 当前队列存储的元素数量
    public int size();
    // 当前队列是否为空
    public boolean isEmpty();
    // 入队
    public void enQueue(E element);
    // 出队
    public E deQueue();
    // 查看索引为0的元素
    public E front();
}

八丶循环队列的实现

3.1 构造方法

public class ArrayList<E> {
    private E[] elements;
    // 设置elements数组默认的初始化空间
    private static final int DEFAULT_CAPACITY = 10;
	
    public CircleQueue() {
        elements = (E[]) new Object[DEFAULT_CAPACITY];
    }
}

3.2 入队

  • 入队前需要考虑两个问题:队列是否需要扩容和计算入队实际索引。

3.2.1 动态扩容

动态数组的扩容方法拿来直接用即可

private void ensureCapacity(int capacity) {
    int oldCapacity = elements.length;
    if (oldCapacity >= capacity) return;
		
    // 新容量为旧容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1); //位运算
    E[] newElements = (E[]) new Object[newCapacity];
    for (int i = 0; i < size; i++) {
        newElements[i] = elements[index(i)];
    }
    elements = newElements;
		
    // 重置front
    front = 0;
}

3.2.2 索引计算

  • 获取实际索引公式 (front+index)%elements.length;
     private int index(int index) {
          return (front +index)%elements.length;
     }

入队代码

public void enQueue(E element) {
    // 数组扩容判断
    ensureCapacity(size + 1);
    // 索引计算,并赋值
    elements[index(size)] = element;
    // size加一
    size++;
}

3.3 出队

  • 一定要更新front指针,一定不要忘
public E deQueue() {
    // 获取出队元素
    E frontElement = elements[front];
    // 将索引位置致空
    elements[front] = null;
    // 更新font
    front = index(1);
    // size减一
    size--;
    // 返回出队元素
    return frontElement;
}

posted @ 2020-08-14 09:52  大眼侠  阅读(315)  评论(0编辑  收藏  举报