站在巨人的肩膀上写代码——Spl中的三种数据结构解析
今天身体莫名get trouble,心情莫名bad。想说什么又没有什么要说的。I want to get a new object?(她不喜欢我怎么办?)嗯?%e9%9d%b3%e8%8d%a3
来简单说说Spl中三种数据结构的基本操作,这三种数据结构分别为双向链表(SplDoubleLinkedList)、堆栈(SplStack)和队列(SplQueue)。
双向链表(SplDoubleLinkedList)
首先实例化对象为$obj
$obj = new SplDoublyLinkedList();
然后我们添加三条数据到双向链表中
$obj->push(1); $obj->push(2); $obj->push(3);
再来添加一条这样的数据
$obj->unshift(10);
这个时候打印一下$obj
print_r($obj);
输出的结果会是这样
SplDoublyLinkedList Object ( [flags:SplDoublyLinkedList:private] => 0 [dllist:SplDoublyLinkedList:private] => Array ( [0] => 10 [1] => 1 [2] => 2 [3] => 3 ) )
对我们看到,1、2和3分别按照次序被添加进了链表对象的数组中,而底部(Bottom)位置的数据则是10,即使用unshift方法添加的数据,这里得知unshift的作用就是添加数据到链表底部。
再调用这个方法
$obj->rewind(); // 10
输出一下当前指针指向的节点
echo 'current: ' . $obj->current();
输出的是这个节点
current: 10
说明双向链表的rewind会将指针移动到底部。
我们再试试next方法
$obj->next(); // 1
输出当前指针指向的节点
echo 'next node: ' . $obj->current();
结果是
next node: 1
结果明了,会将current向顶部移动一个位置。
再来几个测试
$obj->next(); // 2 $obj->next(); // 3 $obj->prev(); // 2 echo 'next node: ' . $obj->current(); // 2 $obj->next(); // 3 $obj->next(); // echo 'next node: ' . $obj->current(); //
代码中反复使用了next方法和prev方法,每次指针指向的节点在代码中都有注释,并输出了两次来验证正确性,输出结果是正确的
next node: 2
next node:
并且我们知道指针超出链表的范围后会返回空值,因此接下来我们可以判断一下当前节点是否有效
if($obj->current()){ echo "Current node valid <br />"; }else{ echo "Current node invalid <br />"; }
返回值为
Current node invalid
或者可以用这样的方式来验证当前节点是否可用
if($obj->valid()){ echo "valid list <br />"; }else{ echo "invalid list <br />"; }
返回内容为
valid list
接下来是删除节点的操作,pop方法用于删除当前指针指向的节点,并返回该节点的内容
$obj->rewind(); echo "<hr /> Pop value: " . $obj->pop(); print_r($obj); echo 'current: ' . $obj->current();
输出的内容为
Pop value: 3
SplDoublyLinkedList Object ( [flags:SplDoublyLinkedList:private] => 0 [dllist:SplDoublyLinkedList:private] => Array ( [0] => 10 [1] => 1 [2] => 2 ) )current: 10
删除节点之前使用rewind重置了指针的位置到Bottom,同时pop删除了Top位置的节点。那么如果current正好指向Top位置会怎样?
$obj->next(); // 1 $obj->next(); // 2 // 把Top位置的节点从链表中删除,并返回 echo "<hr /> Pop value: " . $obj->pop() . "<br />"; echo 'current: ' . $obj->current() . '<br />'; // 10 print_r($obj);
输出
Pop value: 2
current:SplDoublyLinkedList Object ( [flags:SplDoublyLinkedList:private] => 0 [dllist:SplDoublyLinkedList:private] => Array ( [0] => 10 [1] => 1 ) )
如果current正好指向Top位置,那么调用pop之后current会失效。
最后一个要试的方法是shift,用于把Bottom位置的节点从链表中删除,并返回,执行
$obj->shift(); print_r($obj);
会只输出
SplDoublyLinkedList Object ( [flags:SplDoublyLinkedList:private] => 0 [dllist:SplDoublyLinkedList:private] => Array ( [0] => 1 ) )
另外两种数据结构的操作类似,啊,好懒,直接贴一下,要不然得很长时间。
堆栈(SplStack)
测试代码为
<?php $stack = new SplStack(); $stack->push('a'); // push操作箱堆栈里面放入一个节点到tio位置 $stack->push('b'); $stack->push('c'); echo '<pre>'; print_r($stack); echo '</pre>'; echo "Bottom: " . $stack->bottom() . "<br />"; echo "Top: " . $stack->top() . "<br />"; $stack->offsetSet(0,'C'); // 堆栈的offset=0是Top所在的位置,offset=1是top位置节点靠近bottom位置的相邻节点,以此类推 echo '<pre>'; print_r($stack); echo '</pre>'; $stack->rewind(); // 双向链表的rewind和堆栈的rewind相反,堆栈的rewind是的当前指针指向Top所在的位置,而双向链表调用之后指向bottom所在位置 echo 'current: ' . $stack->current() . '<br />'; $stack->next(); // 堆栈的next操作使指针靠近Bottom位置的下一个节点,而双向链表是靠近top的下一个节点 echo 'current: ' . $stack->current() . '<br />'; echo '<hr />'; // 遍历堆栈 $stack->rewind(); while($stack->valid()){ echo $stack->key()."=>".$stack->current() . "<br />"; $stack->next(); // next操作不从链表中删除元素 } // 删除堆栈数据 $popObj = $stack->pop(); // pop操作从堆栈里面提取出最后一个元素(top位置),同时在堆栈里面删除该节点 echo "Poped object: " . $popObj . "<br />"; echo '<pre>'; print_r($stack); echo '</pre>';
打印内容为
SplStack Object ( [flags:SplDoublyLinkedList:private] => 6 [dllist:SplDoublyLinkedList:private] => Array ( [0] => a [1] => b [2] => c ) )Bottom: a
Top: cSplStack Object ( [flags:SplDoublyLinkedList:private] => 6 [dllist:SplDoublyLinkedList:private] => Array ( [0] => a [1] => b [2] => C ) )current: C
current: b2=>C
1=>b
0=>a
Poped object: CSplStack Object ( [flags:SplDoublyLinkedList:private] => 6 [dllist:SplDoublyLinkedList:private] => Array ( [0] => a [1] => b ) )
队列(SplQueue)
测试代码为
<?php $obj = new SplQueue(); $obj->enqueue('a'); // 插入一个节点到队列里面的Top位置 $obj->enqueue('b'); $obj->enqueue('c'); echo '<pre>'; print_r($obj); echo '</pre>'; echo "Bottom: " . $obj->bottom() . "<br />"; echo "Top: " . $obj->top() . "<br />"; $obj->offsetSet(0,'A'); // 队列里面offset=0Bottom所在位置,offset=1是Top所在位置,以此类推 echo '<pre>'; print_r($obj); echo '</pre>'; $obj->rewind(); // 队列里面rewind操作是的指针指向Bottom所在位置的节点 echo 'current: ' . $obj->current() . '<br />'; $obj->rewind(); while($obj->valid()){ echo $obj->key()."=>".$obj->current() . "<br />"; $obj->next(); // next操作是的当前指针指向top方向的下一个节点 } echo "dequeue obj: ".$obj->dequeue()."\n"; // dequeue操作从队列中提取bottom位置的节点,并返回,同时从队列里面删除该元素 echo '<pre>'; print_r($obj); echo '</pre>';
打印内容为
SplQueue Object ( [flags:SplDoublyLinkedList:private] => 4 [dllist:SplDoublyLinkedList:private] => Array ( [0] => a [1] => b [2] => c ) )Bottom: a
Top: cSplQueue Object ( [flags:SplDoublyLinkedList:private] => 4 [dllist:SplDoublyLinkedList:private] => Array ( [0] => A [1] => b [2] => c ) )current: A
0=>A
1=>b
2=>c
dequeue obj: ASplQueue Object ( [flags:SplDoublyLinkedList:private] => 4 [dllist:SplDoublyLinkedList:private] => Array ( [0] => b [1] => c ) )
The End.