队列
队列是一种特殊的线性结构,它只允许在队列的首部(head/front)进行删除操作,这称为“出队”,而在队列的尾部(tail/rear)进行插入操作,这称为“入队”。当队列中没有元素时(即head == tail),称为空队列。比如买票,每个排队买票的窗口就是一个队列。在这个队列当中,新来的人总是站在队列的最后面,来得越早的人越靠前,也就是越早能买到票,我们称为“先进先出”(First In First Out, FIFO)原则。🚘
队列的特性
队列是一个有序列表,可以用数组 或是链表 来实现
在队首删除元素,在队尾插入元素
“先进先出”(FIFO)原则
队列的实现
用数组实现的队列叫作顺序队列 ,用链表实现的队列叫作链式队列 。
数组模拟队列
队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图, 其中 maxSize 是该队列的最大容量。
因为队列的输出、输入是分别从前后端来处理,因此需要两个变量 front及rear分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear则是随着数据输入而改变,如图所示:
数组模拟队列的数组使用一次便不可使用,即使数组还有空闲空间,也无法往队列里添加,这是就需要进行数据的搬移,复用性不好,可以替换为环形队列。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 import java.util.Scanner;public class ArrayQueueTest { public static void main (String[] args) { ArrayQueue queue = new ArrayQueue(3 ); char key = ' ' ; Scanner scanner = new Scanner(System.in); boolean loop = true ; while (loop) { System.out.println("(s)show: 显示队列" ); System.out.println("(e)exit: 退出程序" ); System.out.println("(a)add: 添加数据到队列" ); System.out.println("(g)get: 从队列取出数据" ); System.out.println("(h)head: 查看队列头的数据" ); key = scanner.next().charAt(0 ); switch (key) { case 's' : queue.showQueue(); break ; case 'a' : System.out.println("输入一个数:" ); int value = scanner.nextInt(); queue.addQueue(value); break ; case 'g' : try { int res = queue.getQueue(); System.out.println("取出的数据是" + res); }catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'h' : try { int res = queue.headQueue(); System.out.println("队列头的数据是" + res); }catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'e' : scanner.close(); loop = false ; break ; default : break ; } } System.out.println("程序退出!" ); } } class ArrayQueue { private int maxSize; private int front; private int rear; private int [] arr; public ArrayQueue (int arrMaxSize) { maxSize = arrMaxSize; arr = new int [maxSize]; front = -1 ; rear = -1 ; } public boolean isFull () { return rear == maxSize - 1 ; } public boolean isEmpty () { return rear == front; } public void addQueue (int n) { if (isFull()) { System.out.println("队列满,不能加入数据" ); return ; } rear++; arr[rear] = n; } public int getQueue () { if (isEmpty()) { throw new RuntimeException("队列空,不能取数据" ); } front++; return arr[front]; } public void showQueue () { if (isEmpty()) { System.out.println("队列空" ); return ; } for (int i = 0 ; i < arr.length; i++) { System.out.printf("arr[%d]=%d\n" ,i, arr[i]); } } public int headQueue () { if (isEmpty()) { throw new RuntimeException("队列空" ); } return arr[front + 1 ]; } }
链表模拟队列
基于链表的实现,需要head 和 tail 两个指针。分别指向链表的第一个和最后一个结点。
入队时,tail->next= new_node, tail = tail->next;出队时,head = head->next。
图示如下:
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 import java.util.Scanner;public class LinkedListQueueDemo { public static void main (String[] args) { LinkedListQueue queue = new LinkedListQueue(); char key = ' ' ; Scanner scanner = new Scanner(System.in); boolean loop = true ; while (loop) { System.out.println("(s)show: 显示队列" ); System.out.println("(e)exit: 退出程序" ); System.out.println("(a)add: 添加数据到队列" ); System.out.println("(g)get: 从队列取出数据" ); System.out.println("(h)head: 查看队列头的数据" ); key = scanner.next().charAt(0 ); switch (key) { case 's' : queue.showQueue(); break ; case 'a' : System.out.println("输入一个数:" ); int value = scanner.nextInt(); queue.addQueue(value); break ; case 'g' : try { Object res = queue.getQueue(); System.out.println("取出的数据是" + res); }catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'h' : try { Object res = queue.headQueue(); System.out.println("队列头的数据是" + res); }catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'e' : scanner.close(); loop = false ; break ; default : break ; } } System.out.println("程序退出!" ); } } class LinkedListQueue { private Node front; private Node rear; private int size; public LinkedListQueue () { size = 0 ; front = rear = null ; } private static class Node { private Node next; private Object data; public Node (Object data, Node next) { this .data = data; this .next = next; } } public boolean isEmpty () { return size == 0 ; } public void addQueue (Object data) { if (isEmpty()) { Node newNode = new Node(data, null ); front = newNode; rear = newNode; }else { rear.next = new Node(data, null ); rear = rear.next; } size++; } public Object getQueue () { if (isEmpty()) { throw new RuntimeException("队列空,不能取数据" ); } Object value = front.data; front = front.next; if (front == null ) { rear = null ; } size--; return value; } public void showQueue () { if (isEmpty()) { System.out.println("队列空" ); return ; } Node node = front; while (node != null ) { System.out.print(node.data + "->" ); node = node.next; } System.out.println(); } public Object headQueue () { if (isEmpty()) { throw new RuntimeException("队列空" ); } return front.data; } }
数组模拟环形队列 思路如下:
front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素 front 的初始值 = 0
rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定. rear 的初始值 = 0
当队列满时,条件是 (rear + 1) % maxSize == front 【满】
对队列为空的条件, rear == front 空
当我们这样分析, 队列中有效的数据的个数 (rear + maxSize - front) % maxSize // rear = 1 front = 0
我们就可以在原来的队列上修改得到,一个环形队列
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 import java.util.Scanner;public class CircleArrayDemo { public static void main (String[] args) { CircleQueue queue = new CircleQueue(4 ); char key = ' ' ; Scanner scanner = new Scanner(System.in); boolean loop = true ; while (loop) { System.out.println("(s)show: 显示队列" ); System.out.println("(e)exit: 退出程序" ); System.out.println("(a)add: 添加数据到队列" ); System.out.println("(g)get: 从队列取出数据" ); System.out.println("(h)head: 查看队列头的数据" ); key = scanner.next().charAt(0 ); switch (key) { case 's' : queue.showQueue(); break ; case 'a' : System.out.println("输入一个数:" ); int value = scanner.nextInt(); queue.addQueue(value); break ; case 'g' : try { int res = queue.getQueue(); System.out.println("取出的数据是" + res); }catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'h' : try { int res = queue.headQueue(); System.out.println("队列头的数据是" + res); }catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'e' : scanner.close(); loop = false ; break ; default : break ; } } System.out.println("程序退出!" ); } } class CircleQueue { private int maxSize; private int front; private int rear; private int [] arr; public CircleQueue (int arrMaxSize) { maxSize = arrMaxSize; arr = new int [maxSize]; } public boolean isFull () { return (rear + 1 ) % maxSize == front; } public boolean isEmpty () { return rear == front; } public void addQueue (int n) { if (isFull()) { System.out.println("队列满,不能加入数据" ); return ; } arr[rear] = n; rear = (rear + 1 ) % maxSize; } public int getQueue () { if (isEmpty()) { throw new RuntimeException("队列空,不能取数据" ); } int value = arr[front]; front = (front + 1 ) % maxSize; return value; } public void showQueue () { if (isEmpty()) { System.out.println("队列空" ); return ; } for (int i = front; i < front + size(); i++) { System.out.printf("arr[%d]=%d\n" ,i % maxSize, arr[i % maxSize]); } } public int size () { return (rear + maxSize - front) % maxSize; } public int headQueue () { if (isEmpty()) { throw new RuntimeException("队列空" ); } return arr[front]; } }
😎😎 加油!