Learn the DS data structure extension in PHP together

Posted by inaba on Thu, 23 Dec 2021 09:25:31 +0100

In the previous articles on SPL, we have learned some data structure related data structure objects in SPL, which are very powerful and easy to use. The most important thing is that SPL has been integrated into the PHP source code, and we don't need to install other extensions separately. However, the content of the DataStruct extension library we are going to learn today is more abundant, but correspondingly, we need to install this set of extensions manually. If you don't have a high demand for data structures, it's enough to use the related objects in SPL. However, if you need richer data structure types, this DS extension is a better choice.

The installation of DS extensions is no different from that of other ordinary extensions, and does not require additional component support on the operating system. You can install them directly.

Stack

First, let's start with the stack, the most basic data structure. The stack structure in DS is very simple and easy to use.

$stack = new \Ds\Stack();
var_dump($stack);
// object(Ds\Stack)#1 (0) {
// }

$stack = new \Ds\Stack([1, 2, 3]);
var_dump($stack);
// object(Ds\Stack)#2 (3) {
//     [0]=>
//     int(3)
//     [1]=>
//     int(2)
//     [2]=>
//     int(1)
//   }

The two methods of instantiating stack objects are actually different parameters. If we directly pass an array to the constructor, the array will be used as an element inside the stack for us to use.

$stack->push(4);
$stack->push(5);
var_dump($stack);
// object(Ds\Stack)#2 (5) {
//     [0]=>
//     int(5)
//     [1]=>
//     int(4)
//     [2]=>
//     int(3)
//     [3]=>
//     int(2)
//     [4]=>
//     int(1)
//   }

var_dump($stack->pop()); // int(5)
var_dump($stack->pop()); // int(4)
var_dump($stack);
// object(Ds\Stack)#2 (3) {
//     [0]=>
//     int(3)
//     [1]=>
//     int(2)
//     [2]=>
//     int(1)
//   }

push() is to push the data onto the stack, and pop() is to pop up the elements at the top of the stack. The main operations on the stack are actually these two methods and functions.

var_dump($stack->peek()); // int(3)
// object(Ds\Stack)#2 (3) {
//     [0]=>
//     int(3)
//     [1]=>
//     int(2)
//     [2]=>
//     int(1)
//   }

peek() function directly obtains the data at the top of the stack, but it should be noted that it will not pop up the elements at the top of the stack. That is, this peek() method will only get the content of the data and will not change the data inside the stack.

var_dump($stack->count()); // int(3)
var_dump($stack->isEmpty()); // bool(false)
var_dump($stack->toArray());
// array(3) {
//     [0]=>
//     int(3)
//     [1]=>
//     int(2)
//     [2]=>
//     int(1)
//   }

$stack->clear();
var_dump($stack);
// object(Ds\Stack)#2 (0) {
// }

count() returns the number of elements inside the stack, isEmpty() is used to judge whether the stack is empty, toArray() directly returns the data inside the stack in the form of array, and the clear() method is used to empty the stack. These methods and functions are very simple, so I won't explain more. Finally, let's look at the assignment copy operation of the stack object.

$a = $stack;
$a->push(4);
var_dump($stack);
// object(Ds\Stack)#2 (1) {
//     [0]=>
//     int(4)
//   }

$b = $stack->copy();
$b->push(5);

var_dump($stack);
// object(Ds\Stack)#2 (1) {
//     [0]=>
//     int(4)
//   }

var_dump($b);
// object(Ds\Stack)#1 (2) {
//     [0]=>
//     int(5)
//     [1]=>
//     int(4)
//   }

\The $Stack object is an instantiated object and is passed by reference in normal assignment operations. In the above, we cleared $Stack, and here we let $a equal to this $Stack, and then operate $A. accordingly, the contents of $Stack have also changed. For reference passing, we usually use\_\_ The Stack class directly provides us with a copy() method, which can directly obtain a copy of a Stack object, or a new Stack object. Just like $b in the above code, when the copy() method is used to assign $b, it becomes a new Stack object, and any operation of $b has nothing to do with the $Stack object. We can see that the object id is also completely different.

queue

For queues as like as two peas, the overall function and stack are almost the same, and the way they implement them is basically the same. The specific difference in the implementation level is reflected in the difference between the bomb stack and the queue, that is, the push() method is different in the implementation.

$queue = new \Ds\Queue();
var_dump($queue);
// object(Ds\Queue)#3 (0) {
// }

$queue = new \Ds\Queue([1, 2, 3]);
var_dump($queue);
// object(Ds\Queue)#4 (3) {
//     [0]=>
//     int(1)
//     [1]=>
//     int(2)
//     [2]=>
//     int(3)
//   }

$queue->push(4);
$queue->push(5);
var_dump($queue);
// object(Ds\Queue)#4 (5) {
//     [0]=>
//     int(1)
//     [1]=>
//     int(2)
//     [2]=>
//     int(3)
//     [3]=>
//     int(4)
//     [4]=>
//     int(5)
//   }

var_dump($queue->pop()); // int(1)
var_dump($queue->pop()); // int(2)
var_dump($queue);
// object(Ds\Queue)#4 (3) {
//     [0]=>
//     int(3)
//     [1]=>
//     int(4)
//     [2]=>
//     int(5)
//   }

It can be seen that in the queue, the order of the data we push() in is 1,2,3,4,5, that is, put the data at the bottom of the internal array, and pop() out of the queue directly takes the data at the top, which realizes the effect of first in first out. Comparing the data content of the above stack, we can find that the data of the stack is reversed when pushing (), such as 5, 4, 3, 2 and 1. Then, in pop(), the data is actually taken out from the top, but the stack pushes the data () to the top of the internal array, and then takes out the data directly from the top to achieve the last in first out effect.

Priority queue

Having finished the two most important data structures, let's look at the extended structure of a queue, that is, the implementation of priority queue. In fact, this queue has an additional parameter when pushing () data, that is, the priority of the data. The higher the priority, the higher the priority. Other methods are not much different from ordinary queue and stack methods.

$pQueue = new \Ds\PriorityQueue();

$pQueue->push(1, 100);
$pQueue->push(2, 101);
$pQueue->push(3, 99);

var_dump($pQueue);
// object(Ds\PriorityQueue)#3 (3) {
//     [0]=>
//     int(2)
//     [1]=>
//     int(1)
//     [2]=>
//     int(3)
//   }

var_dump($pQueue->pop()); // int(2)
var_dump($pQueue->pop()); // int(1)
var_dump($pQueue->pop()); // int(3)

Map

Finally, let's learn a Map data structure, which is actually a data structure in the form of K/V key value pairs such as HaspMap. It can only be said that the array in PHP is too powerful and fully compatible with this data structure, so a separate Map structure has no practical significance.

$map = new \Ds\Map(['a'=>1, 2, 5=>3]);
var_dump($map);
// object(Ds\Map)#5 (3) {
//     [0]=>
//     object(Ds\Pair)#6 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       int(1)
//     }
//     [1]=>
//     object(Ds\Pair)#7 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [2]=>
//     object(Ds\Pair)#8 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//   }


var_dump($map->get(0)); // int(2)
var_dump($map->get(5)); // int(3)

$map->put('b', '4');
$map->put('c', [1, 2, 3]);
$map->put('d', new class{public $t = 't';});

var_dump($map);
// object(Ds\Map)#5 (6) {
//     [0]=>
//     object(Ds\Pair)#7 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       int(1)
//     }
//     [1]=>
//     object(Ds\Pair)#6 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [2]=>
//     object(Ds\Pair)#9 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [3]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "4"
//     }
//     [4]=>
//     object(Ds\Pair)#11 (2) {
//       ["key"]=>
//       string(1) "c"
//       ["value"]=>
//       array(3) {
//         [0]=>
//         int(1)
//         [1]=>
//         int(2)
//         [2]=>
//         int(3)
//       }
//     }
//     [5]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       string(1) "d"
//       ["value"]=>
//       object(class@anonymous)#8 (1) {
//         ["t"]=>
//         string(1) "t"
//       }
//     }
//   }

$map->remove('d');
$map->remove('c');

var_dump($map);
// object(Ds\Map)#5 (4) {
//     [0]=>
//     object(Ds\Pair)#8 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       int(1)
//     }
//     [1]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [2]=>
//     object(Ds\Pair)#11 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [3]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "4"
//     }
//   }

In languages such as Java, array and HashMap are two things, or two collection objects. For example, list \ < obj \ > is a data collection, and Map \ < obj \ > is a HashMap collection. Correspondingly, in this generic collection of Java, we need to add and obtain data by using methods like get(), put(), and remove() like the Map in the DS extension.

The Map data structure is quite different from the methods implemented in the above data structures such as stack and queue.

var_dump($map->first());
// object(Ds\Pair)#8 (2) {
//     ["key"]=>
//     string(1) "a"
//     ["value"]=>
//     int(1)
//   }

var_dump($map->last());
// object(Ds\Pair)#8 (2) {
//     ["key"]=>
//     int(5)
//     ["value"]=>
//     int(3)
//   }

var_dump($map->sum()); // int(10)

var_dump($map->hasKey('b')); // bool(true)
var_dump($map->haskey('bb')); // bool(false)

var_dump($map->hasValue('4')); // bool(true)
var_dump($map->hasValue(4)); // bool(false)

It has first() and last() methods to get the first and last data elements directly. There is also a sum() method to obtain the number of data elements. At the same time, you can judge the existence of the specified Key or Value through hasKey() and hasValue(). Is it a bit like key_exists() and in_array() these two methods. Of course, we can also directly obtain the contents of these keys and values.

var_dump($map->keys());
// object(Ds\Set)#10 (4) {
//     [0]=>
//     string(1) "a"
//     [1]=>
//     int(0)
//     [2]=>
//     int(5)
//     [3]=>
//     string(1) "b"
//   }

var_dump($map->values());
// object(Ds\Vector)#10 (4) {
//     [0]=>
//     int(1)
//     [1]=>
//     int(2)
//     [2]=>
//     int(3)
//     [3]=>
//     string(1) "4"
//   }

We can see that the content returned by keys() is an object of type Set, while the content returned by values() is an object of type Vector. These two types are also data structure types in DS, which we will learn again in the next article. In addition to keys and Values, it can also directly return a Vector type object collection structure, using the paris() method.

var_dump($map->pairs());
// object(Ds\Vector)#9 (4) {
//     [0]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       int(1)
//     }
//     [1]=>
//     object(Ds\Pair)#11 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [2]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [3]=>
//     object(Ds\Pair)#8 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "4"
//     }
//   }

In the Map object, some methods for sorting data, merging two maps and intercepting some data are also provided. Post the code directly.

$map->ksort();
var_dump($map);
// object(Ds\Map)#5 (4) {
//     [0]=>
//     object(Ds\Pair)#9 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       int(1)
//     }
//     [1]=>
//     object(Ds\Pair)#8 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [2]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "4"
//     }
//     [3]=>
//     object(Ds\Pair)#11 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//   }

$map->reverse();
var_dump($map);
// object(Ds\Map)#5 (4) {
//     [0]=>
//     object(Ds\Pair)#11 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [1]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "4"
//     }
//     [2]=>
//     object(Ds\Pair)#8 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [3]=>
//     object(Ds\Pair)#9 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       int(1)
//     }
//   }

$newMap = new \Ds\Map();
$newMap->put('a', 'a');
$newMap->put('b', 'b');
$newMap->put('e', 'e');

var_dump($map->diff($newMap));
// object(Ds\Map)#8 (2) {
//     [0]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [1]=>
//     object(Ds\Pair)#11 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//   }

var_dump($map->union($newMap));
// object(Ds\Map)#8 (5) {
//     [0]=>
//     object(Ds\Pair)#11 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [1]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "b"
//     }
//     [2]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [3]=>
//     object(Ds\Pair)#6 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       string(1) "a"
//     }
//     [4]=>
//     object(Ds\Pair)#7 (2) {
//       ["key"]=>
//       string(1) "e"
//       ["value"]=>
//       string(1) "e"
//     }
//   }

var_dump($map->xor($newMap));
// object(Ds\Map)#8 (3) {
//     [0]=>
//     object(Ds\Pair)#7 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [1]=>
//     object(Ds\Pair)#6 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [2]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       string(1) "e"
//       ["value"]=>
//       string(1) "e"
//     }
//   }

var_dump($map->intersect($newMap));
// object(Ds\Map)#8 (2) {
//     [0]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "4"
//     }
//     [1]=>
//     object(Ds\Pair)#6 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       int(1)
//     }
//   }

$map->putAll($newMap);
var_dump($map);
// object(Ds\Map)#5 (5) {
//     [0]=>
//     object(Ds\Pair)#8 (2) {
//       ["key"]=>
//       int(5)
//       ["value"]=>
//       int(3)
//     }
//     [1]=>
//     object(Ds\Pair)#6 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "b"
//     }
//     [2]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//     [3]=>
//     object(Ds\Pair)#7 (2) {
//       ["key"]=>
//       string(1) "a"
//       ["value"]=>
//       string(1) "a"
//     }
//     [4]=>
//     object(Ds\Pair)#12 (2) {
//       ["key"]=>
//       string(1) "e"
//       ["value"]=>
//       string(1) "e"
//     }
//   }

var_dump($map->slice(1, 2));
// object(Ds\Map)#12 (2) {
//     [0]=>
//     object(Ds\Pair)#7 (2) {
//       ["key"]=>
//       string(1) "b"
//       ["value"]=>
//       string(1) "b"
//     }
//     [1]=>
//     object(Ds\Pair)#10 (2) {
//       ["key"]=>
//       int(0)
//       ["value"]=>
//       int(2)
//     }
//   }

var_dump($map->skip(2));
// object(Ds\Pair)#12 (2) {
//     ["key"]=>
//     int(0)
//     ["value"]=>
//     int(2)
//   }

The code contains a lot of content, and the annotation displayed is the result of our execution. It can be seen that the method functions provided by the data structure Map are really rich. And we haven't fully shown it here. It also has some similar methods. If you are interested, you can explore more by yourself. However, as mentioned above, arrays in PHP are very convenient, so the application scenarios of this Map are limited, or some special scenarios that require objects to represent the array structure will be useful.

summary

Isn't it interesting? As we said at the beginning, it's OK to understand and learn, but if the real business only needs some simple stack or queue implementation, it's OK to directly use the data structure in the SPL extension library. Of course, we haven't finished the content in DS. Vector and Set believe that students who have studied Java must be familiar. In the next article, we will continue to learn the remaining data structures in DS.

Test code:

https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/02/source/2. Learn the DS data structure extension in PHP (I)

Reference documents:

https://www.php.net/manual/zh/book.ds.php

Topics: PHP