[PHP data structure] logical operations related to queues

Time:2021-10-17

In the logical structure, we have learned a very classic structure type: stack. Today, let’s learn another classic logical structure type: queue. I believe many students have used cache queue tools such as redis and rabbitmq. In fact, database and program code can realize the operation of queue. Just like stack, queue also has its specific rules. As long as this rule is met, it is called queue.

What is a queue?

Compared with stack, queue is a sequential logical structure of first in first out (FIFO). What is first in, first out? Just like our queue, when we go to the bank or hospital, we always take a number at the door, which is called in order. People who come first can do business or see a doctor first. This is a typical queue. Similarly, daily queuing is a standard queuing mode. If someone cuts in the queue, we can think that it has higher priority if there is a good reason. This is a special form of elements in the queue. Just as we give priority to pregnant women when waiting for the subway or bus, there is also a priority window for soldiers when queuing to buy train tickets. However, this is not within the scope of our discussion this time.

https://imgs.developpaper.com/imgs/1575433-20210723085733759-1635257075.jpg

When queuing at the bus stop, the first person in line can certainly get on the bus first, and then in turn. At this time, you come to the bus stop, so you can only row last. This is the concrete form of queue.

Similarly, like stack, there are some nouns we need to understand. When you come to the bus stop and stand last, this operation is called “joining the queue”. When the bus enters the station, the first passenger gets on the bus. This operation is called “out of line”. The position of the first passenger is called “head of the team”. As the last passenger in the current queue, your position is called “tail of the team”. Back to the code logic, that is to say, the queue is from the “tail” to “join the team” and from the “head” to “leave the team”.

Sequential queue

OK, let’s look at the code directly. The first thing we see is the implementation of the sequence team.

class SqQueue{
    public $data;
    public $front;
    public $rear;
}

Since it is a sequential team, we still use an array data to represent the elements in the team. Then define two pointers front and rear to represent the head and tail of the team. Because it is a sequential queue, the pointer here actually saves the subscript of the array. The next operation is actually very simple, “join the team” with rear + +, and “leave the team” with front + +.

function InitSqQueue(){
    $queue = new SqQueue();
    $queue->data = [];
    $queue->front = 0;
    $queue->rear = 0;
    return $queue;
}

function EnSqQueue(SqQueue &$queue, $e){
    $queue->data[$queue->rear] = $e;
    $queue->rear ++;
}

function DeSqQueue(SqQueue &$queue){
    //Queue is empty
    if($queue->front == $queue->rear){
        return false;
    }
    $e = $queue->data[$queue->front];
    $queue->front++;
    return $e;
}

$q = InitSqQueue();
EnSqQueue($q, 'A');
EnSqQueue($q, 'B');
print_r($q);
// SqQueue Object
// (
//     [data] => Array
//         (
//             [0] => A
//             [1] => B
//         )

//     [front] => 0
//     [rear] => 2
// )

Does it feel that after learning stack, the queue is also well understood. When initializing the queue, it is OK to make the pointer at the head and tail of the queue both 0 subscript records. When joining the queue, the tail of the queue is added. In this code, we join the queue with two elements, and the printed sequential queue content is shown in the comments.

EnSqQueue($q, 'C');
EnSqQueue($q, 'D');
EnSqQueue($q, 'E');
print_r($q);
// SqQueue Object
// (
//     [data] => Array
//         (
//             [0] => A
//             [1] => B
//             [2] => C
//             [3] => D
//             [4] => E
//         )

//     [front] => 0
//     [rear] => 5
// )

echo DeSqQueue($q), PHP_EOL; // A
echo DeSqQueue($q), PHP_EOL; // B
echo DeSqQueue($q), PHP_EOL; // C
echo DeSqQueue($q), PHP_EOL; // D
echo DeSqQueue($q), PHP_EOL; // E

echo DeSqQueue($q), PHP_EOL; // 

print_r($q);
// SqQueue Object
// (
//     [data] => Array
//         (
//             [0] => A
//             [1] => B
//             [2] => C
//             [3] => D
//             [4] => E 
//         )

//     [front] => 5
//     [rear] => 5
// )

When leaving the team, let the front add 1. However, when leaving the queue, we also need to judge whether all the elements in the array are out of the queue. Here, we only use a very simple judgment condition, that is, whether front and rear are equal to judge whether the queue is empty. You can use a diagram to help you understand the code.

https://imgs.developpaper.com/imgs/1575433-20210723085734094-1439671279.jpg

Circular queue

I believe many students have seen it. The queue operation only modifies the pointer records at the head and tail of the queue, but the array will always increase. In this way, if it continues to increase, this array will occupy the memory. This is certainly not a good queue implementation. In fact, in C language, arrays are given a fixed length. The array in PHP is more like a hash structure, so it can grow indefinitely. We don’t need to define a specific array length at the beginning. This is also the convenience of PHP, but what should we do if we don’t want to waste memory space? Just like in C language, we also specify a length for the array in PHP, and use the very classic “circular queue” to solve the storage problem of queue array. As shown in the figure below:

https://imgs.developpaper.com/imgs/1575433-20210723085734369-77128041.jpg

In fact, within the limited array space, when we reach the maximum value of the array, we save the new data back to the previous subscript position. For example, we have 6 elements in the figure. The current team head is in the 2 subscript and the team tail is in the 5 subscript. If we join an element, the end of the team moves to the 6 subscript. If you add another element, the end of the queue will move back to the 0 subscript. If you continue to add, when the end of the queue subscript is equal to the head of the queue subscript minus 1, we think the queue is full and can’t add any more elements.

Similarly, during the out of team operation, we also operate the team head element circularly. When the team head element reaches the subscript of 6 and continues to be out of the team, it will also return to the subscript of 0 and continue to be out of the team. When the head and tail of the queue are equal, the current queue can also be determined as an empty queue.

From this, we can see that compared with ordinary linear queues, circular queues have one more queue full state. Let’s look at how to judge the full condition of the team directly from the code.

define('MAX_QUEUE_LENGTH', 6);

function EnSqQueueLoop(SqQueue &$queue, $e){
    //Determine whether the queue is full
    if(($queue->rear + 1) % MAX_QUEUE_LENGTH == $queue->front){
        return false;
    }
    $queue->data[$queue->rear] = $e;
    $queue->rear = ($queue->rear + 1) % MAX_ QUEUE_ LENGTH; //  Change to cyclic subscript
}

function DeSqQueueLoop(SqQueue &$queue){
    //Queue is empty
    if($queue->front == $queue->rear){
        return false;
    }
    $e = $queue->data[$queue->front];
    $queue->front = ($queue->front + 1) % MAX_ QUEUE_ LENGTH; //  Change to cyclic subscript
    return $e;
}

$q = InitSqQueue();
EnSqQueueLoop($q, 'A');
EnSqQueueLoop($q, 'B');
EnSqQueueLoop($q, 'C');
EnSqQueueLoop($q, 'D');
EnSqQueueLoop($q, 'E');

EnSqQueueLoop($q, 'F');

print_r($q);
// SqQueue Object
// (
//     [data] => Array
//         (
//             [0] => A
//             [1] => B
//             [2] => C
//             [3] => D
//             [4] => E
//[5] = > // tail
//         )

//     [front] => 0
//     [rear] => 5
// )

echo DeSqQueueLoop($q), PHP_EOL;
echo DeSqQueueLoop($q), PHP_EOL;
print_r($q);
// SqQueue Object
// (
//     [data] => Array
//         (
//             [0] => A
//             [1] => B
//[2] = > C // header
//             [3] => D
//             [4] => E
//[5] = > // tail
//         )

//     [front] => 2
//     [rear] => 5
// )

EnSqQueueLoop($q, 'F');
EnSqQueueLoop($q, 'G');

EnSqQueueLoop($q, 'H');
print_r($q);
// SqQueue Object
// (
//     [data] => Array
//         (
//             [0] => G
//[1] = > b // tail
//[2] = > C // header
//             [3] => D
//             [4] => E
//             [5] => F
//         )

//     [front] => 2
//     [rear] => 1
// )

The subscript movement of outgoing and incoming teams and the judgment of team full are based on (queue – > rear + 1)% max_ QUEUE_ In the form of length. Is it very clever to obtain the current cyclic subscript according to the modulus of queue length. I have to feel the wisdom of my ancestors! Of course, this is also the basic mathematical principle. Therefore, we should review the knowledge related to mathematics when learning data structure!

Chain queue

Are you confused about the sequential queue? It doesn’t matter. The chain structure of the queue is actually simpler than the sequential structure, because it really only needs to operate the pointers at the head and tail of the queue, and other things really don’t need to be considered. And this pointer is really a pointer to a specific object.

class LinkQueueNode{
    public $data;
    public $next;
}

class LinkQueue{
    public $first; //  Queue head pointer
    public $rear; //  Tail pointer
}

Here we need two basic physical structures. One is the node and the other is the queue object. The node object is a normal linked list structure, nothing special. The queue object is even simpler. One attribute is the queue head pointer and the other attribute is the queue tail pointer.

function InitLinkQueue(){
    $node = new LinkQueueNode();
    $node->next = NULL;
    $queue = new LinkQueue();
    $queue->first = $node;
    $queue->rear = $node;
    return $queue;
}

function EnLinkQueue(LinkQueue &$queue, $e){
    $node = new LinkQueueNode();
    $node->data = $e;
    $node->next = NULL;

    $queue->rear->next = $node;
    $queue->rear = $node;
}

function DeLinkQueue(LinkQueue &$queue){
    if($queue->front == $queue->rear){
        return false;
    }

    $node = $queue->first->next;
    $v = $node->data;

    $queue->first->next = $node->next;
    if($queue->rear == $node){
        $queue->rear = $queue->first;
    }

    return $v;
}

$q = InitLinkQueue();
EnLinkQueue($q, 'A');
EnLinkQueue($q, 'B');
EnLinkQueue($q, 'C');
EnLinkQueue($q, 'D');
EnLinkQueue($q, 'E');

print_r($q);
// LinkQueue Object
// (
//     [first] => LinkQueueNode Object
//         (
//             [data] => 
//             [next] => LinkQueueNode Object
//                 (
//                     [data] => A
//                     [next] => LinkQueueNode Object
//                         (
//                             [data] => B
//                             [next] => LinkQueueNode Object
//                                 (
//                                     [data] => C
//                                     [next] => LinkQueueNode Object
//                                         (
//                                             [data] => D
//                                             [next] => LinkQueueNode Object
//                                                 (
//                                                     [data] => E
//                                                     [next] => 
//                                                 )

//                                         )

//                                 )

//                         )

//                 )

//         )

//     [rear] => LinkQueueNode Object
//         (
//             [data] => E
//             [next] => 
//         )

// )

echo DeLinkQueue($q), PHP_EOL; // A
echo DeLinkQueue($q), PHP_EOL; // B

EnLinkQueue($q, 'F');
print_r($q);
// LinkQueue Object
// (
//     [first] => LinkQueueNode Object
//         (
//             [data] => 
//             [next] => LinkQueueNode Object
//                 (
//                     [data] => C
//                     [next] => LinkQueueNode Object
//                         (
//                             [data] => D
//                             [next] => LinkQueueNode Object
//                                 (
//                                     [data] => E
//                                     [next] => LinkQueueNode Object
//                                         (
//                                             [data] => F
//                                             [next] => 
//                                         )

//                                 )

//                         )

//                 )

//         )

//     [rear] => LinkQueueNode Object
//         (
//             [data] => F
//             [next] => 
//         )

// )

The out and in team code functions and test code are given together. Is it very simple. The initial queue head element is still an empty node as the starting node. Then, when joining the team, make the rear equal to the newly created node, and establish a chain relationship in the linked list. When leaving the team, it is also the same. Let first become the next hop node of the current first, that is, first – > next. The condition to judge whether the team is empty is simply whether the pointers at the head and tail of the team are equal. Chain team is actually simpler than sequence team, but similarly, next is easy to make people dizzy. Just write it down. You can still learn from the diagram:

https://imgs.developpaper.com/imgs/1575433-20210723085734779-1042439474.jpg

Array queue operation provided by PHP

Finally, just like the stack, the PHP code also provides us with a function that can be used for queue operation.

$sqQueueList = [];

array_push($sqQueueList, 'a');
array_push($sqQueueList, 'b');
array_push($sqQueueList, 'c');

print_r($sqQueueList);
// Array
// (
//     [0] => a
//     [1] => b
//     [2] => c
// )

array_shift($sqQueueList);
print_r($sqQueueList);
// Array
// (
//     [0] => b
//     [1] => c
// )

array_ The shift () function pops up the first element in the array. Please note that the subscript of the element here also changes. If we unset () the 0 subscript element of the array, the subscripts of B and C will still be 1 and 2. And array_ Shift () rearranges the array so that its subscripts remain ordered.

unset($sqQueueList[0]);
print_r($sqQueueList);
// Array
// (
//     [1] => c
// )

summary

The contents of the stack queue are introduced in two articles. But just say not practice fake tricks. Next, let’s have some real dry goods. Use stacks and queues to do problems. If we learn algorithms, we have to brush problems. If we don’t brush them every other day!!!

Test code:

https://github.com/zhangyue0503/Data-structure-and-algorithm/blob/master/3. Stack and queue / source / 3.2 queue related logical operations.php

reference material:

Data structure, Second Edition, Yan Weimin

Data structure, Second Edition, Chen Yue

High score notes on data structure, 2020 edition, tianqin postgraduate entrance examination

Official account: hard core project manager

Add wechat / QQ friends: [xiaoyuezigonggong / 149844827] get free PHP and project management learning materials

Tiktok, official account, voice, headline search, hard core project manager.

Station B ID: 482780532

Recommended Today

Fastems.Mms.Client.BaseData.Service.BaseDataService之FixtureSummaries

in Fastems.Common.dll,   Fastems.Mms.Client.BaseData.Views, In Fixtures/Views/FixtureLibraryView.xaml, the data source of Fixtures has been unclear. The records are as follows. The data source of the View is the Fixtures in Fastems.Mms.Client.Fixtures.ViewModel.FixtureLibraryViewModel, And the source of Fixtures is Fixtures = new PagingCollection(_fixtures, FixtureFilterSources);   BatchingObservableCollection _fixtures; _fixtures creates a collection object BatchingObservableCollection in the constructor public class BatchingObservableCollection : […]