SplQueue理解使用

SPL队列(SplQueue)

一、简介

SplQueue 类通过使用一个双向链表来提供队列的主要功能。



二、类摘要

SplQueue extends SplDoublyLinkedList implements Iterator,ArrayAccess,Countable{
		//类提供的方法
		__construct(void);
		mixed dequeue(void); //获取队列头部元素
		void enqueue(mixed $value); //队列尾部插入元素
		void setIteratorMode(int $mode); //设置队列的迭代模式

		//继承的方法
		//继承父类双链表,注意双链表的模型想象成上下的,而不是左右的,上下的好理解下面这些方法的命名
		//count()方法来自接口Countable
		//current()/key()/next()/rewind()/valid() 来自接口Iterator
		//offsetExists()/offsetGet()/offsetSet()/offsetUnset() 来自接口ArrayAccess
		//serialize()/unserialize() 来自接口Serializable
		pubilc void SplDoublyLinkedList::rewind(void) //重置迭代器到开始的位置
		public int SplDoublyLinkedList::count(void) //计算双链表元素的个数
		public mixed SplDoublyLinkedList::current(void) //返回当前数组条目(the current node)
		public mixed SplDoublyLinkedList::key(void) //返回当前节点的索引值
		public void SplDoublyLinkedList::prev(void) //移动到上一个节点
		public void SplDoublyLinkedList::next(void) //移动迭代器到下一个节点
		public bool SplDoublyLinkedList::isEmpty(void) //检查双链表是否为空
		pubilc bool SplDoublyLinkedList::valid(void) //检查双链表是否包含更多的节点

		/**
		 * 返回迭代的模式
		 * IT_MODE_LIFO => int(2) 后入先出(参考栈)
		 * IT_MODE_FIFO => int(0) 先入先出(参考队列)
		 * IT_MODE_DELETE => int(1) 迭代后,元素会被移出双链表
		 * IT_MODE_KEEP => int(0) 迭代后,元素不会被移出链表
		 * 用双链表实现的栈和队列的区别就在于IteratorMode的不同:
		 * 栈为:   IT_MODE_LIFO | IT_MODE_DELETE 即 2 | 1 = 3 (迭代后删除)或者 IT_MODE_LIFO | IT_MODE_KEEP 即 2 | 0 = 2(迭代后不删除)
		 * 队列为: IT_MODE_FIFO | IT_MODE_DELETE 即 0 | 1 = 1 (迭代后删除)或者 IT_MODE_FIFO | IT_MODE_KEEP 即 0 | 0 = 0(迭代后不删除)
		 */
		public int SplDoublyLinkedList::getIteratorMode(void) 
		public void SplDoublyLinkedList::setIteratormode(int $mode) //设置链表的迭代模式
		
		/**
		 * 注意add方法和offsetSet方法的区别
		 * add在指定的索引处追加新节点
		 * offsetSet在指定的索引处更新值
		 */
		public void SplDoublyLinkedList::add(mixed $index, mixed $newval) //在指定的索引处添加新节点
		public bool SplDoublyLinkedList::offsetExists(mixed $index) //返回请求的索引是否存在
		public mixed SplDoublyLinkedList::offsetGet(mixed $index) //返回指定索引处的值
		public void SplDoublyLinkedList::offsetSet(mixed $index, mixed $newval) //设置指定索引处的值为新值
		public void SplDoublyLinkedList::offsetUnset(mixed $index) //删除指定索引处的节点(双链表会重排)

		public mixed SplDoublyLinkedList::shift(void) //弹出双链表的头部(底部)的节点(the first node)
		public mixed SplDoublyLinkedList::pop(void) //弹出双链表的尾部(顶部)的节点(the last node)

		public void SplDoublyLinkedList::unshift(mixed $value) //在双链表的头部(底部)追加节点
		public void SplDoublyLinkedList::push(mixed $value) //在双链表的尾部(顶部)追加节点

		public mixed SplDoublyLinkedList::bottom(void) //获取双链表的头部(底部)的节点(the first node)(不弹出)
		public mixed SplDoublyLinkedList::top(void) //获取双向链表的尾部(顶部)的节点(the last node)(不弹出)

		public string SplDoublyLinkedList::serialize(void) //返回序列化后的链表,形如i:0;:i:4;:i:6;:i:7;:i:8;
		//反序列化存储(没太搞懂,根据测试结果,反序列化后好像是把原来序列化后的string反序列化后又追加到了该链表中了)
		public void SplDoublyLinkedList::unserialize(string $serialized) 
	}

三、实例理解

3.1 实例一: 理解setIteratormode和getIteratorMode

<?php
$l = new SplDoublyLinkedList();


//设置遍历模式
$l->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_DELETE);
//$l->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO | SplDoublyLinkedList::IT_MODE_DELETE);


//查看各个常量的值
echo "FIFO: ".SplDoublyLinkedList::IT_MODE_FIFO.PHP_EOL; //0
echo "LIFO: ".SplDoublyLinkedList::IT_MODE_LIFO.PHP_EOL; //2
echo "KEEP: ".SplDoublyLinkedList::IT_MODE_KEEP.PHP_EOL; //0
echo "DELETE: ".SplDoublyLinkedList::IT_MODE_DELETE.PHP_EOL; //1


//检测当前链表的遍历模式设置值是多少,设置值是 遍历方向常量 和 遍历后处理常量 两类常量的 | 运算值
//检测原理(按位与)同: 
//    (7 & 4) == 4 true  即00000111 & 00000100 结果为 00000100
//    (7 & 2) == 2 true
//    (7 & 1) == 1 true
//    即 res = (7 & any) == any,if any <= 7, res is true
$mode = $l->getIteratorMode();
var_dump($mode); //1 即00000000与00000001按位或得1
var_dump(($mode & SplDoublyLinkedList::IT_MODE_FIFO) == SplDoublyLinkedList::IT_MODE_FIFO); #outputs true  (1&0)==0 true
var_dump(($mode & SplDoublyLinkedList::IT_MODE_LIFO) == SplDoublyLinkedList::IT_MODE_LIFO); #outputs false (1&2)==2 false
var_dump(($mode & SplDoublyLinkedList::IT_MODE_DELETE) == SplDoublyLinkedList::IT_MODE_DELETE); #outputs true (1&1)==1 true
var_dump(($mode & SplDoublyLinkedList::IT_MODE_KEEP) == SplDoublyLinkedList::IT_MODE_KEEP); #outputs true (1&0)==0 true


//可以看出上面的位运算能够检测数包含了何种模式
//但是因为遍历方向常量FIFO和遍历后处理常量KEEP都是0值,又因为|运算没有交换律的限制
//这样就造成了对FIFO和KEEP的直接检测模糊失效
//为了进一步达到目的,从相反的角度考虑
//直接检测是否是LIFO,是否是DELETE
//检测出这两个确定的结果就可以确定另一方面的结果了。因为两类常量值里面的值是互斥的
$isLIFO = ($mode & SplDoublyLinkedList::IT_MODE_LIFO) == SplDoublyLinkedList::IT_MODE_LIFO; 
var_dump($isLIFO);
$isDELETE = ($mode & SplDoublyLinkedList::IT_MODE_DELETE) == SplDoublyLinkedList::IT_MODE_DELETE; 
var_dump($isDELETE);
?>

3.2 实例二:理解迭代流程
<?php
$link = new SplDoublyLinkedList();
$link->push(4);
$link->push(5);
$link->push(6);
$link->push(7);
$link->push(8);
$link->push(9);
echo "双链表的迭代模式为:\n";
$link->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_KEEP);
$mode = $link->getIteratorMode();
var_dump($mode);


echo "双链表为:\n";
var_dump($link);


$node = $link->pop(); //弹出,改变链表
echo "pop弹出尾部的节点为:\n";
var_dump($node); 


$link->offsetUnset(1); 
echo "删除索引为1的位置的node节点后的双链表为: \n";
var_dump($link); //链表重排


echo "当前的节点在:\n";
$link->rewind();
$current = $link->current();
var_dump($current);


echo "下一个节点在:\n";
$link->next();
$next = $link->current();
var_dump($next);


echo "下一个的上一个的节点在:\n";
$link->prev();
$last = $link->current();
var_dump($last);


$shift = $link->shift();
echo "shift值为\n";
var_dump($shift);
var_dump($link); //弹出,改变链表


$bottom = $link->bottom();
echo "bottom值为\n";
var_dump($bottom);
var_dump($link); //获取,未改变链表


$top = $link->top();
echo "top值为:\n";
var_dump($top);
var_dump($link); //获取,未改变链表


echo "在双链表的底部追加节点\n";;
$link->unshift("233333");
var_dump($link); //追加,改变链表


echo "在双链表的顶部追加节点\n";
$link->push("11111");
var_dump($link); //追加,改变链表
?>

3.3 实例三:理解add和offsetSet的区别
<?php
$link = new SplDoublyLinkedList();
$link->push('a');
$link->push('b');
$link->push('c');
$link->push('d');
var_dump($link);


$link->add(1,'1');
var_dump($link); //在索引为1的位置上添加了一个新节点


$link->offsetSet(1, "23333");
var_dump($link); //为索引为1的节点设置了新的值
?>

3.4 实例四:理解执行过程中改变IteratorMode造成的结果
<?php
//在迭代到不同位置时,改变迭代的模式
//运行以下程序后得到与期望相差较大的结果,想了很久没有很好的理解到为什么结果是这样的,不太建议在迭代过程中改变迭代的模式(不成熟的建议)
$link = new SplDoublyLinkedList();
$link->push('A');
$link->push('B');
$link->push('C');
$link->push('D');
$link->push('E');


echo "链表为:\n";
var_dump($link);
echo "改变迭代模式 keep=>delete:\n";


$mode = $link->getIteratorMode();
echo "改变前的mode: ".$mode."\n";
$link->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_DELETE);
$mode = $link->getIteratorMode();
echo "改变后的mode: ".$mode."\n";


$link->rewind();
var_dump("开始遍历\n\n");
var_dump($link->isEmpty());


$count = $link->count();
echo "链表现在的总元素数: ".$count.PHP_EOL;
$current = $link->current();
echo "当前的元素为: \n";
var_dump($current);
$link->next();


// $mode = $link->getIteratorMode();
// echo "改变前的mode: ".$mode."\n";
// $link->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_DELETE);
// $mode = $link->getIteratorMode();
// echo "改变后的mode: ".$mode."\n";


$count = $link->count();
echo "链表现在的总元素数: ".$count.PHP_EOL;
$current = $link->current();
echo "当前的元素为: \n";
var_dump($current);
$link->next();


$count = $link->count();
echo "链表现在的总元素数: ".$count.PHP_EOL;
$current = $link->current();
echo "当前的元素为: \n";
var_dump($current);
$link->next();


$count = $link->count();
echo "链表现在的总元素数: ".$count.PHP_EOL;
$current = $link->current();
echo "当前的元素为: \n";
var_dump($current);
$link->next();


// $mode = $link->getIteratorMode();
// echo "改变前的mode: ".$mode."\n";
// $link->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_DELETE);
// $mode = $link->getIteratorMode();
// echo "改变后的mode: ".$mode."\n";


$count = $link->count();
echo "链表现在的总元素数: ".$count.PHP_EOL;
$current = $link->current();
echo "当前的元素为: \n";
var_dump($current);
$link->next();


$valid = $link->valid();
echo "valid: ";
var_dump($valid);
var_dump($link);
?>

3.5 实例五:理解SplQueue的简单使用

<?php  
class Test {  
	public static function foo() {  
		echo 'Test::foo() called'.PHP_EOL;  
	}  
	public static function bar() {  
		echo 'Test::bar() called'.PHP_EOL;  
	}  
	public static function msg($msg) {  
		echo "$msg".PHP_EOL;  
	}  
}  


$queue = new SplQueue();  
//SplQueue遍历方向从始至终都是FIFO无需像SplDoublyLinkedList进行设置,只需设置迭代完成后是否移除元素
$queue->setIteratorMode(SplQueue::IT_MODE_DELETE);  
//追加元素到队列中
$queue->enqueue(array("Test", "foo"));  
$queue->enqueue(array("Test", "bar"));  
$queue->enqueue(array("Test", "msg", "Hi there!"));  


var_dump($queue);
foreach ($queue as $task) { 
	if (count($task) > 2) {  
		list($class, $method, $args) = $task;
		echo "class: ".$class."\n";
		echo "method: ".$method."\n";
		echo "args: ".$args."\n";
		$class::$method($args);  
	} else {
		var_dump($task);
		list($class, $method) = $task; 
		echo "class: ".$class."\n";
		echo "method: ".$method."\n";
		$class::$method();  
	}  
}  
?> 



  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值