Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area! “

Time:2020-11-25

Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area!

Author: little brother Fu

Blog: https://bugstack.cn

Precipitation, sharing, growth, let yourself and others can have a harvest!

1、 Preface

The most important thing to buy a house is the house pattern!

If you can accept the geographical location and square meter price, the most important thing is the housing pattern.what? mother-in-law! You A kind of Get out of here!The pattern of housing actually corresponds to the fundamental of program development, that is, data structure. Some local tyrants can exchange money for space, and the room pattern is bigger. Those who have no money can only choose small economic space to save money. Whether it is very similar to different data structures directly affects whether space changes time or time changes space. Then, take a closer look at the rooms, such as the living room sofa sitting portrait hash table, going to the kitchen to call in the stack “LIFO”, going to the toilet to call the queue “FIFO”, going back to each room at night like entering the array. So how comfortable you can live in this room depends largely on the layout of the whole room. Also, you can write the program well, because the data structure is well defined.

So what are the basic data structures that determine the program development?

Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area!

The data structure in program development can be divided into these eight categories;arrayLinked listStackqueueHash tabletreeheapchart。 Among them, array, linked list, hash table, tree are most directly or indirectly used in program development. The corresponding implementation classes can include the following;

type realization article
array ArrayList ArrayList has so much knowledge? A designated position insertion will make Xie plane dizzy! )
Linked list LinkedList Is LinkedList inserted faster than ArrayList? Are you sure? )
tree 2-3 trees, red and black trees Explain the 2-3 balance tree “the predecessor of the red and black tree”) < br / > the operation principle of the red black tree, analyze when to dye, how to rotate, and what is the relationship with the 2-3 tree.)
Hash table HashMap HashMap core knowledge, disturbance function, load factor, capacity expansion list splitting, deep learning) < br / > HashMap data insertion, search, deletion, traversal, source code analysis)
Stack Stack<String>
queue Queue<String>、Deque<String>
  • As mentioned above, in addition to stack and queue, little brother Fu has written a very detailed article to introduce the core knowledge of other data structures and specific implementation applications.
  • Next, we will introduce the rest of the stack and queue in this chapter. In fact, this part of knowledge is not difficult. With the above understanding of arrays and linked lists, other data structures are basically extended from these two aspects.

This article involves more code and practice verification draft. Welcome official account No.Bugstack wormhole stack, reply to download to get a link to open, find ID: 19 to get!

2、 Interview questions

Thank youIs this next to you?

answerOh, thanks tank, my brother. I haven’t graduated yet. I want to see the face of the interviewers from big companies.

askPlane, last timeLinkedListI’ll ask you.LinkedListCan I use it as a queue?

answer: ah? Yes, yes!

askCan arrays be used as queues? Can’t? What’s the feature of pair columns?

answerQueue first in, first out, um.

askDo you have any more? Do you know about delay queues? What about double ended queues?

The plane took the hand of the tank to go out, and also took a “face to face manual” sent by the interviewer. The tank said to the aircraft, the foundation is not solid, the ground is shaking, I want to study hard.

3、 Data structure

We have mastered the array and linked list stand up, is the stack and queue!

Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area!

As shown in the figure, the knowledge of data structure in this chapter is not difficult. As long as you have learned arrays and linked lists, you will have a foundation for mastering other data structures, but you have added some restrictive rules for data storage and reading. Especially for data structures such as linked lists, the efficiency of only operating the head and tail is very high.

4、 Source code learning

1. Let’s talk about a abandoned stack < E > first

Sometimes, instead of making mistakes! Fear is to know only a little.

What we discard is not the stack data structure, but the stack implementation class. If you use it in business development without knowing it, it will probably affect the system performance. In fact, stack is not recommended, but why not? We can find out the root cause by using and source code analysis.

Before learning, we should have a general understanding of this data structure. It is very similar to the arrangement of badminton. It is a kind of last in, first out queue, as follows;

Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area!

1.1 function use

@Test

The example is rightStackStack use, if not run, can you know its output?

Test results:

Get the last element: CCC

See the test results, and you think the answer is consistent?

  • Peek, which means peek, means to have a look at it and won’t pop up the element. Meet the last in, first out rule. It looks at the last element put inccc
  • Lastelement, firstelement, literal method to get the last and the first element.
  • Pop is the pop-up element in the queue. After pop-up, it also means to clear and delete the elements in this position.

1.2 source code analysis

We saidStackStack, this implementation class is not recommended to use, need to see from its source code.

/**
 *
 * <p>A more complete and consistent set of LIFO stack operations is
 * provided by the {@link Deque} interface and its implementations, which
 * should be used in preference to this class.  For example:
 * <pre>   {@code
 *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
 *   
 * @author  Jonathan Payne
 * @since   JDK1.0
 */
public class Stack<E> extends Vector<E>
s.push("aaa");

public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}
  1. StackThe stack was based on inheritance in the JDK 1.0 eraVector, implemented. itselfVectorIs a class not recommended to use, mainly because of its operation method lock(synchronized)The force is too thick. It’s all about the method.
  2. StackThe bottom layer of the stack is to useVectorArray implementation, learningArrayListWhen we know that array structures are needed to add elements and excel throughSystem.arraycopyTo expand the capacity. The stack itself is characterized by the operation of the first and last elements, and it does not need to traverse, so the use of array structure is not ideal.
  3. At the same time, it is clearly marked on the annotation of this method, which is recommendedDeque<Integer> stack = new ArrayDeque<Integer>();Although this is also an array structure, it does not have coarse-grained locks. At the same time, it can apply for the specified space, and it is better than the operation in the expansionStack。 And it is also a double ended queue, which is more flexible to use.

2. Arraydeque

ArrayDequeIt is a dynamically scalable double ended queue based on arrays, which means that you can insert and pop elements at the head and end of the queue at the same time. When the number of elements exceeds the initialization length of the array, the data needs to be expanded and migrated.

Data structure and operation, as follows;

Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area!

From the above figure, we can learn the following knowledge points;

  1. Double end queue is based on array implementation, so expand the migration data operation.
  2. push, like insertion at the endofferLastInsert it into the head so that both ends meet the requirements of LIFO.
  3. On the whole, the double ended queue is a ring. Therefore, if you continue to insert elements after capacity expansion, you can also meet the requirements of last in first out.

2.1 function use

@Test

The above part of the code is consistent with that shown in the above figure. According to the analysis in the figure, we can see the output result, as follows:;

Data out of stack:
  • i d c b a e f g h j, which exactly meets our data stack order.You can refer to the above figure for further understanding

2.2 source code analysis

ArrayDequeThis double ended queue is based on array, so there will be traces of array operation from initialization to data stack expansion in source code. Next, we will analyze them in turn.

2.2.1 initialization

new ArrayDeque<String>(1);In fact, its constructor initialization also provides several methods by default, such as you can specify the size and provide default elements.

private static int calculateSize(int numElements) {
    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);
        initialCapacity |= (initialCapacity >>>  2);
        initialCapacity |= (initialCapacity >>>  4);
        initialCapacity |= (initialCapacity >>>  8);
        initialCapacity |= (initialCapacity >>> 16);
        initialCapacity++;
        if (initialCapacity < 0)   // Too many elements, must back off
            initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 element
    }
    return initialCapacity;
}
  • In the process of initialization, it needs to find a capacity that is the multiple of the minimum 2 of your current transmission value. This is similar to the initialization of HashMap.
2.2.2 data stack

deque.push("a");Arraydeque, which provides a push methoddeque.offerFirst(“a”), consistent, because their underlying source code is the same, as follows;

addFirst:

public void addFirst(E e) {
    if (e == null)
        throw new NullPointerException();
    elements[head = (head - 1) & (elements.length - 1)] = e;
    if (head == tail)
        doubleCapacity();
}

addLast:

public void addLast(E e) {
    if (e == null)
        throw new NullPointerException();
    elements[tail] = e;
    if ( (tail = (tail + 1) & (elements.length - 1)) == head)
        doubleCapacity();
}

This part of the stack element is actually to assign values to the array. The knowledge points are as follows:;

  1. stayaddFirst()To locate the subscript,head = (head - 1) & (elements.length - 1)Because our array length is2^nMultiple of, so2^n - 1It is a binary number that is all 1, and can be used to calculate the index of the array.
  2. sameaddLast()The same method is used to locate the subscript, except that it starts from 0 and increases upward.
  3. Finally, when the head and the tile, the array needs to be expanded twicedoubleCapacity

Subscript calculation:head = (head - 1) & (elements.length - 1)

  • (0 – 1) & (8 – 1) = 7
  • (7 – 1) & (8 – 1) = 6
  • (6 – 1) & (8 – 1) = 5
2.2.3 double expansion, data migration
private void doubleCapacity() {
    assert head == tail;
    int p = head;
    int n = elements.length;
    int r = n - p; // number of elements to the right of p
    int newCapacity = n << 1;
    if (newCapacity < 0)
        throw new IllegalStateException("Sorry, deque too big");
    Object[] a = new Object[newCapacity];
    System.arraycopy(elements, p, a, 0, r);
    System.arraycopy(elements, 0, a, r, p);
    elements = a;
    head = 0;
    tail = n;
}

In fact, the above part of the source code, is twicen << 1At the same time, the data at both ends is migrated into a new array. The whole operation process is also corresponding to the above figure. For better understanding, we will do some tests on this part of the code separately.

Test code:

@Test

The above test process mainly simulates the array with 8 lengths. When the double end queue operation is carried out, the array capacity expansion and data migration operation can be run separately. The test results are as follows;

head:4
tail:4
["e","f","g","h","d","c","b","a"]
["d","c","b","a",null,null,null,null,null,null,null,null,null,null,null,null]
["d","c","b","a","e","f","g","h",null,null,null,null,null,null,null,null]
["d","c","b","a","e","f","g","h","j",null,null,null,null,null,null,"i"]

Process finished with exit code 0

It can be seen from the test results;

  1. When head and tail are equal, expand the capacity.
  2. The first data migration,System.arraycopy(elements, p, a, 0, r);d、c、b、a, into the new array.
  3. The second data migration,System.arraycopy(elements, 0, a, r, p);e、f、g、h, into the new array.
  4. Finally, try adding new elements, I and J. Each time the output result can see the change of the whole two terminal link.

3. Dual end queue LinkedList

LinkedlistIt can support dual end queues by nature, and fetching data from the beginning is also time complexity O (1). At the same time, data insertion and deletion do not need to copy data like array queueLinkedlistIt has these advantages, but it can’t be saidArrayDequeBecause array replication performance is lower than it.

LinkedList, data structure

Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area!

3.1 function use

@Test

test result

Data out of stack:
  • Look at and use the test resultsArrayDequeIt’s the same. There’s no difference in function.

3.2 source code analysis

Pressing stackdeque.push("a");deque.offerFirst("a");

private void linkFirst(E e) {
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

Pressing stackdeque.offerLast("e");

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}
  • linkFirstlinkLastThe two methods are to insert elements into the first and last nodes of the linked list. Because this is a linked list structure, there is no capacity expansion. You only need to link the two-way links.

4. Delay queue

Do you sometimes need to save some data and count down to a certain time to use it?

In the queue data structure of Java, there is also a delay queue, which can be obtained by setting the storage time and rotating training in turn.

4.1 function use

First write a delayed implementation class

public class TestDelayed implements Delayed {

    private String str;
    private long time;

    public TestDelayed(String str, long time, TimeUnit unit) {
        this.str = str;
        this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return time - System.currentTimeMillis();
    }

    @Override
    public int compareTo(Delayed o) {
        TestDelayed work = (TestDelayed) o;
        long diff = this.time - work.time;
        if (diff <= 0) {
            return -1;
        } else {
            return 1;
        }
    }

    public String getStr() {
        return str;
    }
}
  • This is equivalent to a fixed template method of delay queue, which controls the delay in this way.

Case test

@Test
public void test_DelayQueue() throws InterruptedException {
    DelayQueue<TestDelayed> delayQueue = new DelayQueue<TestDelayed>();
    delayQueue.offer(new TestDelayed("aaa", 5, TimeUnit.SECONDS));
    delayQueue.offer(new TestDelayed("ccc", 1, TimeUnit.SECONDS));
    delayQueue.offer(new TestDelayed("bbb", 3, TimeUnit.SECONDS));
    
    logger.info(((TestDelayed) delayQueue.take()).getStr());
    logger.info(((TestDelayed) delayQueue.take()).getStr());
    logger.info(((TestDelayed) delayQueue.take()).getStr());
}

test result

01:44:21.000 [main] INFO  org.itstack.interview.test.ApiTest - ccc
01:44:22.997 [main] INFO  org.itstack.interview.test.ApiTest - bbb
01:44:24.997 [main] INFO  org.itstack.interview.test.ApiTest - aaa

Process finished with exit code 0
  • In the case test, we set different sleep time, 1, 3, 5, TimeUnit.SECONDS 。
  • The test results are in 21, 22, 24, and output the queue results we want.
  • The output order of the elements in the queue does not depend on the order in which they are stored. They are determined by the length of sleep.

4.2 source code analysis

4.2.1 element stack

Stack:delayQueue.offer(new TestDelayed("aaa", 5, TimeUnit.SECONDS));

public boolean offer(E e) {
    if (e == null)
        throw new NullPointerException();
    modCount++;
    int i = size;
    if (i >= queue.length)
        grow(i + 1);
    size = i + 1;
    if (i == 0)
        queue[0] = e;
    else
        siftUp(i, e);
    return true;
}

private void siftUpUsingComparator(int k, E x) {
    while (k > 0) {
        int parent = (k - 1) >>> 1;
        Object e = queue[parent];
        if (comparator.compare(x, (E) e) >= 0)
            break;
        queue[k] = e;
        k = parent;
    }
    queue[k] = x;
}
  • About data storage andReentrantLockIt can re-enter the lock, but it is not the focus of the data structure in this chapter, which will be introduced in the following chapters.
  • DelayQueueIt is based on array implementation, so it can be dynamically expanded. In addition, the order in which it inserts elements does not affect the final output order.
  • The sorting of elements depends on the CompareTo method, that is, the length of sleep.
  • At the same time, only to achieveDelayedInterface to store elements.
4.2.2 element out of stack

Out of the stackdelayQueue.take()

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        for (;;) {
            E first = q.peek();
            if (first == null)
                available.await();
            else {
                long delay = first.getDelay(NANOSECONDS
                if (delay <= 0)
                    return q.poll();
                first = null; // don't retain ref while
                if (leader != null)
                    available.await();
                else {
                    Thread thisThread = Thread.currentT
                    leader = thisThread;
                    try {
                        available.awaitNanos(delay);
                    } finally {
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
        if (leader == null && q.peek() != null)
            available.signal();
        lock.unlock();
    }
}
  • This part of the code is a bit long, mainly the acquisition of elements.DelayQueueyesLeader-FollowrIn a variant of the pattern, when the consumer thread is waiting for await, it always waits for the first element to complete sleep.
  • This will minimize idle time and improve thread utilization.After the data structure is finished, there will be a special chapter

5. What other queues are there?

5.1 queue class structure

Face to face Manual Chapter 9 what is a queue? What is double end queue, delay to column, blocking queue, all knowledge blind area!

type realization describe
Queue LinkedBlockingQueue Bounded blocking queue composed of linked list structure
Queue ArrayBlockingQueue Bounded blocking queue composed of array structure
Queue PriorityBlockingQueue Unbounded priority queue support
Queue SynchronousQueue Blocking queues that do not store elements
Queue LinkedTransferQueue Unbounded blocking queue composed of linked list structure
Deque LinkedBlockingDeque Bidirectional blocking queue composed of linked list structure
Deque ConcurrentLinkedDeque Thread safe bidirectional blocking queue composed of linked list structure
  • In addition to the queues we’ve talked about, the rest are basically blocking queues, which are the above.
  • There is no difference in data structure, but the corresponding blocking function and locking mechanism are added.

2.5 use cases

public class DataQueueStack {
  • This is aLinkedBlockingQueueQueue use case, on the one hand, to store data, on the other hand, to obtain from the queue for consumption.
  • Because this is a blocking queue, when getting elements, if the queue is empty, it will block.
  • LinkedBlockingQueueIt is a blocking queue. Two reentrantlocks are used to achieve thread safety in and out of the queue. The await and signal of the respective condition objects are used to realize the waiting and wake-up functions.

5、 Summary

  • This is the end of this article about the data structure of stack and queue. In addition, there are some application processes of blocking queue lock. Let’s talk about lock related knowledge points later, and then focus on the introduction.
  • The design of the queue structure is very suitable for some needsLIFOperhapsFIFOAt the same time, there are double end, delay and combination function classes in the data structure of the queue, so it is very convenient to use.
  • The knowledge of data structure is the end of this chapter. If there are excellent contents, we will continue to add them later. Next chapter, brother Fu( bugstack.cn )We are going to introduce the algorithms involved in the data structure, which mainly come fromCollectionsClass.

6、 Series articles

  • ArrayList has so much knowledge? A designated position insertion will make Xie plane dizzy!
  • HashMap core knowledge, disturbance function, load factor, capacity expansion list splitting, deep learning
  • If your resume is like this, who wants you!
  • Summary of learning route resources for 5 years
  • Understand the design mode to interview more than 20K

Recommended Today

Summary of recent use of gin

Recently, a new project is developed by using gin. Some problems are encountered in the process. To sum up, as a note, I hope it can help you. Cross domain problems Middleware: func Cors() gin.HandlerFunc { return func(c *gin.Context) { //Here you can use * or the domain name you specify c.Header(“Access-Control-Allow-Origin”, “*”) //Allow header […]