zoukankan      html  css  js  c++  java
  • 日常学习随笔-数组、单链表、双链表三种形式实现队列结构的基本操作(源码注释)

    一、队列结构(本文侧重于源码实现,基础理论不多赘述)

      和栈一样,队列(queue)也是表,然而使用队列是在一端插入数据,在另一端删除数据。这里插入就是入队(enqueue),删除就是(dequeue).

           队列的核心思想是:“先进先出”

      队列的实现方式有很多中,常见的有

      (1)数组方式

      (2)单链表方式

      (3)双链表方式

      (4)其他

    二、数组方式实现队列结构(详细注释说明)

       我学习的时候,发现网上有很多数组实现队列,用得最多的是循环结构的方式,提供一下:(数组循环结构实现队列结构)https://blog.csdn.net/ggxxkkll/article/details/8662954

    我这里并没有使用这种方式,下面的案例使用的是,在队列内部维护了2个数组,一个是执行数组(固定长度-不可扩展容量),一个等待数组(初始长度+System复制扩展容量),这个队列是永远支持入队操作的,当执行队列未满的时候,优先入队执行队列,当执行队列满了的时候,

    会将数据继续入队到等待队列中。当执行队列出队数据的时候,也会检查等待队列中是否有数据,有的话会调取等待的数据到执行队列中。

    提供一下类的结构图:

     源码如下:

    MyQueueDefin3.java

      1 package com.xfwl.algorithmAnalysis.heap;
      2 import java.util.Arrays;
      3 /**
      4  * 自定义栈结构(基于数组的形式)
      5  * 队列的核心思想:先进先出
      6  * @function  日常学习测试
      7  * @author 小风微凉
      8  * @time  2018-5-20 上午8:41:27
      9  */
     10 public class MyQueueDefin3<T> {
     11     /**
     12      * 定义一个默认扩展容量:100
     13      * 特别说明:
     14      *           这个案例就不做数组容量扩展了,默认设置一个定量的数组。如果入队列达到上限则需要等待!
     15      * 所以又需要创建一个等待数组(这个可以扩容)
     16      *         
     17      */
     18     private static final int DEFAULT_CAPACITY=10;
     19     private static final int DEFAULT_WAIT_CAPACITY=10;
     20     /**
     21      * 数组队列容器:(执行队列-不支持扩展)
     22      */
     23     private T[] arrQueue;
     24     /**
     25      * 等待队列数组(等待队列-支持扩展)
     26      */
     27     private T[] waitQueue;
     28     /**
     29      * 计数器(执行队列中的数据条数)
     30      */
     31     private int nodeCount=0;
     32     /**
     33      * 计数器(等待队列中的数据条数)
     34      */
     35     private int nodeWaitCount=0;
     36     /**
     37      * 栈构造器
     38      */
     39     public MyQueueDefin3(){
     40         //重置队列结构
     41         this.arrQueue=(T[]) new Object[this.DEFAULT_CAPACITY];
     42         this.waitQueue=(T[]) new Object[this.DEFAULT_WAIT_CAPACITY];
     43         this.nodeCount=0;
     44         this.nodeWaitCount=0;
     45     }
     46     /**
     47      * 扩展数组容器(仅供waitQueue使用)
     48      * @param newCapacity 新容量大小
     49      * 说明:这里参考ArrayList源码中的一套扩展规则">>"
     50      */
     51     public void ensureCapacity(int newCapacity){
     52         //大小范围检查
     53         if(newCapacity<=this.size()){//不超过了当前容器的容量大小
     54             return;//则不需要扩展容器容量
     55         }
     56         //数组初始值判断 
     57         if(this.waitQueue==null){
     58             waitQueue=(T[]) new Object[newCapacity];
     59             return;//第一次初始化进来
     60         }
     61         //需要扩展容器容量
     62         T[] newItems=(T[]) Arrays.copyOf(this.waitQueue, newCapacity,this.waitQueue.getClass());
     63         this.waitQueue=newItems;
     64     }
     65     /**
     66      * 执行队列容量
     67      * @return
     68      */
     69     public int size(){
     70         return this.nodeCount;
     71     }
     72     /**
     73      * 等待队列容量
     74      * @return
     75      */
     76     public int waitSize(){
     77         return this.nodeWaitCount;
     78     }    
     79     /**
     80      * 数据入队列 
     81      * @param data  数据
     82      * @return
     83      */
     84     public boolean enqueue(T data){
     85         boolean bool=false;
     86         try{
     87             //判断当前执行队列是否达到上限
     88             if(this.size()==this.DEFAULT_CAPACITY){//执行队列已经上限,数据压入等待队列中
     89                 //判断等待队列是否达到上限,是否需要扩容
     90                 if(this.nodeWaitCount==this.waitQueue.length){//等待队列达到上限,需要扩容
     91                     int newCapacity=this.waitSize()+this.waitSize()>>1;//扩展量:取当前容量的一半,且向下取整
     92                     ensureCapacity(newCapacity);                    
     93                 }                
     94                 //数据压入等待队列
     95                 this.waitQueue[this.nodeWaitCount]=data;
     96                 this.nodeWaitCount++;                
     97                 bool=false; 
     98                 System.out.println("执行队列已满容量:"+DEFAULT_CAPACITY+",数据进入等待队列!等待队列容量:"+this.waitSize());
     99             }else{//执行队列未满,可继续压入                
    100                 this.arrQueue[this.nodeCount]=data;
    101                 this.nodeCount++;
    102                 bool=true; 
    103                 System.out.println("数据进入执行队列!当前容量:"+this.size()+",剩余容量:"+(this.DEFAULT_CAPACITY-this.size()));
    104             }
    105         }catch(Exception e){
    106             e.printStackTrace();
    107             throw e;
    108         }
    109         return bool;    
    110     }
    111     /**
    112      * 数据出队列
    113      * @return
    114      */
    115     public T dequeue(){
    116         T data=null;
    117         if(this.size()==0){
    118             System.out.println("执行队列中无数据,请先插入数据!");
    119             return data;
    120         }        
    121         if(this.size()==this.DEFAULT_CAPACITY){//执行队列已经上限,出队的同时,调取等待队列的第一条数据到执行队列中
    122             //出执行队列
    123             data=this.arrQueue[0];
    124             //数组数据前移一位
    125             System.arraycopy(this.arrQueue, 1, this.arrQueue, 0, this.size()-1);
    126             this.arrQueue[this.size()-1]=null;
    127             this.nodeCount--;
    128             System.out.println("执行队列【已满】,出队数据:"+data+",当前容量:"+this.nodeCount+",剩余熔炼"+(this.DEFAULT_CAPACITY-this.nodeCount));
    129             //调取判断
    130             if(this.waitSize()>0){
    131                 //调取等待队列的第一条数据到执行队列的最后一条
    132                 T tmpData=this.waitQueue[0];
    133                 this.arrQueue[this.DEFAULT_CAPACITY-1]=tmpData;
    134                 //等待队列数据变化:要移除的位置之后的数据前移一位
    135                 System.arraycopy(this.waitQueue, 1, this.waitQueue, 0, this.waitSize()-1);
    136                 //末尾的数据需要置空
    137                 this.waitQueue[this.waitSize()-1]=null;
    138                 //计数-1
    139                 this.nodeWaitCount--;
    140                 this.nodeCount++;
    141                 System.out.println("tips:等待队列调取一位数据补充执行队列,调取数据:"+tmpData+",当前执行队列当前容量:"+this.nodeCount+",剩余熔炼"+(this.DEFAULT_CAPACITY-this.nodeCount));
    142             }else{
    143                 System.out.println("tips:等待队列中无数据,当前执行队列当前容量:"+this.nodeCount+",剩余熔炼"+(this.DEFAULT_CAPACITY-this.nodeCount));
    144             }            
    145         }else{//仅仅执行队列中数据出列
    146             //出执行队列
    147             data=this.arrQueue[0];
    148             //数组数据前移一位
    149             System.arraycopy(this.arrQueue, 1, this.arrQueue, 0, this.size()-1);
    150             this.arrQueue[this.size()-1]=null;
    151             this.nodeCount--;
    152             System.out.println("执行队列【不满】,出队数据:"+data+",当前容量:"+this.nodeCount+",剩余熔炼"+(this.DEFAULT_CAPACITY-this.nodeCount));
    153         }
    154         return data;        
    155     }    
    156     /**
    157      * 打印队列数据
    158      */
    159     public void printList(){
    160         System.out.println("----1·【执行队列】开始打印---------------------");
    161         for(int i=0;i<this.size();i++){
    162             System.out.println(this.arrQueue[i]);            
    163         }
    164         if(this.size()==0){
    165             System.out.println("队列为空,无数据返回!");            
    166         }
    167         System.out.println("----1·【执行队列】结束打印---------------------");
    168         System.out.println("----2·【等待队列】开始打印---------------------");
    169         for(int i=0;i<this.waitSize();i++){
    170             System.out.println(this.waitQueue[i]);            
    171         }
    172         if(this.waitSize()==0){
    173             System.out.println("队列为空,无数据返回!");            
    174         }
    175         System.out.println("----2·【等待队列】结束打印---------------------");
    176     }
    177 }

     测试类:Test3.java

     1 package com.xfwl.algorithmAnalysis.heap;
     2 
     3 public class Test3 {
     4     public static void main(String[] args) {
     5         //创建一个队列对象
     6         MyQueueDefin3<Object> queue=new MyQueueDefin3<>();
     7         //打印
     8         queue.printList();
     9         //压入数据(把执行队列压满)
    10         for(int i=0;i<10;i++){
    11             queue.enqueue("数据-"+(i+1));
    12         }
    13         //打印
    14         queue.printList();
    15         //再压入一个数据到执行队列中
    16         queue.enqueue("数据-11");
    17         queue.enqueue("数据-12");
    18         queue.enqueue("数据-13");
    19         //打印
    20         queue.printList();
    21         //执行队列出列一个数据
    22         queue.dequeue();
    23         //打印
    24         queue.printList();
    25     }
    26 }

     运行结果:

    ----1·【执行队列】开始打印---------------------
    队列为空,无数据返回!
    ----1·【执行队列】结束打印---------------------
    ----2·【等待队列】开始打印---------------------
    队列为空,无数据返回!
    ----2·【等待队列】结束打印---------------------
    数据进入执行队列!当前容量:1,剩余容量:9
    数据进入执行队列!当前容量:2,剩余容量:8
    数据进入执行队列!当前容量:3,剩余容量:7
    数据进入执行队列!当前容量:4,剩余容量:6
    数据进入执行队列!当前容量:5,剩余容量:5
    数据进入执行队列!当前容量:6,剩余容量:4
    数据进入执行队列!当前容量:7,剩余容量:3
    数据进入执行队列!当前容量:8,剩余容量:2
    数据进入执行队列!当前容量:9,剩余容量:1
    数据进入执行队列!当前容量:10,剩余容量:0
    ----1·【执行队列】开始打印---------------------
    数据-1
    数据-2
    数据-3
    数据-4
    数据-5
    数据-6
    数据-7
    数据-8
    数据-9
    数据-10
    ----1·【执行队列】结束打印---------------------
    ----2·【等待队列】开始打印---------------------
    队列为空,无数据返回!
    ----2·【等待队列】结束打印---------------------
    执行队列已满容量:10,数据进入等待队列!等待队列容量:1
    执行队列已满容量:10,数据进入等待队列!等待队列容量:2
    执行队列已满容量:10,数据进入等待队列!等待队列容量:3
    ----1·【执行队列】开始打印---------------------
    数据-1
    数据-2
    数据-3
    数据-4
    数据-5
    数据-6
    数据-7
    数据-8
    数据-9
    数据-10
    ----1·【执行队列】结束打印---------------------
    ----2·【等待队列】开始打印---------------------
    数据-11
    数据-12
    数据-13
    ----2·【等待队列】结束打印---------------------
    执行队列【已满】,出队数据:数据-1,当前容量:9,剩余熔炼1
    tips:等待队列调取一位数据补充执行队列,调取数据:数据-11,当前执行队列当前容量:10,剩余熔炼0
    ----1·【执行队列】开始打印---------------------
    数据-2
    数据-3
    数据-4
    数据-5
    数据-6
    数据-7
    数据-8
    数据-9
    数据-10
    数据-11
    ----1·【执行队列】结束打印---------------------
    ----2·【等待队列】开始打印---------------------
    数据-12
    数据-13
    ----2·【等待队列】结束打印---------------------

     三、单链表方式实现队列结构

    类结构图:

     MyQueueDefin.java类

      1 package com.xfwl.algorithmAnalysis.heap;
      2 /**
      3  * 自定义栈结构(基于单链表的形式)
      4  * 队列的核心思想:先进先出
      5  * @function  日常学习测试
      6  * @author 小风微凉
      7  * @time  2018-5-20 上午8:41:27
      8  */
      9 public class MyQueueDefin<T> {
     10     /**
     11      * 头结点
     12      */
     13     private Node<T> front;    
     14     /**
     15      * 计数器
     16      */
     17     private int nodeCount=0;
     18     /**
     19      * 队列构造器
     20      */
     21     public MyQueueDefin(){
     22         //重置队列结构
     23         front=new Node(null,null);
     24         nodeCount=0;
     25     }
     26     /**
     27      * 队列容量
     28      * @return
     29      */
     30     public int size(){
     31         return this.nodeCount;
     32     }
     33     /**
     34      * 拿到最后一个结点(最新的入队列数据结点)
     35      * @return
     36      */
     37     private Node<T> findLastNode(){
     38         Node<T> tmp=this.front;
     39         while(tmp.next!=null){
     40             tmp=tmp.next;
     41         }
     42         return tmp;
     43     }
     44     /**
     45      * 数据入队列 
     46      * @param data  数据
     47      * @return
     48      */
     49     public boolean enqueue(T data){
     50         boolean bool=false;
     51         try{
     52             //创建新鲜结点
     53             Node<T> newNode=new Node<>(data,null);
     54             //拿到队列尾部结点
     55             this.findLastNode().next=newNode;
     56             //计数器+1
     57             this.nodeCount++;
     58             bool=true; 
     59         }catch(Exception e){
     60             e.printStackTrace();
     61             throw e;
     62         }
     63         return bool;    
     64     }
     65     /**
     66      * 数据出队列
     67      * @return
     68      */
     69     public T dequeue(){
     70         if(this.size()==0){
     71             System.out.println("空队列,请先插入数据!");
     72             return null;
     73         }
     74         T data=this.findNode(0).data;
     75         this.front.next=this.findNode(0).next;
     76         this.nodeCount--;        
     77         return data;        
     78     }
     79     /**
     80      * 根据索引值找到结点
     81      * @param index 位置索引值
     82      * @return
     83      */
     84     private Node<T> findNode(int index){
     85         if(index<0 || index>(this.size()-1)){
     86             throw new IllegalArgumentException("参数不合法,请重新输入!");
     87         }
     88         //第一个数据结点
     89         Node tmp=this.front.next;
     90         for (int i = 0; i < this.size(); i++) {
     91             if(index==i){
     92                 break;
     93             }
     94             tmp=tmp.next;
     95         }
     96         return tmp;
     97     }
     98     /**
     99      * 打印队列数据
    100      */
    101     public void printList(){
    102         System.out.println("-----------开始打印----------------");
    103         for(int i=0;i<this.size();i++){
    104             System.out.println(this.findNode(i).data);
    105         }
    106         if(this.size()==0){
    107             System.out.println("队列为空,无数据!");
    108         }
    109         System.out.println("-----------结束打印----------------");
    110     }
    111     /**
    112      * 内置一个结点类
    113      */
    114     private class Node<T>{
    115         /**
    116          * 结点数据域
    117          */
    118         private T data;
    119         /**
    120          * 结点指针域
    121          */
    122         private Node<T> next;
    123         /**
    124          * 结点构造函数
    125          */
    126         public Node(T data,Node<T> node){
    127             this.data=data;
    128             this.next=node;
    129         }
    130     }
    131 }

      测试类:Test.java

     1 package com.xfwl.algorithmAnalysis.heap;
     2 /**
     3  * 测试类
     4  * @function  
     5  * @author 小风微凉
     6  * @time  2018-5-20 上午9:01:13
     7  */
     8 public class Test {
     9     public static void main(String[] args) {
    10         //创建队列对象
    11         MyQueueDefin<Object> queue=new MyQueueDefin<>();
    12         //打印
    13         queue.printList();
    14         //入队
    15         queue.enqueue("当1个数据");
    16         queue.enqueue("当2个数据");
    17         queue.enqueue("当3个数据");
    18         queue.enqueue("当4个数据");
    19         queue.enqueue("当5个数据");
    20         //打印
    21         queue.printList();
    22         //出队
    23         queue.dequeue();
    24         //打印
    25         queue.printList();
    26         //入队
    27         queue.enqueue("当6个数据");
    28         //打印
    29         queue.printList();
    30     }
    31 }

      运行结果:

    -----------开始打印----------------
    队列为空,无数据!
    -----------结束打印----------------
    -----------开始打印----------------
    当1个数据
    当2个数据
    当3个数据
    当4个数据
    当5个数据
    -----------结束打印----------------
    -----------开始打印----------------
    当2个数据
    当3个数据
    当4个数据
    当5个数据
    -----------结束打印----------------
    -----------开始打印----------------
    当2个数据
    当3个数据
    当4个数据
    当5个数据
    当6个数据
    -----------结束打印----------------

     四、双链表方式实现队列结构 

    类结构图

    MyQueueDefin2.java 

      1 package com.xfwl.algorithmAnalysis.heap;
      2 
      3 /**
      4  * 自定义栈结构(基于双链表的形式)
      5  * 队列的核心思想:先进先出
      6  * @function  日常学习测试
      7  * @author 小风微凉
      8  * @time  2018-5-20 上午8:41:27
      9  */
     10 public class MyQueueDefin2<T> {
     11     /**
     12      * 头结点
     13      */
     14     private Node<T> front;    
     15     /**
     16      * 尾结点
     17      */
     18     private Node<T> back;    
     19     /**
     20      * 计数器
     21      */
     22     private int nodeCount=0;
     23     /**
     24      * 队列构造器
     25      */
     26     public MyQueueDefin2(){
     27         //重置队列结构
     28         this.front=new Node(null,null,null);
     29         this.back=new Node(null,null,null);
     30         this.front.next=this.back;
     31         this.back.prev=this.front;
     32         nodeCount=0;
     33     }
     34     /**
     35      * 队列容量
     36      * @return
     37      */
     38     public int size(){
     39         return this.nodeCount;
     40     }
     41     /**
     42      * 拿到最后一个结点(最新的入队列数据结点)
     43      * @return
     44      */
     45     private Node<T> findLastNode(){
     46         if(this.size()==0){
     47             return this.front;
     48         }
     49         return this.back.prev;
     50     }
     51     /**
     52      * 数据入队列 
     53      * @param data  数据
     54      * @return
     55      */
     56     public boolean enqueue(T data){
     57         boolean bool=false;
     58         try{
     59             //创建新鲜结点
     60             Node<T> newNode=new Node<>(data,null,null);
     61             //拿到队列尾部结点
     62             Node lastNode=this.findLastNode();
     63             lastNode.next=newNode;
     64             newNode.prev=lastNode;
     65             newNode.next=this.back;
     66             this.back.prev=newNode;
     67             //计数器+1
     68             this.nodeCount++;
     69             bool=true; 
     70         }catch(Exception e){
     71             e.printStackTrace();
     72             throw e;
     73         }
     74         return bool;    
     75     }
     76     /**
     77      * 数据出队列
     78      * @return
     79      */
     80     public T dequeue(){
     81         if(this.size()==0){
     82             System.out.println("空队列,请先插入数据!");
     83             return null;
     84         }
     85         Node<T> deNode=this.findNode(0);
     86         T data=deNode.data;        
     87         this.front.next=deNode.next;
     88         deNode.next.prev=this.front;
     89         this.nodeCount--;        
     90         return data;        
     91     }
     92     /**
     93      * 根据索引值找到结点
     94      * @param index 位置索引值
     95      * @return
     96      */
     97     private Node<T> findNode(int index){
     98         if(index<0 || index>(this.size()-1)){
     99             throw new IllegalArgumentException("参数不合法,请重新输入!");
    100         }
    101         //第一个数据结点
    102         Node tmp=this.front.next;
    103         for (int i = 0; i < this.size(); i++) {
    104             if(index==i){
    105                 break;
    106             }
    107             tmp=tmp.next;
    108         }
    109         return tmp;
    110     }
    111     /**
    112      * 打印队列数据
    113      */
    114     public void printList(){
    115         System.out.println("-----------开始打印----------------");
    116         for(int i=0;i<this.size();i++){
    117             System.out.println(this.findNode(i).data);
    118         }
    119         if(this.size()==0){
    120             System.out.println("队列为空,无数据!");
    121         }
    122         System.out.println("-----------结束打印----------------");
    123     }
    124     /**
    125      * 内置一个结点类
    126      */
    127     private class Node<T>{
    128         /**
    129          * 结点数据域
    130          */
    131         private T data;
    132         /**
    133          * 结点前驱指针域
    134          */
    135         private Node<T> prev;
    136         /**
    137          * 结点后驱指针域
    138          */
    139         private Node<T> next;
    140         /**
    141          * 结点构造函数
    142          */
    143         public Node(T data,Node<T> prev,Node<T> next){
    144             this.data=data;
    145             this.prev=prev;
    146             this.next=next;
    147         }
    148     }
    149 }

      测试类:Test2.java 

     1 package com.xfwl.algorithmAnalysis.heap;
     2 /**
     3  * 测试类
     4  * @function  
     5  * @author 小风微凉
     6  * @time  2018-5-20 上午9:01:13
     7  */
     8 public class Test2 {
     9     public static void main(String[] args) {
    10         //创建队列对象
    11         MyQueueDefin2<Object> queue=new MyQueueDefin2<>();
    12         //打印
    13         queue.printList();
    14         //入队
    15         queue.enqueue("当1个数据");
    16         queue.enqueue("当2个数据");
    17         queue.enqueue("当3个数据");
    18         queue.enqueue("当4个数据");
    19         queue.enqueue("当5个数据");
    20         //打印
    21         queue.printList();
    22         //出队
    23         queue.dequeue();
    24         //打印
    25         queue.printList();
    26         //入队
    27         queue.enqueue("当6个数据");
    28         //打印
    29         queue.printList();
    30     }
    31 }

      运行结果:

    -----------开始打印----------------
    队列为空,无数据!
    -----------结束打印----------------
    -----------开始打印----------------
    当1个数据
    当2个数据
    当3个数据
    当4个数据
    当5个数据
    -----------结束打印----------------
    -----------开始打印----------------
    当2个数据
    当3个数据
    当4个数据
    当5个数据
    -----------结束打印----------------
    -----------开始打印----------------
    当2个数据
    当3个数据
    当4个数据
    当5个数据
    当6个数据
    -----------结束打印----------------
  • 相关阅读:
    【网易官方】极客战记(codecombat)攻略-森林-墓地阴魂tomb-ghost
    【网易官方】极客战记(codecombat)攻略-森林-盗墓者tomb-raider
    no plugin found for prefix 'tomcat 7' in the current project
    java.lang.IllegalStateException: Ambiguous mapping found
    Result Maps collection already contains value for
    Delete 和 Put 请求失效, Spring 框架
    NoClassDefFound Error: com/fasterxml/jackson/annotation/JsonAutoDetect
    mybatis 常用标签
    sql join
    objectMapper、JsonNode、JsonObject常用方法
  • 原文地址:https://www.cnblogs.com/newwind/p/9062757.html
Copyright © 2011-2022 走看看