队列是一种特殊的线性表,只能在头尾两端进行操作,遵循先进先出的原则。下面是一些队列接口的简单实现。
双向链表实现基本队列
package com.ldg.queue;
import com.ldg.doubles.LinkedList;
/***
* 队列:首部执行出队 尾部执行入队 只在首尾进行操作 所以底层用双向链表来实现 时间复杂度很小
*
* @author Administrator
*
*/
public class Queue<T> {
// 双向链表实现
private LinkedList<T> linkedList = new LinkedList<>();
// 入队
public void enQueue(T element) {
linkedList.add(element);
}
// 出队
public T deQueue() {
return linkedList.remove(0);
}
// 判断是队列否为空
public Boolean isEmpty() {
return size() == 0;
}
// 队列大小
public int size() {
return linkedList.getSize();
}
// 获取首部元素
public T front() {
return linkedList.get(0);
}
// 清空队列
public void clear() {
linkedList.clear();
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Size:" + size() + " Queue[");
for (int i = 0; i < size(); i++) {
if (i != 0) {
stringBuilder.append(",");
}
stringBuilder.append(linkedList.get(i));
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}
栈实现基本队列
package 栈;
import java.util.Stack;
//声明两个stack
public class _232_用栈实现队列 {
// 一个用来push
Stack<Integer> inStack = new Stack<Integer>();
// 一个用来peek pop
Stack<Integer> outStack = new Stack<Integer>();
// 入队
public void push(int x) {
inStack.push(x);
}
// 出队
public int pop() {
// 判断outStack是不是为空
if (outStack.isEmpty()) {
// 将inStack的元素放入outStack中
while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
}
}
return outStack.pop();
}
// 查看首部元素
public int peek() {
if (outStack.isEmpty()) {
// 将inStack的元素放入outStack中
while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
}
}
return outStack.peek();
}
//判断队列是否为空
public boolean empty() {
return inStack.isEmpty() && outStack.isEmpty();
}
}
**双端队列 **
双端队列指的是在首部和尾部都可以进行出队和入队的操作。
package com.ldg.deque;
import com.ldg.doubles.LinkedList;
/**
* 双端队列:在首尾都可以执行出队和入队 双向链表实现
*
* @author Administrator
*
* @param <T>
*/
public class Deque<T> {
// 双向链表
private LinkedList<T> linkedList = new LinkedList<>();
// 队列大小
public int size() {
return linkedList.getSize();
}
// 从尾部入队
public void enQueueRear(T element) {
linkedList.add(element);
}
// 从首部入队
public void enQueueFront(T element) {
linkedList.add(0, element);
}
// 从尾部出队
public T deQueueRear() {
return linkedList.remove(size() - 1);
}
// 从首部出队
public T deQueueFront() {
return linkedList.remove(0);
}
public boolean isEmpty() {
return size() == 0;
}
// 获取首部元素
public T front() {
return linkedList.get(0);
}
// 获取尾部元素
public T rear() {
return linkedList.get(size() - 1);
}
// 清空队列
public void clear() {
linkedList.clear();
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Size:" + size() + " DeQueue[");
for (int i = 0; i < size(); i++) {
if (i != 0) {
stringBuilder.append(",");
}
stringBuilder.append(linkedList.get(i));
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}
双端队列的测试
循环队列
循环队列:底层用优化后的动态数组实现 所以有循环的感觉
ps:就是在首部出队时不需要将第二个元素到尾部元素一个个往前移动
ps:在尾部入队时不一定要一味往后加 ,可以利用数组前面的空间
这样方法实现的复杂度也是O(1)
package com.ldg.circleQueue;
//循环队列:底层用优化后的动态数组实现 所以有循环的感觉
// ps:就是在首部出队时不需要将第二个元素到尾部元素一个个往前移动
// ps:在尾部入队时不一定要一味往后加 ,可以利用数组前面的空间
//这样方法实现的复杂度也是O(1)
@SuppressWarnings("unchecked")
public class CircleQueue<T> {
// 首部序号
private int frist;
private int size;
// 数组初始长度
private final static int length = 10;
// 声明一个泛型数组
@SuppressWarnings("unused")
private T[] elements;
// 初始化数组
public CircleQueue() {
elements = (T[]) new Object[length];
}
// 入队 (size+frist)%elements.length取模运算可以利用到前面的空间
public void enQueue(T element) {
isAddCapcity();
// elements[(size + frist) % elements.length] = element;
elements[index(size)] = element;
size++;
}
// 出队 (frist + 1) % elements.length 找到第首部下一个元素
public T deQueue() {
T old = elements[index(0)];
elements[index(0)] = null;
frist = index(1);
size--;
return old;
}
// 判断队列是否为空
public Boolean isEmpty() {
return size == 0;
}
// 获取队列元素个数
public int size() {
return size;
}
// 查看首部元素的值
public T front() {
return elements[frist];
}
// 清空队列
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
frist = 0;
}
// 是将整个数组打印
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Size:" + elements.length + " Frist:" + frist + " CircleQueue[");
for (int i = 0; i < elements.length; i++) {
if (i != 0) {
stringBuilder.append(",");
}
stringBuilder.append(elements[i]);
}
stringBuilder.append("]");
return stringBuilder.toString();
}
// 判断是否扩容
private void isAddCapcity() {
if ((size + 1) > elements.length) {
int newCapcity = elements.length << 1;
T[] newElemenTs = (T[]) new Object[newCapcity];
for (int i = 0; i < elements.length; i++) {
// newElemenTs[i] = elements[(frist + i) % elements.length];
newElemenTs[i] = elements[index(i)];
}
frist = 0;
elements = newElemenTs;
}
}
// 索引映射:将逻辑索引映射成真实索引 并返回
private int index(int index) {
// 取模运算可以优化一下
// return (frist+index)%elements.length;
// 因为 0<=length<2elements.length
int length = frist + index;
return length >= elements.length ? length - elements.length : length;
}
}
循环队列的测试
循环双端队列
循环双端队列:底层用优化后的动态数组实现 ,可以在首部和尾部进行入队,出队的操作。
package com.ldg.circleDeque;
/**
* 循环双端队列:底层用优化后的动态数组实现 ,可以在首部和尾部进行入队,出队的操作。
*
* @author Administrator
*
*/
@SuppressWarnings("unchecked")
public class CircleDeque<T> {
// 首部序号
private int frist;
private int size;
// 数组初始长度
private final static int length = 10;
// 声明一个泛型数组
@SuppressWarnings("unused")
private T[] elements;
// 初始化数组
public CircleDeque() {
elements = (T[]) new Object[length];
}
//获取队列长度
public int size() {
return size;
}
//尾部入队
public void enQueueRear(T element) {
isAddCapcity();
// elements[(size + frist) % elements.length] = element;
elements[index(size)] = element;
size++;
}
//首部入队
public void enQueueFront(T element) {
isAddCapcity();
// 首部元素序号为0参考
frist = index(-1);
elements[frist] = element;
size++;
}
//尾部出队
public T deQueueRear() {
T old = elements[index(size - 1)];
elements[index(size - 1)] = null;
size--;
return old;
}
//首部出队
public T deQueueFront() {
T old = elements[index(0)];
elements[index(0)] = null;
frist = index(1);
size--;
return old;
}
//判断是队列是否为空
public boolean isEmpty() {
return size() == 0;
}
//查看首部元素
public T front() {
return elements[index(0)];
}
//查看尾部元素
public T rear() {
return elements[index(size - 1)];
}
// 清空队列
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
frist = 0;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Size:" + size() + " frist" + frist + " CircleDeQueue[");
for (int i = 0; i < elements.length; i++) {
if (i != 0) {
stringBuilder.append(",");
}
stringBuilder.append(elements[i]);
}
stringBuilder.append("]");
return stringBuilder.toString();
}
// 判断是否扩容
private void isAddCapcity() {
if ((size + 1) > elements.length) {
int newCapcity = elements.length << 1;
T[] newElemenTs = (T[]) new Object[newCapcity];
for (int i = 0; i < elements.length; i++) {
// newElemenTs[i] = elements[(frist + i) % elements.length];
newElemenTs[i] = elements[index(i)];
}
frist = 0;
elements = newElemenTs;
}
}
// 索引映射:将逻辑索引映射成真实索引 并返回
private int index(int index) {
if (index < 0) {
// 当在首部入队时要考虑的
return frist > 0 ? frist + index : index + elements.length;
} else {
// 其他情况
// 取模运算可以优化一下
// return (frist+index)%elements.length;
// 因为 0<=length<2elements.length
int length = frist + index;
return length >= elements.length ? length - elements.length : length;
}
}
}
循环双端队列测试
就这样吧。