tips:因为涉及到指针,所以我们使用引用来模拟,所以读者要有面向对象的知识储备。简介你可以简单地将链表理解为动态数组。它不需要一个一个地开辟空间。同时要注意它存在的主要意义或者使用场景主要是“指针功能”,可以来回指向。它在某些应用程序中起着关键作用,尤其是内存管理。因为引用涉及到记忆,往往会有一些程序边界,需要程序员有一定程度的严密逻辑才能保证代码的健壮性和健壮性,所以这个知识点是面试常见的考点。下面看一下PHP单链表的实现(附正题实现):data=$val;$this->next=$nex;}}/***TODO:构建单链表*/ClassSingleLinkList{/*创建链表,头插入方式n为节点总数*/publicfunctionheadInsert($n){/*创建一个新的链表头节点*/$head=newNode(null,null);for($i=$n;$i>0;$i--){$newNode=新节点($i,null);$head->data=$newNode->data;#将新节点分配给头节点$newNode->next=$head->next;#头节点的后继节点作为新节点的后继节点,相当于在原头节点和头节点的后继节点之间增加了一个新节点$head->next=$newNode;#使用新节点作为头节点的后继节点。此时原头节点的后继节点发生了变化}return$head;}/*尾部插入方法创建链表*/publicfunctionrearInsert($n){/*创建一个新的后节点*/$rear=newNode(null,null);对于($j=0;$j<$n;$j++){$newNode=新节点($j,null);$rear->data=$newNode->data;//$newNode=$rear->next;$rear->next=$newNode;$rear=$newNode;}返回$rear;}/***TODO:读取链表中的第i个数据*@param$listobject待插入的链表*@param$iint节点号*/publicfunctionreadIThNode($list,$i){/*如果链表为空或者i小于等于0*/if($list==null||$i<=0){echo"invalidinputparameter";返回;}/**/$p=$list->next;#设置p指向第一个节点(即头节点的后继节点))$j=0;#定时器必须初始化while($p&&$j<$i){$p=$p->next;++$j;}/*stepi*/if($p==null){#表示链表结束,没有i节点,过滤掉i大于链表长度的情况(因为节点是散列的,它的长度事先不知道)echo"ilengthisgreaterthanthelengthofthelinkedlist";出口;}else{$e=$p->data;#i-th节点存在,returnreturn$e;}}/***TODO:在链表的第i个位置之前插入节点e*@param$list待插入的对象链表*@param$iint节点号*@param$e待插入的对象节点*/publicfunctionInsert($list,$i,$e){if($e==null){echo"要插入的节点为空";出口;$p=$list->下一个;#设置p指向第一个节点$j=0;#定时器必须初始化while($p&&$j<$i){$p=$p->next;#保证节点向后移动++$j;}/*步骤i*/if($p==null){#表示链表结束,没有i节点,过滤掉i大于链表长度的情况(因为节点是散列的,它的长度事先不知道)echo"没有i节点";出口;}else{/*标准插入语句(头插入)*/$e->next=$p->next;$p->下一个=$e;返回$列表;}}/***TODO:删除链表的第i个节点并返回该节点的值*@param$listobject待插入的链表*@param$iint节点序号*/publicfunctionDelete($list,$i){if($list==null||$i<=0){echo"输入参数无效";出口;$p=$list->下一个;#设置p指向第一个节点$j=0;#定时器必须初始化while($p&&$j<$i){$p=$p->next;#保证节点向后移动++$j;}/*stepi*/if($p==null){#表示链表结束,没有i节点,过滤掉i大于链表长度的情况,认为即如果i大于链表长度,则跳出上述循环,直接进入判断,然后返回echo"第i个节点不存在";出口;}else{/*标准删除语句*/$q=$p->next;$p->下一个=$q->下一个;$e=$q->数据;取消设置($q);返回$e;}}/***TODO:删除整个链表*@param$listobject待插入的链表*/publicfunctionDeleteAll($list){if($list==null){echo"输入参数无效";出口;$p=$list->下一个;#设置p指向第一个节点while($p!=null){$q=$p->next;#确保节点向后移动unset($p);$p=$q;}}/***问题1:输出倒数第K个节点*@param$headobjectlinkedlist*@param$kintserialnumber*/functionFindKthToTail($head,$k){/*如果链表为空或k无效则返回null*/if($head==null||$k<=0){返回空值;}/*这里使用了复杂度为O(n)的算法,需要准备两个节点*/$behind=$head;#指向链表的第一个节点/*算法思路:准备两个指针。如果第一个指针指向n-1(即链表末尾),则第二个指针指向倒数k的位置,两者之差为(n-1)-(n-k)=k-1*/for($i=0;$i<$k-1;$i++){/*让第一个指针先走k-1个单位,如果不为空,指针向后移动*//*注意:这里有一个隐藏条件,就是链表的长度可能小于k,不遍历整个链表我们无法知道它的长度*/if($head->next!=null){$head=$head->下一个;}else{返回;}}/*当第一个指针走到k-1且不为空时,让第二个指针开始走,当第一个指针走到n-1时,第二个指针也走到倒数第k个位置,这是所需的*/while($head->next!=null){$head=$head->next;$behind=$behind->下一个;}返回$后面;}/***问题2:反向链表*@param$head对象链表*/publicfunctionReverseList($pHead){/*如果链表为空,返回null*/if($pHead==null){returnnull;}$pre=$pHead;#PreviousNode,这里是根节点$cur=$pre->next;#当前节点2例子:1->2->3$next=null;#下一个节点/*链表存在且不为空*/while(!$cur){$next=$cur->next;#用一个变量来暂存下一个节点,因为一旦前面反了,链接就断了$cur->next=$pre;#使用上一个节点作为当前节点下一个节点进行反转#指针向后移动$pre=$cur;$cur=$next;}return$pre;}}$object=newSingleLinkList();$result=(newSingleLinkList)->headInsert(4);$pre=$object->ReverseList($result);//$behind=$object->FindKthToTail($result,1);//$e=$object->readIThNode($result,2);//echo$e;//$newNode=newNode(6,null);//$newList=$object->Insert($result,2,$newNode);//$e=$object->Delete($result,2);echo"
";//print_r($result);print_r($pre);