| 主文章(数据结构的索引目录—进不去就说明我还没写完) |
|---|
| https://blog.youkuaiyun.com/grd_java/article/details/122377505 |
| 模拟数据结构的网站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html |
|---|
| 源码(码云):https://gitee.com/yin_zhipeng/data_structures_and_algorithms_in_java.git |
|---|
| 队列 |
|---|
- 一种先入先出的数据结构
- 每次访问数据,都只能从队列的头部访问,插入数据只能从队列尾部访问(普通队列)
1.数组实现(Array Implementation)
| 动画演示 |
|---|
- 入队列
- 出队列
- 循环队列
| 思路 |
|---|
- 创建数组作为队列,定义capacity表示队列(数组)大小,有效的存储空间只有capacity-1个,需要保留一个空间做判断(具体看上图循环队列)
- 定义front和tail表示队列的头指针和尾指针
- 假设队列9个空间,既然要实现循环,那么第10个元素,应该插入到第一个位置(第一个位置为空的话)
- 通过10%capacity=1,可以算出第10个元素应该插入到第一位,但是如果1位置有元素,表示不能插入,队列满
- 如果front==rear表示队列为空,
- 如果(tail+1)%capacity== front 表示队列满,不能继续插入数据
- 后移一位下标(front/tail+ 1)%capacity
- 有效元素个数tail + capacity - head; 加capacity是因为tail-head可能是负数比如-1,而%capacity的值是循环队列的下标,,-3%2=-1,不是+1,会下标越界
- 当我们想取到队列第三个值的时候,(head+3)%capacity即可
| 代码:com/yzpnb/data_structures/queues/array_implementation/ArrayQueue.java |
|---|
- 运行效果
public class ArrayQueue<T> {
private T[] queue;//数组作为队列
private int capacity;//队列容量
private int head;//头指针
private int tail;//尾部指针,指向末尾元素的下一个位置,如果tail的下一个位置就是head,则不允许插入数据
//构造
public ArrayQueue(int capacity){
queue = newArray(capacity);//队列
this.capacity = capacity;//容量
head = 0;//头指针
tail = 0;//尾指针
}
/**
* 构建数组,直接转型为T(泛型)
* @param size 大小
*/
private T[] newArray(int size){
return (T[])new Object[size];
}
//入队列
public boolean enQueue(T o){
queue[tail] = o;
int newTail = (tail+1) % capacity;//指针后移一位
if(newTail == head)
throw new IndexOutOfBoundsException("Queue full!!!队列满");
tail = newTail;
return true;
}
//出队列
public T deQueue(){
if(head == tail)
throw new IndexOutOfBoundsException("Queue empty!!!队列为空");
T deQueue = queue[head];//获取队列头数据
queue[head] = null;//置为null
head = (head + 1) % capacity;//下标后移
return deQueue;
}
//获取指定下标结点,以用户角度看,下标不是循环的
public T get(int i){
int size = size();//获取有效个数
if(i<0 || i > size) {
final String msg = "Index " + i + ", queue size " + size;
throw new IndexOutOfBoundsException(msg+"下标超出队列当前元素数量");
}
int index = (head + i) % capacity;//找到用户想要元素的下标
return queue[index];
}
//有效元素个数tail + capacity - head; 加capacity是因为tail-head可能是负数比如-1
public int size(){
// Can't use % here because it's not mod: -3 % 2 is -1, not +1.
int diff = tail - head;
if (diff < 0)//如果是负数
diff += capacity;//+capacity
return diff;
}
public void printer(){
System.out.print("队列:");
int size = size();
for(int i = 0;i<size;i++){
System.out.print(queue[((head+i)%capacity)]+" ");
}
System.out.println();
}
public static void main(String[] args) {
ArrayQueue<Integer> queue = new ArrayQueue<Integer>(4);
queue.enQueue(1);queue.enQueue(2);queue.enQueue(3);
queue.printer();
System.out.println("出队列"+queue.deQueue());
System.out.println("出队列"+queue.deQueue());
queue.printer();
queue.enQueue(4);
queue.printer();
System.out.println("第二个元素:"+queue.get(1));
}
}
2.链表实现(Linked List Implementation
| 动画演示 |
|---|
- 入队列
- 出队列
| 实现思路 |
|---|
- 定义head和tail分别指向队头和队尾结点,构造队列时,直接创建一个空结点作为头
- 插入结点时,tail指向的结点的后缀,指向新插入结点,tail指向新插入结点
- 出队列,返回当前头结点(队列第二个结点,第一个是辅助),head指向当前头结点的后继
| 代码:com/yzpnb/data_structures/queues/linked_list_implementation/LinkedQueue.java |
|---|
- 运行效果
import java.util.Collection;
public class LinkedQueue<E> {
/**
* Linked list node class 单链表结点
*/
static class Node<E> {
E item;
Node<E> next;//后继
Node(E x) { item = x; }
}
private final int capacity;//最大容量
transient Node<E> head;//头
private transient Node<E> last;//尾
/**
* 构造队列
*/
public LinkedQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
//根据集合构造
public LinkedQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
int n = 0;
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
enqueue(e);
++n;
}
}
//入队列
public void enqueue(E e) {
Node<E> node = new Node<E>(e);
last = last.next = node;
}
public E dequeue(){
E peek = peek();
head = head.next;
return peek;
}
//获取头结点(队列第二个结点)
public E peek() {
Node<E> first = head.next;
if (first == null)
return null;
else
return first.item;
}
public void printer(){
System.out.print("队列:");
Node<E> first = head.next;
while(first != null){
System.out.print(first.item+" ");
first = first.next;
}
System.out.println();
}
public static void main(String[] args) {
LinkedQueue<Integer> queue = new LinkedQueue<Integer>(4);
queue.enqueue(1);queue.enqueue(2);queue.enqueue(3);
queue.printer();
System.out.println("出队列"+queue.dequeue());
System.out.println("出队列"+queue.dequeue());
queue.printer();
System.out.println("入队列4");
queue.enqueue(4);
queue.printer();
}
}
本文详细介绍了如何使用数组和链表实现队列数据结构,包括入队、出队操作,并提供了Java代码示例。通过动画演示加深了理解,同时展示了两种实现方式的不同之处。







3万+

被折叠的 条评论
为什么被折叠?



