这是一个十分有趣的问题。三者相遇,会发生一种怪异的冲突。
当装载器模式模式实现链表的不同操作的算法之时,我们在链类表中是用$this传入链表本身。结果,算法中,无法删除链表的head。
具体表现为,函数内部,删除head成功,而返回值则记远是原始的head.
为什么呢?原来就是调用入口保护在作怪。但如果细想一下,这个保护是必须的。否则,函数流程没有返回的位置了。无法再继续下去。
所以,算法内部只能放弃删除head的想法。如何实现呢?请看以下代码:
<?php
error_reporting(E_ALL);
class csList{
public $data='';
public $parent;
public $childNodes=array();
public function __construct($data=false){
$this->data=$data;
}
//问题就是出在这里,因为这里是调用入口,本节点自然不可以被删除。
public function loadData($dataString,$className){
$obj=new $className();
$obj->loadDataString($dataString,$this);
//print_r($this); //这里是错的。
}
}
class csStringAdapter{
public function loadDataString($dataString, csList $cl, $level=0){
$spliter=array("\r\n", ',',' ');
$dataArray=explode($spliter[$level],$dataString);
for($i=0,$j=count($dataArray);$i<$j;$i++){
$newNode=new csList();
$newNode->parent = $cl;
$cl->childNodes[]=$newNode;
$dataItems=explode(' ', $dataArray[$i]);
if (strpos($dataArray[$i],$spliter[$level+1])!==false){
echo 1;// exit;
$this->loadDataString($dataArray[$i],$newNode,$level+1);
}else{
$newNode->data=$dataArray[$i];
}
}
if ((count($cl->childNodes)==1) && ($cl->data=='')){ //因为head节点是空节点,所以要删除
$cl=$cl->childNodes[0];//这样删除head是不行的。
//print_r ($cl); //但这里打印输出的结果是正确的。
}
}
}
$test = new csList();
$nodeStr='a,b,c,d,e';
$test->loadData($nodeStr,'csStringAdapter');
print_r($test); //这里打印也是错的。head总是空节点,即是无data,同时只有一个childNodes的节点
?>
明白了PHP对调用入口的保护,也就是明白了,程序中函数调用需要从哪里来,还回哪里去,那么,上面的代码就好修改了。以下是修改后的代码
<?php
error_reporting(E_ALL);
class csList{
public $data='';
public $parent;
public $childNodes=array();
public function __construct($data=false){
$this->data=$data;
}
//问题就是出在这里,因为这里是调用入口,本节点自然不可以被删除。
public function loadData($dataString,$className){
$obj=new $className();
$obj->loadDataString($dataString,$this);
//print_r($this); //这里是对的。
}
}
class csStringAdapter{
public function loadDataString($dataString, csList $cl, $level=0){
$spliter=array("\r\n", ',',' ');
$dataArray=explode($spliter[$level],$dataString);
for($i=0,$j=count($dataArray);$i<$j;$i++){
$newNode=new csList();
$newNode->parent = $cl;
$cl->childNodes[]=$newNode;
$dataItems=explode(' ', $dataArray[$i]);
if (strpos($dataArray[$i],$spliter[$level+1])!==false){
echo 1;// exit;
$this->loadDataString($dataArray[$i],$newNode,$level+1);
}else{
$newNode->data=$dataArray[$i];
}
}
if ((count($cl->childNodes)==1) && ($cl->data=='')){ //因为head节点是空节点,所以要删除
//$cl=$cl->childNodes[0];//这样删除head是不行的。
//print_r ($cl); //但这里打印输出的结果是正确的。
//我们这样修改:将子节点数据复制到父节点中,实际是放弃第一层子节点:
$cl->data=$cl->childNodes[0]->data;
$cl->childNodes=$cl->childNodes[0]->childNodes;
for($i=0,$j=count($cl->childNodes);$i<$j;$i++){
$cl->childNodes[$i]->parent=$cl;
}
}
}
}
$test = new csList();
$nodeStr='a,b,c,d,e';
$test->loadData($nodeStr,'csStringAdapter');
print_r($test); //经过这样修改,一切就正确了。
?>
分享到:
相关推荐
链表迭代器模式是一种设计模式,它在编程中扮演着重要的角色,特别是在处理集合类数据结构如链表时。在Java、C++等面向对象语言中,迭代器模式被广泛使用,它允许程序顺序访问集合对象的元素,而无需暴露其底层表示...
用于辅助学习并理解Python中的链表(Linked List)的使用规则、范例和简单操作等。
C 语言动态链表的建立 C 语言动态链表的建立是计算机编程中的一种常见技术,用于存储和管理大规模数据。动态链表是一种动态分配内存的数据结构,能够根据实际情况自动调整存储空间。下面是一个使用 C 语言编写的...
链表的知识点包括链表的基本概念、链表的类型、链表的操作、链表的应用、链表的优缺点、链表的实现、链表的算法、链表的题目、链表的实际应用、...语言、链表的设计模式、链表的性能优化、链表的并发控制、链表的测试等...
- **迭代**:通过调用遍历器的next()方法,逐个访问链表中的元素。 - **条件检查**:在遍历过程中,可以设置条件,仅处理满足条件的节点。 - **操作节点**:遍历过程中,可以对当前节点执行任意操作,如更新值或...
链表是一种基础且重要的数据结构,它在计算机科学中扮演着关键角色,特别是在处理动态数据集合时。链表不同于数组,因为它们不依赖于连续的内存空间,而是通过节点之间的引用进行连接。在这个实例中,我们将探讨两种...
4. **`main.c`和`main.out`**:`main.c`通常是程序的主入口点,它包含了调用链表库函数的实际代码示例。`main.out`可能是编译后的可执行文件,用户可以通过运行这个文件来测试链表库的功能。 5. **Makefile**:这是...
结合这两个函数,我们可以在初始化一个链表后,先调用`reverseList`函数反转链表,然后调用`printListReverse`函数打印链表。这样,就能实现从尾到头的打印。 在实际编程中,还需要考虑一些边界情况,比如链表为空...
链表 代码 链表 代码 链表 代码 链表 代码 链表 代码 链表 代码 链表 代码 链表 代码 链表 代码 链表 代码 链表 代码
在主函数`main`中,首先获取用户输入的链表长度,调用`creatlinklist`创建链表并打印原始链表的元素,接着调用`invert`逆置链表,并再次打印逆置后的链表元素,展示逆置的效果。 另外,代码中还包含了一个C语言实现...
`main`函数是程序的入口点,它首先读取用户输入的链表长度`n`,然后调用`CreateLink_L`创建链表,接着调用`LoadLink_L`打印原始链表,最后调用`ReverLink`逆置并打印逆置后的链表。 总结来说,通过上述知识点的分析...
有两个链表a和b,设结点中包含学号和姓名。从a链表中删去与b链表中相同学号的结点。
链表反转是链表操作中的一项基本技能,它涉及到链表节点之间的指针调整,使得链表的顺序与原顺序相反。本文将详细解析链表反转的原理以及C/C++语言下的实现方法。 ### 链表反转原理 链表由一系列节点组成,每个...
3. **递归调用**:对小于基准值的子链表和大于等于基准值的子链表分别进行快速排序,直到链表为空。 4. **合并链表**:将排序后的两个子链表合并为一个有序链表。 在给定的文件中,`快速排序.cpp`可能包含了具体的...
在本文中,我们将深入探讨线性单链表的创建和操作,包括链表结点的定义、链表指针类型、创建链表结点的函数、创建线性表的函数、向链表末尾追加元素、获取链表元素地址、删除链表元素以及清空链表。 首先,链表结点...
链表的创建与两链表的合并链表的创建与两链表的合并
- 调用`create()`创建第二个链表`h2`,并显示其内容。 - 调用`merge()`归并`h1`和`h2`,结果存储在`h`中。 - 最后显示归并后的链表`h`。 2. **创建链表** (`create()`): - 使用循环接收用户的输入,并根据输入...
与数组不同,链表中的元素不需连续存储,这使得插入和删除操作更为灵活,只需改变相邻节点的指针即可,而无需移动大量数据。 在多级菜单中,我们通常需要一个层次结构来表示菜单项。例如,一级菜单可以包含多个二级...