Queue of Arraydeque Source

Source: Internet
Author: User

The front says that stack is a Advanced post-outData structure: Stack, then the corresponding queue is a FIFO First outData structure: Queue. Compare the Stack,queue is a first-in-one-out container that has two ports, from one port to the element, and the other for the element.  If the stack is compared to a cask, then the queue is a pipe.     is not easy to understand, because the queue has two ports, one is responsible for the other team in charge, so there will be a first-out effect. Of course, we say that Arraydeque is a two-way queue, the queue of two ports can be queued and out of the team operation. Further said, in fact, Arraydeque can be said to be a two-way loop queue, is not and the list of linked lists very much like, why say so, we will be specific analysis below. 1. Definition
1 public class Arraydeque<e> extends abstractcollection<e>2                            implements Deque<e>, Cloneable, Serializable
From the definition of arraydeque, it can be seen that it inherits Abstractcollection and implements the Deque,cloneable,serializable interface. Do not know see here you will not find anything, deque interface we have seen in LinkedList, LinkedList is also to implement Deque interface. We said that Deque is a double-ended queue, which is implemented in the queue interface, what is a double-ended queue, that is, in the same end of the queue can be queued and can be out of the team, so the deque can be used as a queue and can use as a stack.      But today it's about queue queues, so just look at some of the principles and implementations of one-way queues. Look at the queue interface:
1 public Interface queue<e> extends collection<e> {2     //Add an element to the end of the queue and throw a Iiiegaislabeepeplian exception if the queues are full 3     Boolean Add (E e); 4     //Add an element to the end of the queue and return True if the queues are full, then return False 5     Boolean offer (e e); 6     //Remove and return elements of the queue header if the queue is empty , a Nosuchelementexception exception is thrown 7     e remove (), 8     //is removed and returned to the element of the queue header, or null 9     E poll () if the queue is empty;     Returns the element of the head of the queue, if the queue is empty, throws a Nosuchelementexception exception, one     e element (); The element that is returned to     the queue header, or null13 E if the queue is empty     Peek (); 14}
Seeing the definition of queue, there is no way to find that it is very similar to Stack's. However, Arraydeque is not a fixed-size queue, and each time the queue is full it will be expanded, unless it is scaled beyond the bounds of int to throw an exception. So the add and offer here is almost indistinguishable. 2. Underlying storage        Of course, from the name of Arraydeque can be seen that his bottom is an array implementation (and LinkedList is a list of the implementation of the queue), to see the main arraydeque.
1     //Bottom with array storage element 2     private transient e[] elements;3      //Queue Header element Index (one to pop out) 4       private transient int head;5      //Queue next element to add index 6       private transient int tail;7      //Minimum initial capacity size, need to be 2 N Power 8       private static final int min_ Initial_capacity = 8;
It should be noted here that the min_initial_capacity, which must be initialized to a power of 2 N. Why must be 2 of the power of N, remember HashMap in our analysis, HashMap also require the initial capacity of its underlying array must be 2 of the N power, remember that was based on what reason? Do not remember the words, then return to see the "write to the JDK series of jdk1.6 container (4)-hashmap source code analysis."     So Arraydeque here is based on what to consider, we look at below. The tail is not the index of the last element, it is the next element index to be added, that is, the last element +1. 3. Construction Method
 1/** 2 * Default construction method, the initial capacity of the array is 3 */4 public Arraydeque () {5 elements = (e[]) new OBJECT[16]; 6 } 7 8/** 9 * Constructs a ArrayDeque10 */11 public arraydeque (int numelements) with a specified initial capacity {Allo Cateelements (numelements); 13}14 15/**16 * Constructs a collection ArrayDeque17 public */18 that specifies arraydeque collection parameters (collection<? extends e> c) {allocateelements (C.size ()); AddAll (c); 21}22 23/**24 * Allocate an array of appropriate capacity sizes to ensure that the initial capacity is greater than the specified numeleme NTS of the smallest 2 n power */26 private void allocateelements (int numelements) {int initialcapacity = Min_initial_ CAPACITY;28//Find the smallest 2 of the power greater than the specified capacity n//Find the best power of two to hold elements.30//Tests "&lt = "because arrays aren ' t kept full.31//If the specified capacity is less than the initial capacity of 8, perform the logical operation in if (Numelements >= Initialcapa City) {initialcapacity = numelements;34 initialcapacity |= (initialcapacity >>&Gt 1); initialcapacity |= (initialcapacity >>> 2); initialcapacity |= (initialcapacity >>> 4), PNs initialcapacity |= (initialcapacity >>> 8); initialcapacity |= (in Itialcapacity >>> initialcapacity++;40 (initialcapacity < 0)//Too man Y elements, must back off42 initialcapacity >>>= 1; Good luck allocating 2 ^ elements43}44 elements = (e[]) new object[initialcapacity];45}
See here, I believe a lot of people do not understand (including me), but we can come to a careful analysis, recall that we analyzed in HashMap, 2 of the N power and 2 of the N power-1 of the binary is what it looks like, and then look at: 2^n conversion to binary is what it looks like:
2^1 = 102^2 = 1002^3 = 10002^n = 1 (n 0)

  

And look at what the 2^n-1 binary looks like:

2^1-1 = 012^2-1 = 0112^3-1 = 01112^n-1 = 0 (n 1)
Look at the code initialcapacity++ What is meant, that is, after Initialcapity+1 is 2 of the power of N, then what is the initialcapacity at this time? is the above 2^n-1 (initialcapacity + 1 = 2^n), that is, how do I make initialcapacity for 2^n-1, then the above 4 times ">>>" and "|"     The operation. ">>>" is an unsigned right shift, meaning is to convert an operand to binary, remove the post n displacement, and the high 0。     For example: The binary 1101,11 >>> 2 of 11 is: (1) Remove the post two bits 01, (2) The high point is 0, and the last one is 0011. "|" is a bitwise OR operation, meaning convert two operands to binary, if two operands have 1 or 1, all 0 is 0, respectively ., for example: the binary of two numbers 8 and 9 is 1000 and 1001,1000 for each other |      1001 = 1001. Understand ">>>" and "|" After the operation, take a look at the 4 ">>>" and "|" in the code above. What do you mean, ">>>" turns a number low to 1, "|"     , the entire binary of the last number is changed to 1. For example: If initialcapacity=9,9 is converted to binary: 1001, then after the first round of >>>1:100, then 1001 | 100 = 1101; After the second round of >>>2, it becomes: 0011, then 1101 | 0011 = 1111,1111 is converted to 10 with +1 equals 16 (2^4), and by this series of operations it is done to acquire an n power of 2 greater than the minimum specified capacity. If the given initialcapacity is large enough, it will eventually become 1111111111111111111111111111111 (31 bits 1), and of course finally to prevent overflow (initialcapacity<0),      Move the initialcapacity right 1 bits to 2 30, then when initialcapacity will be less than 0, that is, when initialcapacity as an int value <<1 out of bounds. In fact, in the HashMap also has such a purpose of operation, but its code is not so implemented, it is through a loop, each cycle only right 1 bits. To recall:
1     //ensure a capacity of n power of 2, is capacity is greater than initialcapacity of the smallest 2 of the N power 2      int capacity = 1;3 while      (capacity < initialcapacity) 4          capacity <<= 1;

So what is the difference between these two methods? This notation in HashMap is more capacity-aware, while the effect in Arraydeque is higher (up to 4 displacements and/or operations + 1 plus one operation).

4. Queue (add element to end of team)

1     /** 2      * Add an element if the queue is full, throw a Iiiegaislabeepeplian exception 3      */4 Public     Boolean add (E e) {5         /// Call the AddLast method to add elements to the end of the Team 6         addlast (e); 7         return true; 8     } 9      /**11      * Add an element of      */13     public Boolean offer (E-e) {         //Call the Offerlast method to add elements to the end of the queue         offerlast (e);     }17     /**19      * Add an element at the end of the team      */21 public     boolean offerlast (e) {         24//Call the AddLast method and add the element to the end of the queue         addlast (e);         return true;25     }     /**28      * add element to team tail      */30 public     void AddLast (e e) {         to//if the element is null, I throw a null pointer exception if         (E = = null) A             throw new NullPointerException ();/         /Put element E in the tail position of the array         elements[tail] = e;36         // Determine if the tail and head are equal, and if equal, expand the array to the size of the PNS if         ((tail = (tail + 1) & (elements.length-1)) = = head)             //perform twice-fold expansion 39
   
    doublecapacity ();     
   

Here, ((tail = (tail + 1) & (elements.length-1)) = = Head) This code is the key, why write it like this. The normal add element should be tail+1 right, but the deletion and addition of the queue is not on the same side, what meaning, we draw a picture to see.

We assume that the initial capacity of the queue is 8, the initial queue added 4 elements A, B, C, D, respectively, in the array 0, 1, 2, 3 subscript position, such as the left, at this point the head corresponding array subscript 0,tail corresponding array subscript 4. When the queue through a series of queues and out of the team, it will become the right image, at this time the head corresponding array subscript 3,tail corresponding array subscript 7. Then the question comes, if this time again add an element to the array subscript 7 position, at this time theoretically tail+1=8, that is already out of bounds, need to expand the array, but we look at the location of the arrays 0, 1, 2 due to the team operation, the three positions are empty,     If you are expanding at this point, you will waste space. Let's think about ArrayList. In order to reduce space waste, how does it do it, by using array copy, each time the element is deleted, the element that is deleted after the element index is moved forward one bit.      However, this has resulted in a low level of efficiency. How to do it, can we change a way of thinking, we could think of the array as a "ring" connected to the end., the first position of the array, the position of the index 0, and the last position of the length-1 the position of the index is next to each other (remember the doubly linked list?). )。 It is important to note that the head is not the first position of the array index 0,tail is not the last position of the array index length-1,head and tail are actually a pointer, along with the outbound and queued operations constantly moving. If tail is moved to Length-1, if the first position of the array has no element 0, then you need to point the tail to 0, pointing backwards. at this point, when tail is equal to head, there are two cases, one is an empty queue and the other is that the queue will be full (only tail have empty locations), the array will be expanded as long as the queue is determined to be full. To recall the next 2 of the N power and 2 of the N power-1 into the binary after the look: what is the conversion of 2^n to binary is what it looks like:
2^1 = 102^2 = 1002^3 = 10002^n = 1 (n 0)

And look at what the 2^n-1 binary looks like:

2^1-1 = 012^2-1 = 0112^3-1 = 01112^n-1 = 0 (n 1)
What will be found if (2^n) & (2^n-1) = 0 Right, for example, 2^3=8 and 2^3-1=7,8 and 7 binary are 1000 and 0111,1000 respectively |     0111 = 0000, which is 0. Now look at this code ((tail = (tail + 1) & (elements.length-1)) = = head) is not beginning to understand, (tail + 1) & (elements.length-1), when tail is equal to Length-1 time is (2^n) & (2^n-1), at this time the result 0 is assigned to tail, that is, this time tail point to 0, confirms the previous we said. So if tail is not the index of the last position of the array, such as Tail=5, then 5 & (elements.length-1) is actually equal to 5 right, because tail will never be greater than length, So when tail is not equal to length-1, the result of (tail + 1) & (Elements.length-1) is tail+1 (we have analyzed H & (HashMap) in 2^n-1 equivalent to H 2^n). so from here, we can think of Arraydeque as a two-way cyclic queue., the word "as" is used here because it is simply a "ring" of code, not a "ring" on a storage structure. At this point, we finally understand ((tail = (tail + 1) & (elements.length-1) = = head) The meaning of this code, we will summarize the effect of this code: (1) The tail+1 operation, (2) If the tail+1 has crossed the bounds, the tail assignment is 0, (3) when tail and head point to the same index, the need for expansion。 Since it is necessary to expand, then we will see how the specific expansion of it.
 1/** 2 * When the array is going to be full (tail==head), the array will be twice times the capacity 3 */4 private void Doublecapacity () {5//verify head and TA Il is equal to 6 assert head = = tail; 7 int p = head; 8//record array length 9 int n = elements. Length;10//calculates the number of elements behind the head, there is no use of the JDK's own English annotation right, because the so-called queue up and down, just We look at different directions, if the picture above, it should be left instead of right11 int r = n-p; Number of elements to the right of P12//expands array length by twice times int newcapacity = n << 1;14///If at this time             The length is less than 0, then throws the IllegalStateException exception, when newcapacity will be less than 0, before we have said the int value <<1 the cross if (newcapacity < 0) 16 throw new IllegalStateException ("Sorry, deque too Big"); 17//Create an array that is twice times the size of the original array. [object[] A = "New O" BJECT[NEWCAPACITY];19//Copies the value of the original array head element to the new array System. Arraycopy (elements, p, a, 0, R); 21//Copy the element before head of the original array to the new array System. Arraycopy (elements, 0, a, r, p); 23//assigns a new array to elements24 elements = (e[]) a;25//Reset HeadIndex of the first position of the array 026 head = 0;27//reset tail The last position in the array index +1 ((length-1) + 1) tail = n;29} 
This needs to be cleared, why the array copy was made two times, of course, because the array was divided into two segments by head ... There are elements behind, and there are elements in front ... 5. Team out (remove and return to Team head Elements )
 1/** 2 * Remove and return the element of the queue header, if the queue is empty, throw a Nosuchelementexception exception 3 */4 public E Remove () {5//Call R Emovefirst method, remove element 6 return Removefirst () from Team head;         7} 8 9/**10 * @throws nosuchelementexception {@inheritDoc}11 */12 public E Removefirst () {13 Call the Pollfirst method to remove and return the element of the team header from E x = Pollfirst (); 15//If the queue is empty, throw an nosuchelementexception exception if (x = = null) + throw new Nosuchelementexception (), return x;19}20 21/**22 * Remove and return to queue header      element, if the queue is empty, returns NULL23 */24 public E poll () {25//calls the Pollfirst method, removes and returns the element of the team header, return Pollfirst (); 27  }28 public E Pollfirst () {int h = head; 31//Take out the elements of the array team head position (e) result = Elements[h]; element is null if deque empty33//If there are no elements in the array header position, the null value is returned if (result = = null) and return n     ULL;36//Set the array header position empty, that is, delete the element elements[h] = null; Must null out SLOT38         Move the head pointer forward one position. 1 head = (H +) & (elements. length-1); 40//Return the team head element to a return R ESULT;42}
Pollfirst (H + 1) & (elements. length-1) no longer need to explain the specific, do not understand the above explanation, of course, this is to deal with the critical situation. 6. Return the team header element (not deleted)
1     /** 2      *  Returns the element of the queue header, if the queue is empty, throws a Nosuchelementexception exception 3      */4 public     E element () {5         // Call the GetFirst method to get the element of the team header 6         return GetFirst (); 7     } 8  9     /**10      * @throws nosuchelementexception {@ inheritdoc}11      */12 public     e GetFirst () {         //get array head position element         e x = elements[head];15         // If the element of the head position of the array is null, an exception is thrown if         (x = = null), and the             New Nosuchelementexception ();         return x;19     }     /**22      * Returns the element of the queue header, if the queue is empty, returns NULL23      */24 public     E Peek () {         //Call Peekfirst method, Gets the element of the head of the team         return Peekfirst ();     }28 public     E Peekfirst () {         //Get the element of the array head position and return         return elements [head]; Elements[head] is null if deque empty32     }
To this, arraydeque as the operation method of queue, we analyzed, the main difficulty is to think of Arraydeque as a two-way circular queue, head and tail pointer is how to move, and if you do "ring",     If you do not understand it, be sure to check the diagram a few more times, and do a bit of displacement and OR operation. Of course Arraydeque as a two-way queue and there are some deque-specific methods, as well as some methods as a stack, here we do not see more, interested, you can try to analyze, because the bottom is an array, some other operations understand is very simple,     Do not understand can go to the memory of the "write to the JDK series of jdk1.6 container (1)-arraylist source code analysis." Of course we're talking about arraydeque and LinkedList are simple queues (neither thread-safe nor blocking), There are also two types of queues in Java's concurrent package Java.util.concurrent package, concurrent queue Concurrentlinkedqueue and blocking queue blockingqueue.  These two are carefully analyzed when we analyze Java and contract in the future. The arraydeque of the queue is finished!

Queue of Arraydeque Source

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.