• 算法3:链表实现队列


    • 我们在算法2中已经使用Node实现了链表的功能。此时,我们进一步对链表进行延伸。题目:“使用单链表实现队列,实现先进先出的功能”。
    • 解题思路: 既然是链表,那么必然有一个头节点和尾结点。先进先出,那就是从头节点取数据,从尾节点添加数据
    • 复制代码
      package code.code_02;
      
      /**
       * 使用单链表设计出队列
       */
      public class SingleNodeQueue {
      
          private Node head; //当前队列的头
          private Node tail;   //当前队列的尾
          private int size;
      
          public SingleNodeQueue () {
              head = null;
              tail = null;
              size = 0;
          }
          //用于单链表的节点
          private class Node {
              public V data;
              public Node next;
      
              Node (V _data){
                  this.data = _data;
              }
              public V getData() {
                  return data;
              }
          }
      
          public boolean isEmpty () {
              return size == 0 ? true : false;
          }
      
          public int size () {
              return size;
          }
      
          //获取链表的头
          public V peek ()
          {
              Node node = null;
              Node next = null;
              if (head == null) {
                  System.out.println("当前队列还没有设置元素");
                  tail = null;
                  return null;
              }
              else {
                  //提前记录下头节点和头节点的持有的下一个节点的引用
                  node = head;
                  next = head.next;
                  //将头节持有的下一个节点引用释放掉
                  head.next = null;
                  //因为头节点的下一个节点之前被记录过
                  //此时,头节点head会释放掉原始的内存对象
                  // 并且来到新的头节点位置(也就是之前的第二个节点)
                  head = next;
                  size--;
              }
              //因为node是局部变量,方法调用完成以后,node所对应的内存对象会被回收
              return node.getData();
          }
      
          //获取链表的头, 此方法是对peek进行的优化
          public V peek1 ()
          {
              V value = null;
              if (head == null) {
                  System.out.println("当前队列还没有设置元素");
                  tail = null;
                  return null;
              }
              else {
                  value = head.getData();
                  /**
                   * 此处优化非常的美妙, 一句话抵得上peek()方法中的4句
                   *  node = head;
                   *  next = head.next;
                   *  head.next = null;
                   *  head = next;
                   */
                  head = head.next;
                  size--;
              }
              return value;
          }
      
          //设置链表元素
          public void offer (V data) {
              Node node = new Node(data);
              if (tail == null) {
                  head = node;
                  tail = node;
              }
              else {
                  tail.next = node;
                  tail = node;
              }
              size++;
          }
      
          public static void main(String[] args) {
              SingleNodeQueue queue = new SingleNodeQueue<>();
              queue.offer(1);
              queue.offer(2);
              queue.offer(3);
              System.out.println(queue.size());
      
              do {
                  System.out.println("获取单向队列的元素: " + (queue.peek()));
                  System.out.println("测试当前队列长度" + queue.size());
              }while(queue.size() > 0);
      
      
              System.out.println("================测试泛型,优化后的peek================================");
      
              SingleNodeQueue queue1 = new SingleNodeQueue<>();
              queue1.offer("test 1");
              queue1.offer("test 2");
              queue1.offer("test 3");
              System.out.println(queue1.size());
      
              do {
                  System.out.println("获取单向队列的元素: " + (queue1.peek1()));
                  System.out.println("测试当前队列长度" + queue1.size());
              }while(queue1.size() > 0);
      
      
          }
      }
      复制代码

      打印结果如下:

      复制代码
      3
      获取单向队列的元素: 1
      测试当前队列长度2
      获取单向队列的元素: 2
      测试当前队列长度1
      获取单向队列的元素: 3
      测试当前队列长度0
      ================测试泛型,优化后的peek================================
      3
      获取单向队列的元素: test 1
      测试当前队列长度2
      获取单向队列的元素: test 2
      测试当前队列长度1
      获取单向队列的元素: test 3
      测试当前队列长度0
      
      Process finished with exit code 0
      复制代码

       

    • 下面继续延伸。题目 “使用双向链表的知识,设计一个双向队列。要求是队列的头和队列的尾,都可以添加数据并且取数据
      复制代码
      package code.code_02;
      
      /**
       * 使用双链表设计一个双向队列,使对象的头节点和尾节点都可以
       * 添加/弹出节点元素
       */
      public class DoubleNodeQueue {
      
          private Node head; //当前队列的头
          private Node tail;   //当前队列的尾
          private int size;
      
          public DoubleNodeQueue() {
              head = null;
              tail = null;
              size = 0;
          }
      
          //双链表
          private static class Node {
              public V data;
              public Node last;
              public Node next;
      
              Node (V _data){
                  this.data = _data;
              }
              public V getData() {
                  return data;
              }
          }
      
          public boolean isEmpty () {
              return size == 0 ? true : false;
          }
      
          public int size () {
              return size;
          }
      
          //从队列头部取元素
          public V peekHead ()
          {
              V value = null;
              if (head == null) {
                  System.out.println("当前队列还没有设置元素");
                  tail = null;
                  return value;
              }
              else {
                  value = head.getData();
                  //此时, 队列的第二个元素成为新的
                  //头节点head
                  head = head.next;
                  size--;
              }
              return value;
          }
      
          //从队列尾部取元素
          public V peekTail ()
          {
              V value = null;
              if (tail == null) {
                  System.out.println("当前队列还没有设置元素");
                  return value;
              }
              else {
                  value = tail.getData();
                  //如果头和尾相等,说明队列只有一个元素
                  //等价与tail.last == null;
                  if (head == tail) {
                      head = null;
                      tail = null;
                  } else {
                      tail = tail.last;
                      tail.next = null;
                  }
                  size--;
              }
              return value;
          }
      
          //从尾节点添加队列元素
          public void pushTail (V data) {
              Node node = new Node<>(data);
              if (head == null) {
                  head = node;
                  tail = node;
              }
              else {
                  tail.next = node;
                  //双向链表组成的队列新增部分
                  //当前节点需要持有之前的尾结点对象引用
                  node.last = tail;
                  //添加完成以后, 尾节点需要移动到新添加的节点node处,
                  //此时,新添加的node成为尾节点tail
                  tail = node;
              }
              size++;
          }
      
          //从头节点添加队列元素
          public void pushHead (V data) {
              Node node = new Node<>(data);
              if (head == null) {
                  head = node;
                  tail = node;
              }
              else {
                  /**
                   * 从头结点添加队列新元素,那么之前的头节点变成第二个元素
                   * 因此,之前的头结点head.last需要持有新节点对象引用node
                   * 新节点node.next需要持有之间的头结点
                   */
                  head.last = node;
                  node.next = head;
                  //添加完成以后, 头节点需要移动到新添加的节点node处,
                  //此时,新添加的node成为头节点head
                  head = node;
              }
              size++;
          }
      
          public static void main(String[] args) {
              DoubleNodeQueue queue = new DoubleNodeQueue<>();
              //demo1, 测试从尾部添加元素,头部获取元素。 先进先出
              queue.pushTail(1);
              queue.pushTail(2);
              queue.pushTail(3);
      
              System.out.println("=============测试双向队列尾部添加元素,头部取元素—----先进先出==========================");
              do {
                  System.out.println("获取单向队列的元素: " + (queue.peekHead()));
              }while(queue.size > 0);
      
              //demo2, 测试从尾部添加元素,从尾部获取元素
              queue.pushTail(-1);
              queue.pushTail(-2);
              queue.pushTail(-3);
      
              System.out.println("=============测试双向队列尾部添加元素,尾部获取元素—----后进先出==========================");
              do {
                  System.out.println("获取单向队列的元素: " + (queue.peekTail()));
              }while(queue.size > 0);
      
              //demo3, 测试从头部添加元素,头部取元素
              queue.pushHead(11);
              queue.pushHead(12);
              queue.pushHead(13);
              System.out.println("=============测试双向队列头部添加元素,头部获取元素—----后进先出==================");
              do {
                  System.out.println("获取单向队列的元素: " + (queue.peekHead()));
              }while(queue.size > 0);
      
              //demo4, 测试从头部添加元素, 尾部取元素
              queue.pushHead(21);
              queue.pushHead(22);
              queue.pushHead(23);
              System.out.println("=============测试双向队列头部添加元素,尾部获取元素—----先进先出==========================");
              do {
                  System.out.println("获取单向队列的元素: " + (queue.peekTail()));
              }while(queue.size > 0);
      
          }
      }
      复制代码

      打印信息如下:

    • 复制代码
      =============测试双向队列尾部添加元素,头部取元素—----先进先出==========================
      获取单向队列的元素: 1
      获取单向队列的元素: 2
      获取单向队列的元素: 3
      =============测试双向队列尾部添加元素,尾部获取元素—----后进先出==========================
      获取单向队列的元素: -3
      获取单向队列的元素: -2
      获取单向队列的元素: -1
      =============测试双向队列头部添加元素,头部获取元素—----后进先出==================
      获取单向队列的元素: 13
      获取单向队列的元素: 12
      获取单向队列的元素: 11
      =============测试双向队列头部添加元素,尾部获取元素—----先进先出==========================
      获取单向队列的元素: 21
      获取单向队列的元素: 22
      获取单向队列的元素: 23
      
      Process finished with exit code 0
      复制代码

       

    • 有了单链表的实现,相信双链表实现也能理解。如果此算法有问题,说明链表的知识掌握的还不够牢靠,请先看算法2的相关知识 https://www.cnblogs.com/chen1-kerr/p/16905803.html
  • 相关阅读:
    手把手教你ubuntu下移植MJPG-streamer
    css3 初步了解
    云计算:掌控未来,一触即发!
    【Vuforia+Unity】AR04-地面、桌面平面识别功能(Ground Plane Target)
    如何在Spring Boot框架下实现高效的Excel服务端导入导出?
    新的类功能 --- c++11
    社招前端一面经典手写面试题集锦
    怎么查看线程的状态及interrupt优雅的关闭线程和interrupt()、interrupted()、isInterrupted()的作用以及区别在哪?
    PHP:类的基本概念
    web网页设计——体育气步枪射击主题(5页面)带图片轮播特效(HTML+CSS) ~学生网页设计作业源码
  • 原文地址:https://www.cnblogs.com/chen1-kerr/p/16909869.html