循环数组 and ArrayDeque

   我竟然今天才知道循环数组这个概念!

   1. 怎么实现循环?

      通过首尾两个下标!如果尾下标的下一个就是头下标,那么队列就满了?但是怎么知道尾下标的下一个了?可一通过下标与数组长度取余!

      还有就是如果首尾相等,那么这这个队列为空!

      ArrayDeque 就是通过一个循环数组实现的!它判断队列是否满了或者获得前一个元素?通过:

      分析源码的过程中,我就在纳闷,ArrayDeque里面的elements数组,通过位操作进行循环数组判断时是怎么做到的!

      比如说,如果elements.length - 1 = 4 , head = 2 , 那么无论怎么& 都是0 , 根本就得不到想得到的头元素啊!

     通过分析它的构造函数以及结合位运算的规律,发现,elements.length - 1 根本就不可能等于4 , 8 , 16 这样的2^n ,但是elments.length 却可以为8 , 16 , 32这样2^n ,4除外,最小为8

     再看看位运算的规律 : elements.length = 2 ^ n , 那么它的二进制形式,比如8 , 1000 ,那么比8小的数 , 一定是他后三位的随意组合,所以相与一定为0 ,但是对于elements.length - 1 , 比如7,

    0111 , 那么,<=7 的数与7相与,不就等于本本身吗,负数相反! 

   

负数的二进制规律:

1、取负数的绝对值的原码;

2、计算原码的反码;正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
// 原码10010= 反码11101 (10010,1为符号码,故为负) (11101)
3、对反码加一,获取补码。

  

   构造函数:

    分配elements数组空间

private void allocateElements(int numElements) { //假设numElements = 10 二进制 : 1010
        int initialCapacity = MIN_INITIAL_CAPACITY;
        // Find the best power of two to hold elements.
        // Tests "<=" because arrays aren't kept full.
        if (numElements >= initialCapacity) {
            initialCapacity = numElements;
            initialCapacity |= (initialCapacity >>>  1); // 右移一位 0101 然后与 1010 相或 = 1111 = 15
            initialCapacity |= (initialCapacity >>>  2);
            initialCapacity |= (initialCapacity >>>  4);
            initialCapacity |= (initialCapacity >>>  8);
            initialCapacity |= (initialCapacity >>> 16); // 15 为什么要右移多次了?
            initialCapacity++; // 16

            if (initialCapacity < 0)   // Too many elements, must back off
                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
        }
        elements = (E[]) new Object[initialCapacity];
    }
public void addFirst(E e) {  
    if (e == null)  
        throw new NullPointerException();  
    // 本来可以简单地写成head-1,但如果head为0,减1就变为-1了,和elements.length - 1进行与操作就是为了处理这种情况,这时结果为elements.length - 1。  
    elements[head = (head - 1) & (elements.length - 1)] = e;  
    if (head == tail) // head和tail不可以重叠  
        doubleCapacity();  
}  

  

public void addLast(E e) {  
    if (e == null)  
        throw new NullPointerException();  
    // tail位置是空的,把元素放到这。  
    elements[tail] = e;  
    // 和head的操作类似,为了处理临界情况 (tail为length - 1时),和length - 1进行与操作,结果为0。  
    if ( (tail = (tail + 1) & (elements.length - 1)) == head)  
        doubleCapacity();  
}  

  代码来源 : http://blog.csdn.net/microtong/article/details/4626224

/** 
 * 数组实现的循环队列 
 * @author TongQiang 
 */  
public class QueueArray {  
    Object[] a; //对象数组,队列最多存储a.length-1个对象  
    int front;  //队首下标  
    int rear;   //队尾下标  
    public QueueArray(){  
        this(10); //调用其它构造方法  
    }  
    public QueueArray(int size){  
        a = new Object[size];  
        front = 0;  
        rear =0;  
    }  
    /** 
     * 将一个对象追加到队列尾部 
     * @param obj 对象 
     * @return 队列满时返回false,否则返回true 
     */  
    public boolean enqueue(Object obj){ 
    	// g关于这个地方为什么要rear+1 这样不就会少加一个元素吗?
//    	如果是rear%a.length 的话,那么dang rear = 4 ,接下来,出队列,那么front = 1 , 那么这是rear % a.length = 0 . a[rear] 不就出错了吗
        if((rear+1)%a.length==front){  
            return false;  
        }  
        a[rear]=obj;  
        rear = (rear+1)%a.length;  
        return true;  
    }  
    /** 
     * 队列头部的第一个对象出队 
     * @return 出队的对象,队列空时返回null 
     */  
    public Object dequeue(){  
        if(rear==front){  
            return null;  
        }  
        Object obj = a[front];  
        front = (front+1)%a.length;  
        return obj;  
    }  
    public static void main(String[] args) {  
        QueueArray q = new QueueArray(4);  
        System.out.println(q.enqueue("张三"));  
        System.out.println(q.enqueue("李斯"));  
        System.out.println(q.enqueue("赵五"));  
        System.out.println(q.enqueue("王一"));//无法入队列,队列满  
        for(int i=0;i<4;i++){  
            System.out.println(q.dequeue());  
        }  
    }  
}  

猜你喜欢

转载自kainever7.iteye.com/blog/2202640
今日推荐