ArrayDeque

队列方法基础说明见队列接口设计

一 ArrayDeque中操使用了各种位操作,先对位运算进行说明

  1. 二进制数表示
    二进制数使用补码表示
    最高位为 符号位,正数的符号为0,负数为1 。其余代表数值本身。 对于负数, 通过对该数的绝对值的补码按位取反,在对整个数加1;

    举例: -1的二进制表示
    1的补码 00000001
    取反 11111110
    加1 11111111

  2. 位运算符号
    逻辑运算符
    ~ 按位非

    & 按位与 只有两个操作数对应位同为1时,结果为1,其余全为0。

    | 按位或 只有两个操作数同为0时,结果为0,其余全为1

    ^ 按位异或运算符;

    1. 相同结果为0, 否则为1. 即 0^0 = 0; 0^1 = 1 ; 1^1 = 0;
    2. 0 异或任何数等于任何数
    3. 1 异或任何数等于任何数取反
    4. 任何数异或自己等于把自己设置为0

移位运算
1.<< 左位移运算符 将向左移动指定位数,高位溢出截断 ; 在低位补0;

  1. ">>" 右移运算符,向右边移动指定的位数 ;若值为正,则在高位插入0;若值为负,则在高位插入1。 低位溢出截断
  2. " >>>" 右移运算符,向右边移动指定的位数 ; 无论正负,都在高位插入0

源码分析

public class ArrayDeque  extends AbStractCollection implements Deque , Cloneable,Serializable{
      
      
      //The capacity of the deque is the length of this array, which is always a power of two 
      //The array is never allowed to become full 
      // We also guarantee that all array cells not holding deque elements are always null.
      
      //怎么做到分配最合适的2的幂次方数呢 见allocateElements
      
      transient Object[] elements;
      
      
      
      public ArrayDeque(){
          
          element = new Object[16];
      }
      
      public ArrayDeque(int numElements) {
        allocateElements(numElements);
      }
      
      public ArrayDeque(Collection c) {
        allocateElements(c.size());
        addAll(c);
      }
      
      private void allocateElements(int numElements){
          
          int initialCapacity = MIN_INITIAL_CAPACITY;
          
          if(numElements > initialCapacity){
              
              //效果是把numElements数表示二进制后,在最高位1之后统统改变成1,
              //由于第一位的1 表示1 在加1后 就可以得到合适的2的幂次方。
              //假设传入 numElements = 18
              //initialCapacity = 00010010;
              initialCapacity = numElements;
              
              //initialCapacity >>> 1 = 00001001
              //initialCapacity =  00010010| 00001001 =  00011011
              initialCapacity |= (initialCapacity >>> 1);
              
              //initialCapacity >>> 2 = (00011011 >>> 2) = 00000110
              //initialCapacity = 00011011 | 00000110 =00011111;
              initialCapacity |= (initialCapacity >>> 2);
              
              // initialCapacity >>> 4 = 00000001
              //initialCapacity = 00011111 |  00000001 = 00011111
              initialCapacity |= (initialCapacity >>> 4);
              
              //initialCapacity = 00011111 |  00000000 = 00011111
              initialCapacity |= (initialCapacity >>> 8);
              //initialCapacity = 00011111 |  00000000 = 00011111
              initialCapacity |= (initialCapacity >>> 16);
              //initialCapacity = 00011111 = 31
              
              initialCapacity++;
              
              if(initialCapacity < 0){
                  
                  initialCapacity >>>= 1;
              }
              
          }
          
          elements = new Object[initialCapacity]
          
      }
      
      private void doubleCapacity(){
          
           assert head == tail;
           
           int p = head;
           int n = elements.length;
           int r = n - p; 
           //数组长度翻倍
           int newCapacity = n << 1;
           if (newCapacity < 0)
               throw new IllegalStateException("Sorry, deque too big");
           
            Object[] a = new Object[newCapacity];
            //将head右边的元素拷贝到数组开头处
            System.arraycopy(elements,p,a,0,r);
            //拷贝head左边的元素到新数组里
            System.arraycopy(elements,0,a,r,p);
            
            elements = a;
            head = 0;
            tail = n;  
          
      }
      
      //尾部添加
      public void addLast(E e){
          
          if(e == null){
              throw ...
          }
          
          element[tail] = e;
          //elements.length的二进制码 出符号位是0外 其它都是1
         //假设数组长度16  elements.length = 00001111;
         // tail =2 
         // tail = tail + 1 = 3
         // 00000011 & 00001111 = 00000011  = 3   会小于数组长度,开始head=0 不需要扩容
         
         // 假设tail =15
         // tail = tail + 1 = 16
         // 00010000 & 00001111 = 0  这时候就需要扩容了
         
          if( tail = (tail + 1) &(elements.length) == head)
              doubleCapacity();
          
      }
      
      //头部添加 
      public void addFirst(E e){
          
           if (e == null)
               throw new NullPointerException();
           
           //head -1)&(elements.length -1) 计算head前一个位置
           // 假设 刚开始head = 0, 数组长度16 
           // -1&15 = 11111111 & 00001111  = 00001111  = 15
           elements[head = (head -1)&(elements.length -1)] = e;
           
           if(head == tail){
               doubleCapacity();
           }
          
      }
      
    public E pollFirst(){
        
        final Object[] elements = this.elements;
        final int h = head;
        
        E result = (E)elements[h];
        if(result != null){
            element[h] = null;
            //head 移到下一个位置 
            head = (h+1) & (elements.length -1);
        }
        
        return result;
        
    }
    
    public E pollLast(){
        final Object[] elements = this.elements;
        //计算最后一个位置 
        final int t = (tail - 1) & (elements.length - 1);
        E result = (E) elements[t];
        if (result != null) {
            elements[t] = null;
            tail = t;
        }
        return result;  
    }
      
    
    public boolean removeFirstOccurrence(Object o){
        
        if(o != null){
            
            int mask = element.length - 1;
            int i = head;
            
            //i = (i+1)&mask 相当于 i++
            for(Object x; (x = elements[i]) != null; i = (i+1)&mask){
                
                if (o.equals(x)) {
                    delete(i);
                    return true;
                }
            }
            
        }
        
        return false;
        
    }
    
    public boolean removeLastOccurrence(Object o) {
        if (o != null) {
            int mask = elements.length - 1;
            int i = (tail - 1) & mask;
            for (Object x; (x = elements[i]) != null; i = (i - 1) & mask) {
                if (o.equals(x)) {
                    delete(i);
                    return true;
                }
            }
        }
        return false;
    }
    
    public boolean contains(Object o) {
        if (o != null) {
            int mask = elements.length - 1;
            int i = head;
            //从头部开始往后遍历, 循环到空元素就结束
            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
                if (o.equals(x))
                    return true;
            }
        }
        return false;
    }
    
    
    public int size() {
        return (tail - head) & (elements.length - 1);
    }

      
   boolean delete(int i) {
        checkInvariants();
        final Object[] elements = this.elements;
        final int mask = elements.length - 1;
        final int h = head;
        final int t = tail;
        final int front = (i - h) & mask;
        final int back  = (t - i) & mask;

        // Invariant: head <= i < tail mod circularity
        if (front >= ((t - h) & mask))
            throw new ConcurrentModificationException();

        // Optimize for least element motion
        if (front < back) {
            if (h <= i) {
                System.arraycopy(elements, h, elements, h + 1, front);
            } else { // Wrap around
                System.arraycopy(elements, 0, elements, 1, i);
                elements[0] = elements[mask];
                System.arraycopy(elements, h, elements, h + 1, mask - h);
            }
            elements[h] = null;
            head = (h + 1) & mask;
            return false;
        } else {
            if (i < t) { // Copy the null tail as well
                System.arraycopy(elements, i + 1, elements, i, back);
                tail = t - 1;
            } else { // Wrap around
                System.arraycopy(elements, i + 1, elements, i, mask - i);
                elements[mask] = elements[0];
                System.arraycopy(elements, 1, elements, 0, t);
                tail = (t - 1) & mask;
            }
            return true;
        }
    }

  }
    

总结:

This class is likely to be faster than {@link Stack} when used as a stack, and faster than {@link LinkedList} when used as a queue.

1.arrayDeque 基于数组实现双端队列,替代栈使用,作为队列使用效率高于linkedList。为了提高效率,设计采用了循环数组。设计了两个变量head和 tail记录了头尾。使用位操作进行各种判断,以及对head和tail的维护

2.没有索引位置的概念,如果同时需要根据索引位置进行操作,或者经常需要在中间进行插入和删除,则应该选LinkedList。 而从两端进行操作,一般而言,ArrayDeque效率更高一些,应该被优先使用,

你可能感兴趣的:(ArrayDeque)