• 算法3:链表实现双端队列


    • 我们在算法2中已经使用Node实现了链表的功能。此时,我们进一步对链表进行延伸。题目:“使用单链表实现队列,实现先进先出的功能”。
    • 解题思路: 既然是链表,那么必然有一个头节点和尾结点。先进先出,那就是从头节点取数据,从尾节点添加数据
      1. package code.code_02;
      2. /**
      3. * 使用单链表设计出队列
      4. */
      5. public class SingleNodeQueue {
      6. private Node head; //当前队列的头
      7. private Node tail; //当前队列的尾
      8. private int size;
      9. public SingleNodeQueue () {
      10. head = null;
      11. tail = null;
      12. size = 0;
      13. }
      14. //用于单链表的节点
      15. private class Node {
      16. public V data;
      17. public Node next;
      18. Node (V _data){
      19. this.data = _data;
      20. }
      21. public V getData() {
      22. return data;
      23. }
      24. }
      25. public boolean isEmpty () {
      26. return size == 0 ? true : false;
      27. }
      28. public int size () {
      29. return size;
      30. }
      31. //获取链表的头
      32. public V peek ()
      33. {
      34. Node node = null;
      35. Node next = null;
      36. if (head == null) {
      37. System.out.println("当前队列还没有设置元素");
      38. tail = null;
      39. return null;
      40. }
      41. else {
      42. //提前记录下头节点和头节点的持有的下一个节点的引用
      43. node = head;
      44. next = head.next;
      45. //将头节持有的下一个节点引用释放掉
      46. head.next = null;
      47. //因为头节点的下一个节点之前被记录过
      48. //此时,头节点head会释放掉原始的内存对象
      49. // 并且来到新的头节点位置(也就是之前的第二个节点)
      50. head = next;
      51. size--;
      52. }
      53. //因为node是局部变量,方法调用完成以后,node所对应的内存对象会被回收
      54. return node.getData();
      55. }
      56. //获取链表的头, 此方法是对peek进行的优化
      57. public V peek1 ()
      58. {
      59. V value = null;
      60. if (head == null) {
      61. System.out.println("当前队列还没有设置元素");
      62. tail = null;
      63. return null;
      64. }
      65. else {
      66. value = head.getData();
      67. /**
      68. * 此处优化非常的美妙, 一句话抵得上peek()方法中的4句
      69. * node = head;
      70. * next = head.next;
      71. * head.next = null;
      72. * head = next;
      73. */
      74. head = head.next;
      75. size--;
      76. }
      77. return value;
      78. }
      79. //设置链表元素
      80. public void offer (V data) {
      81. Node node = new Node(data);
      82. if (tail == null) {
      83. head = node;
      84. tail = node;
      85. }
      86. else {
      87. tail.next = node;
      88. tail = node;
      89. }
      90. size++;
      91. }
      92. public static void main(String[] args) {
      93. SingleNodeQueue queue = new SingleNodeQueue<>();
      94. queue.offer(1);
      95. queue.offer(2);
      96. queue.offer(3);
      97. System.out.println(queue.size());
      98. do {
      99. System.out.println("获取单向队列的元素: " + (queue.peek()));
      100. System.out.println("测试当前队列长度" + queue.size());
      101. }while(queue.size() > 0);
      102. System.out.println("================测试泛型,优化后的peek================================");
      103. SingleNodeQueue queue1 = new SingleNodeQueue<>();
      104. queue1.offer("test 1");
      105. queue1.offer("test 2");
      106. queue1.offer("test 3");
      107. System.out.println(queue1.size());
      108. do {
      109. System.out.println("获取单向队列的元素: " + (queue1.peek1()));
      110. System.out.println("测试当前队列长度" + queue1.size());
      111. }while(queue1.size() > 0);
      112. }
      113. }

      打印信息如下:


      3
      获取单向队列的元素: 1
      测试当前队列长度2
      获取单向队列的元素: 2
      测试当前队列长度1
      获取单向队列的元素: 3
      测试当前队列长度0
      ================测试泛型,优化后的peek================================
      3
      获取单向队列的元素: test 1
      测试当前队列长度2
      获取单向队列的元素: test 2
      测试当前队列长度1
      获取单向队列的元素: test 3
      测试当前队列长度0

      Process finished with exit code 0
       

    • 下面继续延伸。题目 “使用双向链表的知识,设计一个双向队列。要求是队列的头和队列的尾,都可以添加数据并且取数据
      1. package code1.code_02;
      2. /**
      3. * 使用双链表设计一个双向队列,使对象的头节点和尾节点都可以
      4. * 添加/弹出节点元素
      5. */
      6. public class DoubleNodeQueue04 {
      7. private Node head; //当前队列的头
      8. private Node tail; //当前队列的尾
      9. private int size;
      10. public DoubleNodeQueue04() {
      11. head = null;
      12. tail = null;
      13. size = 0;
      14. }
      15. //双链表
      16. private static class Node {
      17. public V data;
      18. public Node last;
      19. public Node next;
      20. Node (V _data){
      21. this.data = _data;
      22. }
      23. public V getData() {
      24. return data;
      25. }
      26. }
      27. public boolean isEmpty () {
      28. return size == 0;
      29. }
      30. public int size () {
      31. return size;
      32. }
      33. //从队列头部取元素
      34. public V peekHead ()
      35. {
      36. V value = null;
      37. if (head == null) {
      38. System.out.println("当前队列还没有设置元素");
      39. return value;
      40. }
      41. value = head.getData();
      42. if (head == tail) {
      43. head = null;
      44. tail = null;
      45. }
      46. else {
      47. //此时, 队列的第二个元素成为新的
      48. //头节点head
      49. head = head.next;
      50. }
      51. size--;
      52. return value;
      53. }
      54. //从队列尾部取元素
      55. public V peekTail ()
      56. {
      57. V value = null;
      58. if (tail == null) {
      59. System.out.println("当前队列还没有设置元素");
      60. return value;
      61. }
      62. value = tail.getData();
      63. //如果头和尾相等,说明队列只有一个元素等价与tail.last == null;
      64. if (head == tail) {
      65. head = null;
      66. tail = null;
      67. } else {
      68. tail = tail.last;
      69. tail.next = null;
      70. }
      71. size--;
      72. return value;
      73. }
      74. //从尾节点添加队列元素
      75. public void pushTail (V data) {
      76. Node node = new Node<>(data);
      77. if (head == null) {
      78. head = node;
      79. tail = node;
      80. }
      81. else {
      82. tail.next = node;
      83. //双向链表组成的队列新增部分
      84. //当前节点需要持有之前的尾结点对象引用
      85. node.last = tail;
      86. //添加完成以后, 尾节点需要移动到新添加的节点node处,
      87. //此时,新添加的node成为尾节点tail
      88. tail = node;
      89. }
      90. size++;
      91. }
      92. //从头节点添加队列元素
      93. public void pushHead (V data) {
      94. Node node = new Node<>(data);
      95. if (head == null) {
      96. head = node;
      97. tail = node;
      98. }
      99. else {
      100. /**
      101. * 从头结点添加队列新元素,那么之前的头节点变成第二个元素
      102. * 因此,之前的头结点head.last需要持有新节点对象引用node
      103. * 新节点node.next需要持有之间的头结点
      104. */
      105. head.last = node;
      106. node.next = head;
      107. //添加完成以后, 头节点需要移动到新添加的节点node处,
      108. //此时,新添加的node成为头节点head
      109. head = node;
      110. }
      111. size++;
      112. }
      113. public static void main(String[] args) {
      114. DoubleNodeQueue04 queue = new DoubleNodeQueue04<>();
      115. //demo1, 测试从尾部添加元素,头部获取元素。 先进先出
      116. queue.pushTail(1);
      117. queue.pushTail(2);
      118. queue.pushTail(3);
      119. System.out.println("=============测试双向队列尾部添加元素,头部取元素—----先进先出==========================");
      120. do {
      121. System.out.println("获取单向队列的元素: " + (queue.peekHead()));
      122. }while(queue.size > 0);
      123. //demo2, 测试从尾部添加元素,从尾部获取元素
      124. queue.pushTail(-1);
      125. queue.pushTail(-2);
      126. queue.pushTail(-3);
      127. System.out.println("=============测试双向队列尾部添加元素,尾部获取元素—----后进先出==========================");
      128. do {
      129. System.out.println("获取单向队列的元素: " + (queue.peekTail()));
      130. }while(queue.size > 0);
      131. //demo3, 测试从头部添加元素,头部取元素
      132. queue.pushHead(11);
      133. queue.pushHead(12);
      134. queue.pushHead(13);
      135. System.out.println("=============测试双向队列头部添加元素,头部获取元素—----后进先出==================");
      136. do {
      137. System.out.println("获取单向队列的元素: " + (queue.peekHead()));
      138. }while(queue.size > 0);
      139. //demo4, 测试从头部添加元素, 尾部取元素
      140. queue.pushHead(21);
      141. queue.pushHead(22);
      142. queue.pushHead(23);
      143. System.out.println("=============测试双向队列头部添加元素,尾部获取元素—----先进先出==========================");
      144. do {
      145. System.out.println("获取单向队列的元素: " + (queue.peekTail()));
      146. }while(queue.size > 0);
      147. }
      148. }

      打印信息如下:

     
    =============测试双向队列尾部添加元素,头部取元素—----先进先出==========================
    获取单向队列的元素: 1
    获取单向队列的元素: 2
    获取单向队列的元素: 3
    =============测试双向队列尾部添加元素,尾部获取元素—----后进先出==========================
    获取单向队列的元素: -3
    获取单向队列的元素: -2
    获取单向队列的元素: -1
    =============测试双向队列头部添加元素,头部获取元素—----后进先出==================
    获取单向队列的元素: 13
    获取单向队列的元素: 12
    获取单向队列的元素: 11
    =============测试双向队列头部添加元素,尾部获取元素—----先进先出==========================
    获取单向队列的元素: 21
    获取单向队列的元素: 22
    获取单向队列的元素: 23

    Process finished with exit code 0
     

  • 相关阅读:
    【工具】电脑网络连接正常,但是有些页面无法登录,如何解决?
    【LeetCode】Day177-统计一致字符串的数目
    通过内网穿透,在Windows 10系统下搭建个人《我的世界》服务器公网联机
    图Graph的存储、图的广度优先搜索和深度优先搜索(待更新)
    【C++】C++职工信息管理系统
    [LeetCode]剑指 Offer 48. 最长不含重复字符的子字符串
    前端人员不要只知道KFC,你应该了解 BFC、IFC、GFC 和 FFC
    【数据集的制作】VOC2007数据集格式的转换(voc2yolo)与划分
    node.js+室内装修风格选择系统 毕业设计-附源码211552
    【Spring Cloud】多数据源配置
  • 原文地址:https://blog.csdn.net/chen_yao_kerr/article/details/127955694