特点:先进先出 后进后出

队列是一个有序的列表

  1. 可以通过数组跟列表进行实现(数组实现叫顺序存储,链表实现叫做链式存储)
  2. 遵循先入先出的原则

    数组实现

    分析:

  3. 数组需要记录数组的最大容量

  4. 需要队列的前端与后端标记变量 前端随着数据的输入而改变 后端随着数据的输出而改变

代码实现:(没有优化 数组不是环形对列 一次性对列)

  1. public class ArrayQueueDome {
  2. public static void main(String[] args) {
  3. ArrayQueue arr = new ArrayQueue(5);
  4. arr.addArray(5);
  5. arr.addArray(4);
  6. arr.addArray(3);
  7. arr.addArray(-1);
  8. arr.addArray(1);
  9. arr.addArray(1);
  10. // 看看head数据是啥
  11. System.out.println(arr.putArray());
  12. System.out.println(arr.peek());
  13. for (int i = 0; i < 6; i++)
  14. System.out.println(arr.putArray());
  15. }
  16. }
  17. //建立一个数组队列
  18. class ArrayQueue {
  19. // 定义最大容量
  20. private int maxSize;
  21. // 队列的头尾
  22. private int rear;
  23. private int front;
  24. // 创建队列
  25. private int[] arr;
  26. public int[] getArr() {
  27. return arr;
  28. }
  29. // 创建队列的构造器
  30. public ArrayQueue(int arrMaxSize) {
  31. this.maxSize = arrMaxSize;
  32. this.arr = new int[maxSize];
  33. this.front = -1; // 指向头部的前一个位置
  34. this.rear = -1;// 指向尾部的位置(就是队列的最后一个数据)
  35. }
  36. // 判断队列是否已经满了
  37. public boolean isFull() {
  38. return maxSize == rear + 1;
  39. }
  40. // 判断队列是否为空
  41. public boolean isEmpty() {
  42. return front == rear;
  43. }
  44. // 添加数据到队列(添加数据时变得只有rear 尾)
  45. public void addArray(int i) {
  46. // 添加时要先进行判断
  47. if (isFull()) {
  48. System.out.println("full!!!!");
  49. } else {
  50. rear++;
  51. arr[rear] = i;
  52. }
  53. }
  54. // 输出信息 (输出数据时变得只有front 头)
  55. public int putArray() {
  56. // 先进行判断队列是否为空
  57. if (isEmpty()) {
  58. throw new RuntimeException("empty!!!!");
  59. } else {
  60. front++;
  61. return arr[front];
  62. }
  63. }
  64. // 显示队列的头数据是什么
  65. public int peek() {
  66. return arr[front + 1];
  67. }
  68. }

需要进行环形的更改:
代码如下:

  1. import java.util.Scanner;
  2. public class ArrayQueueDome {
  3. public static void main(String[] args) {
  4. // 测试一把
  5. System.out.println("测试数组模拟环形队列的案例~~~");
  6. // 创建一个环形队列
  7. CircleArray queue = new CircleArray(5); // 说明设置 4, 其队列的有效数据最大是 3
  8. char key = ' '; // 接收用户输入
  9. Scanner scanner = new Scanner(System.in);//
  10. boolean loop = true;
  11. // 输出一个菜单
  12. while (loop) {
  13. System.out.println("s(show): 显示队列");
  14. System.out.println("e(exit): 退出程序");
  15. System.out.println("a(add): 添加数据到队列");
  16. System.out.println("g(get): 从队列取出数据");
  17. System.out.println("h(head): 查看队列头的数据");
  18. key = scanner.next().charAt(0);// 接收一个字符
  19. switch (key) {
  20. case 's':
  21. queue.look();
  22. break;
  23. case 'a':
  24. System.out.println("输出一个数");
  25. int value = scanner.nextInt();
  26. queue.addArray(value);
  27. break;
  28. case 'g': // 取出数据
  29. try {
  30. int res = queue.putArray();
  31. System.out.printf("取出的数据是%d\n", res);
  32. } catch (Exception e) {
  33. // TODO: handle exception
  34. System.out.println(e.getMessage());
  35. }
  36. break;
  37. case 'h': // 查看队列头的数据
  38. try {
  39. int res = queue.peek();
  40. System.out.printf("队列头的数据是%d\n", res);
  41. } catch (Exception e) {
  42. // TODO: handle exception
  43. System.out.println(e.getMessage());
  44. }
  45. break;
  46. case 'e': // 退出
  47. scanner.close();
  48. loop = false;
  49. break;
  50. default:
  51. break;
  52. }
  53. }
  54. System.out.println("程序退出~~");
  55. }
  56. }
  57. //建立一个数组队列
  58. class CircleArray {
  59. // 定义最大容量
  60. private int maxSize;
  61. // 队列的头尾
  62. private int rear;
  63. private int front;
  64. // 创建队列
  65. private int[] arr;
  66. public int[] getArr() {
  67. return arr;
  68. }
  69. // 创建队列的构造器
  70. public CircleArray(int arrMaxSize) {
  71. this.maxSize = arrMaxSize;
  72. this.arr = new int[maxSize];
  73. this.front = 0; // 指向头部的前一个位置
  74. this.rear = 0;// 指向尾部的位置(就是队列的最后一个数据)
  75. }
  76. // 判断队列是否满
  77. public boolean isFull() {
  78. return (rear + 1) % maxSize == front;
  79. }
  80. // 判断队列是否为空
  81. public boolean isEmpty() {
  82. return front == rear;
  83. }
  84. // 添加数据到队列(添加数据时变得只有rear 尾)
  85. public void addArray(int i) {
  86. // 添加时要先进行判断
  87. if (isFull()) {
  88. System.out.println("full!!!!");
  89. } else {
  90. arr[rear] = i;
  91. // 将 rear 后移, 这里必须考虑取模
  92. rear = (rear + 1) % maxSize;
  93. }
  94. }
  95. // 输出信息 (输出数据时变得只有front 头)
  96. public int putArray() {
  97. // 先进行判断队列是否为空
  98. if (isEmpty()) {
  99. throw new RuntimeException("empty!!!!");
  100. } else {
  101. int value = arr[front];
  102. front = (front + 1) % maxSize;
  103. return value;
  104. }
  105. }
  106. // 显示队列的头数据是什么
  107. public int peek() {
  108. return arr[front];
  109. }
  110. // 遍历数组
  111. public void look() {
  112. // 遍历
  113. if (isEmpty()) {
  114. System.out.println("队列空的,没有数据~~");
  115. return;
  116. }
  117. // 思路:从 front 开始遍历,遍历多少个元素
  118. // 动脑筋
  119. for (int i = front; i < front + size(); i++) {
  120. System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
  121. }
  122. }
  123. // 求出当前队列有效数据的个数
  124. public int size() {
  125. return (rear + maxSize - front) % maxSize;
  126. }
  127. }

链表实现

单:

  1. package cn.corgy.queue;
  2. public class LinkedListQueueDome {
  3. public static void main(String[] args) {
  4. HeroNode hero1 = new HeroNode(1, "王超", "hehehe");
  5. HeroNode hero2 = new HeroNode(2, "1超", "2222");
  6. HeroNode hero3 = new HeroNode(3, "2超", "11111");
  7. HeroNode hero5 = new HeroNode(3, "2超", "修改的");
  8. HeroNode hero4 = new HeroNode(4, "3超", "333333");
  9. SingleLinkedList singleLinkedList = new SingleLinkedList();
  10. singleLinkedList.addByOrder(hero1);
  11. singleLinkedList.addByOrder(hero3);
  12. singleLinkedList.addByOrder(hero2);
  13. singleLinkedList.addByOrder(hero2);
  14. singleLinkedList.show();
  15. System.out.println("************************************");
  16. singleLinkedList.updateNode(hero5);
  17. singleLinkedList.show();
  18. System.out.println("************************************");
  19. singleLinkedList.deleteNode(2);
  20. singleLinkedList.show();
  21. }
  22. }
  23. //创建单向链表
  24. class SingleLinkedList {
  25. // 创建单向列表的头部 不进行数据的储存
  26. private HeroNode head = new HeroNode(0, "", "");
  27. /**
  28. * 无序添加 与添加的顺序有关
  29. *
  30. * @param heroNode 添加的节点
  31. */
  32. public void add(HeroNode heroNode) {
  33. // 添加一个临时变量到辅助遍历全部的链表
  34. HeroNode temp = head;
  35. while (true) {
  36. // 如果遍历到最后一个节点 next就会显示null
  37. if (temp.next == null) {
  38. break;
  39. }
  40. // 没有找到向后移动进行索引
  41. temp = temp.next;
  42. }
  43. // 跳出后进行赋值
  44. temp.next = heroNode;
  45. }
  46. /**
  47. * 有序添加 根据数据编号进行排序
  48. *
  49. * @param heroNode 需要添加的节点
  50. */
  51. public void addByOrder(HeroNode heroNode) {
  52. HeroNode temp = head;
  53. while (true) {
  54. // 如果添加的数据已经存在 打印信息 直接退出
  55. if (temp.no == heroNode.no) {
  56. System.out.println("需要添加的节点" + heroNode.no + "已经存在");
  57. return;
  58. }
  59. if (temp.next == null) {
  60. break;
  61. }
  62. // 遍历 满足temp.no < heroNode.no && heroNode.no <temp.next.no
  63. // 进行添加操作
  64. if ((temp.no < heroNode.no && heroNode.no < temp.next.no)) {
  65. HeroNode temp2 = temp.next;
  66. temp.next = heroNode;
  67. heroNode.next = temp2;
  68. return;
  69. }
  70. // 加一进位
  71. temp = temp.next;
  72. }
  73. temp.next = heroNode;
  74. }
  75. /**
  76. * 修改节点信息
  77. */
  78. public void updateNode(HeroNode heroNode) {
  79. // 判断是否空
  80. if (head.next == null) {
  81. System.out.println("链表为空~");
  82. return;
  83. }
  84. // 通过遍历全部找到相同的编号值
  85. HeroNode temp = head;
  86. while (true) {
  87. if (temp.next == null) {
  88. System.out.println("沒有你要修改的节点");
  89. return;
  90. }
  91. if (temp.next.no == heroNode.no) {
  92. temp.next.name = heroNode.name;
  93. temp.next.nickname = heroNode.nickname;
  94. return;
  95. }
  96. // 进位
  97. temp = temp.next;
  98. }
  99. }
  100. /**
  101. * 根据编号删除某个节点
  102. */
  103. public void deleteNode(int no) {
  104. HeroNode temp = head;
  105. while (true) {
  106. if (temp.next == null) {
  107. break;
  108. }
  109. // 删除的条件
  110. if (no == temp.next.no) {
  111. if (temp.next.next == null) {
  112. temp.next = null;
  113. return;
  114. } else {
  115. // 跳过中间那个直接指向下一个
  116. temp.next = temp.next.next;
  117. return;
  118. }
  119. }
  120. temp = temp.next;
  121. }
  122. System.out.println("没有这个节点");
  123. }
  124. /**
  125. * 链表的展示
  126. */
  127. public void show() {
  128. // 先判断列表是否为空
  129. if (head.next == null) {
  130. System.out.println("队列为空");
  131. return;
  132. }
  133. HeroNode temp = head.next;
  134. while (true) {
  135. // 如果遍历到最后一个节点 next就会显示null
  136. if (temp == null) {
  137. break;
  138. }
  139. System.out.println(temp);
  140. // 没有找到向后移动进行索引
  141. temp = temp.next;
  142. }
  143. }
  144. }
  145. // 定义 HeroNode,每个 HeroNode 对象就是一个节点
  146. class HeroNode {
  147. public int no;
  148. public String name;
  149. public String nickname;
  150. public HeroNode next; // 指向下一个节点
  151. // 构造器
  152. public HeroNode(int no, String name, String nickname) {
  153. this.no = no;
  154. this.name = name;
  155. this.nickname = nickname;
  156. }
  157. // 为了显示方法,我们重新 toString
  158. @Override
  159. public String toString() {
  160. return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
  161. }
  162. }
  1. 求单链表的有效节点:

    1. /**
    2. * 统计链表的有效个数 有头的话要去头
    3. *
    4. * @param head 头节点
    5. * @return 返回有效的个数
    6. */
    7. public static int getLength(HeroNode head) {
    8. if (head.next == null)
    9. System.out.println("empty!!");
    10. HeroNode temp = head.next;
    11. int index = 0;
    12. while (true) {
    13. index++;
    14. if (temp.next == null)
    15. break;
    16. temp = temp.next;
    17. }
    18. return index;
    19. }
    20. }
  2. 查找单链表中倒数第K个节点

    1. /**
    2. * 查找单链表中倒数第K个节点 调用了前面的获取有效个数的方法
    3. *
    4. * @param head 头节点
    5. * @param lastNo 倒数的第K个值
    6. * @return 返回节点信息
    7. */
    8. public static HeroNode findLastIndexNode(HeroNode head, int lastNo) {
    9. if (head.next == null) {
    10. System.out.println("链表为空");
    11. return null;
    12. }
    13. // 先获取所需链表的有效长度
    14. int size = getLength(head);
    15. // 获取要查询的节点信息(size-lastNo)
    16. int index = size - lastNo;
    17. if (lastNo <= 0 || lastNo > size) {
    18. return null;
    19. }
    20. // 获取
    21. HeroNode cur = head.next;
    22. for (int i = 0; i < index; i++) {
    23. cur = cur.next;
    24. }
    25. return cur;
    26. }
  3. 单链表的反转

    1. /**
    2. * 但链表进行翻转 <br>
    3. * 思路:<br>
    4. * 1.创建一个新的头做新的对象 <br>
    5. * 2.将原本的链表依次向新的头进行插入<br>
    6. * 3.将老的头的next替代新的头的next
    7. *
    8. * @param head 头节点
    9. */
    10. public static void reverseQueue(HeroNode head) {
    11. // 其中空链表跟单节点列表不用进行翻转
    12. if (head.next == null || head.next.next == null)
    13. return;
    14. HeroNode reverseNode = new HeroNode(0, "", "");
    15. HeroNode cur = head.next;
    16. HeroNode next = null;
    17. // 遍历需要反转的列表进行定位
    18. while (cur != null) {
    19. next = cur.next;
    20. cur.next = reverseNode.next;
    21. reverseNode.next=cur;
    22. cur = next;
    23. }
    24. head.next = reverseNode.next;
    25. }
    26. }
  4. 从尾到头打印单链表

  5. 合并两个单链表 合并后依旧要有序


双**:

根据单列表进行了简单的修改 即可变成双向的列表

  1. package cn.corgy.queue;
  2. public class DoubleLinkedQueueDome {
  3. public static void main(String[] args) {
  4. DoubleHeroNode hero1 = new DoubleHeroNode(1, "王超", "hehehe");
  5. DoubleHeroNode hero2 = new DoubleHeroNode(2, "1超", "2222");
  6. DoubleHeroNode hero3 = new DoubleHeroNode(3, "2超", "11111");
  7. DoubleHeroNode hero5 = new DoubleHeroNode(3, "2超", "修改的");
  8. DoubleHeroNode hero4 = new DoubleHeroNode(4, "3超", "333333");
  9. DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
  10. doubleLinkedList.addByOrder(hero1);
  11. doubleLinkedList.addByOrder(hero3);
  12. doubleLinkedList.addByOrder(hero4);
  13. doubleLinkedList.addByOrder(hero2);
  14. doubleLinkedList.show();
  15. System.out.println("************************************");
  16. doubleLinkedList.updateNode(hero5);
  17. doubleLinkedList.show();
  18. System.out.println("************************************");
  19. doubleLinkedList.deleteNode(4);
  20. doubleLinkedList.show();
  21. }
  22. }
  23. //创建双向链表
  24. class DoubleLinkedList {
  25. // 创建单向列表的头部 不进行数据的储存
  26. private DoubleHeroNode head = new DoubleHeroNode(0, "", "");
  27. public DoubleHeroNode getHead() {
  28. return head;
  29. }
  30. /**
  31. * 遍历双向链表
  32. */
  33. public void show() {
  34. // 先判断列表是否为空
  35. if (head.next == null) {
  36. System.out.println("队列为空");
  37. return;
  38. }
  39. DoubleHeroNode temp = head.next;
  40. while (true) {
  41. // 如果遍历到最后一个节点 next就会显示null
  42. if (temp == null) {
  43. break;
  44. }
  45. System.out.println(temp);
  46. // 没有找到向后移动进行索引
  47. temp = temp.next;
  48. }
  49. }
  50. /**
  51. * 无序添加到列表的最后 与添加的顺序有关
  52. *
  53. * @param heroNode 添加的节点
  54. */
  55. public void add(DoubleHeroNode heroNode) {
  56. // 添加一个临时变量到辅助遍历全部的链表
  57. DoubleHeroNode temp = head;
  58. while (true) {
  59. // 如果遍历到最后一个节点 next就会显示null
  60. if (temp.next == null) {
  61. break;
  62. }
  63. // 没有找到向后移动进行索引
  64. temp = temp.next;
  65. }
  66. // 跳出后进行赋值
  67. temp.next = heroNode;
  68. heroNode.pre = temp; // 双向的精髓
  69. }
  70. /**
  71. * 有序添加 根据数据编号进行排序
  72. *
  73. * @param heroNode 需要添加的节点
  74. */
  75. public void addByOrder(DoubleHeroNode heroNode) {
  76. DoubleHeroNode temp = head;
  77. while (true) {
  78. // 如果添加的数据已经存在 打印信息 直接退出
  79. if (temp.no == heroNode.no) {
  80. System.out.println("需要添加的节点" + heroNode.no + "已经存在");
  81. return;
  82. }
  83. if (temp.next == null) {
  84. break;
  85. }
  86. // 遍历 满足temp.no < heroNode.no && heroNode.no <temp.next.no
  87. // 进行添加操作
  88. if ((temp.no < heroNode.no && heroNode.no < temp.next.no)) {
  89. DoubleHeroNode temp2 = temp.next;
  90. // 前一个的下一节点为插入
  91. temp.next = heroNode;
  92. // 插入节点的下一个位为后一个
  93. heroNode.next = temp2;
  94. // 插入节点的前一个节点为前一个
  95. heroNode.pre = temp;
  96. // 插入节点的后一个的前一个节点为插入
  97. temp2.pre = heroNode;
  98. return;
  99. }
  100. // 加一进位
  101. temp = temp.next;
  102. }
  103. temp.next = heroNode;
  104. }
  105. /**
  106. * 修改节点信息
  107. */
  108. public void updateNode(DoubleHeroNode heroNode) {
  109. // 判断是否空
  110. if (head.next == null) {
  111. System.out.println("链表为空~");
  112. return;
  113. }
  114. // 通过遍历全部找到相同的编号值
  115. DoubleHeroNode temp = head;
  116. while (true) {
  117. if (temp.next == null) {
  118. System.out.println("沒有你要修改的节点");
  119. return;
  120. }
  121. if (temp.next.no == heroNode.no) {
  122. temp.next.name = heroNode.name;
  123. temp.next.nickname = heroNode.nickname;
  124. return;
  125. }
  126. // 进位
  127. temp = temp.next;
  128. }
  129. }
  130. /**
  131. * 根据编号删除某个节点
  132. */
  133. public void deleteNode(int no) {
  134. DoubleHeroNode temp = head;
  135. while (true) {
  136. if (temp.next == null) {
  137. break;
  138. }
  139. // 删除的条件
  140. if (no == temp.next.no) {
  141. if (temp.next.next == null) {// 如果是最后一各节点话直接进行删除
  142. temp.next = null;
  143. return;
  144. } else {
  145. // 跳过中间那个直接指向下一个
  146. temp.next = temp.next.next;
  147. temp.next.next.pre = temp;
  148. return;
  149. }
  150. }
  151. temp = temp.next;
  152. }
  153. System.out.println("没有这个节点");
  154. }
  155. }
  156. //定义 HeroNode,每个 HeroNode 对象就是一个节点 (定义双向的链表)
  157. class DoubleHeroNode {
  158. public int no;
  159. public String name;
  160. public String nickname;
  161. public DoubleHeroNode next; // 指向下一个节点
  162. public DoubleHeroNode pre; // 指向前一个节点
  163. // 构造器
  164. public DoubleHeroNode(int no, String name, String nickname) {
  165. this.no = no;
  166. this.name = name;
  167. this.nickname = nickname;
  168. }
  169. // 为了显示方法,我们重新 toString
  170. @Override
  171. public String toString() {
  172. return "DoubleHeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
  173. }
  174. }