php链表实现,利用PHP实现常用的数据结构之链表(小白系列文章五)

tips:因为涉及指针,我们用引用来模拟,所以读者应该有面向对象的知识贮备。

引子

你可以把链表简单理解为动态数组,它不需要一块一块的开辟空间,同时,你又要注意,它存在的主要意义或者说使用场景主要是”指针功能“,它能够指来指去,对一些应用特别是内存管理起到了关键作用。

引文

因为涉及内存,常常会有一些程序的边界限制,需要programer拥有一定严密的逻辑去保证代码的鲁棒性和健壮性,所以这个知识点是面试的常考点。下面我们看看PHP的单链表实现(附常考题目实现):

/**

* PHP 单链表

* author:entner

* time :2017-8-14

* email :1185087164@qq.com

*/

/**

* TODO:构建链表节点

*/

Class Node{

public $data;

public $next;

public function __construct($val,$nex){

$this->data = $val;

$this->next = $nex;

}

}

/**

* TODO:构建单链表

*/

Class SingleLinkList{

/* 头插法创建链表 n为节点总数 */

public function headInsert($n){

/* 新建一个头节点 */

$head = new Node(null,null);

for($i=$n;$i>0;$i--){

$newNode = new Node($i,null);

$head->data = $newNode->data; #新建节点赋值给头节点

$newNode->next = $head->next; #将头节点的后继节点作为新建节点的后继节点,相当于在原头节点和头节点的后继节点中间添加了一个新节点

$head->next = $newNode; #将新建节点作为头节点的后继节点,这时候原本头节点的后继节点已经改变了

}

return $head;

}

/* 尾插法创建链表 */

public function rearInsert($n){

/* 新建一个尾节点 */

$rear = new Node(null,null);

for($j=0;$j

$newNode = new Node($j,null);

$rear->data = $newNode->data;

//$newNode = $rear->next;

$rear->next = $newNode;

$rear = $newNode;

}

return $rear;

}

/**

* TODO:读取链表中第i个数据

* @param $list object 待插入的链表

* @param $i int 节点序号

*/

public function readIThNode($list,$i){

/* 如果链表为空或者i小等于0 */

if($list == null || $i<=0){

echo "输入参数不合法";

return ;

}

/* */

$p = $list->next; #设置p指向第一个节点(即头节点的后继节点))

$j=0; #计时器必须初始化

while($p && $j

$p = $p->next;

++$j;

}

/* 第i步 */

if($p == null){ #说明链表已经结束,不存在i节点,过滤掉i大于链表长度的情况(因为节点是散列的,事先并不知道其长度)

echo "i长度大于链表长度" ;

exit;

}else{

$e = $p->data; #第i个节点存在 ,返回

return $e;

}

}

/**

* TODO:在链表的第i个位置之前插入节点e

* @param $list object 待插入的链表

* @param $i int 节点序号

* @param $e object 待插入的节点

*/

public function Insert($list,$i,$e){

if($e == null){

echo "待插入节点为空";

exit;

}

$p = $list->next; #设置p指向第一个节点

$j=0; #计时器必须初始化

while($p && $j

$p = $p->next; #保证节点在向后移动

++$j;

}

/* 第i步 */

if($p == null){ #说明链表已经结束,不存在i节点,过滤掉i大于链表长度的情况(因为节点是散列的,事先并不知道其长度)

echo "不存在i节点" ;

exit;

}else{

/* 标准的插入语句(头插法) */

$e->next = $p->next;

$p->next = $e;

return $list;

}

}

/**

* TODO:删除链表的第i个节点,并返回该节点的值

* @param $list object 待插入的链表

* @param $i int 节点序号

*/

public function Delete($list,$i){

if($list == null || $i<=0){

echo "输入参数不合法";

exit;

}

$p = $list->next; #设置p指向第一个节点

$j=0; #计时器必须初始化

while($p && $j

$p = $p->next; #保证节点在向后移动

++$j;

}

/* 第i步 */

if($p == null){ #说明链表已经结束,不存在i节点,过滤掉i大于链表长度的情况,以为若i大于链表长度,则上面循环会跳出直接进入判断然后返回

echo "不存在i节点" ;

exit;

}else{

/* 标准的删除语句 */

$q = $p->next;

$p->next = $q->next;

$e = $q->data;

unset($q);

return $e;

}

}

/**

* TODO:删除整张链表

* @param $list object 待插入的链表

*/

public function DeleteAll($list){

if($list == null ){

echo "输入参数不合法";

exit;

}

$p = $list->next; #设置p指向第一个节点

while($p != null ){

$q = $p->next; #保证节点在向后移动

unset($p);

$p = $q;

}

}

/**

* Question1:输出倒数第K个节点

* @param $head object 链表

* @param $k int 序号

*/

function FindKthToTail($head, $k){

/* 如果链表为空或者k不合法 返回null */

if($head == null || $k<=0){

return null;

}

/* 这里采用了复杂度为O(n)的算法,需要准备两个节点 */

$behind = $head; #指向链表的第一个节点

/* 算法思路:准备两个指针,假如第一个指针走到n-1(即链表末尾),第二个指针走到倒数k的位置,两者之间相差(n-1)-(n-k) = k-1 */

for($i=0;$i

/* 让第一个指针先走k-1个单位,如果不为空,则指针向后移动 */

/* 注意:这里有一个隐藏的条件,就是链表的长度有可能小于k,我们不不遍历完整个链表是无法知道其长度的 */

if($head->next != null){

$head = $head->next;

}else{

return ;

}

}

/* 当第一个指针走到k-1且还不为空,这时让第二个指针开始走,当第一个指针走到n-1的时候,第二个指针也走到了倒数第k的位置,即所求 */

while($head->next != null){

$head = $head->next;

$behind = $behind->next;

}

return $behind;

}

/**

* Question2:反转链表

* @param $head object 链表

*/

public function ReverseList($pHead)

{

/* 如果链表为空,返回null */

if($pHead == null){

return null;

}

$pre = $pHead; #前一节点 ,这里是根节点

$cur = $pre->next; #当前节点 2 例:1->2->3

$next = null; #后一节点

/* 链表存在且不为空 */

while(!$cur){

$next = $cur->next; #用一个变量暂时存储后一节点,因为一旦前面反转,就断链了

$cur->next = $pre; #将前一节点作为当前节点的后一节点,是为反转

#指针后移

$pre = $cur;

$cur = $next;

}

return $pre;

}

}

$object = new SingleLinkList();

$result = (new SingleLinkList)->headInsert(4);

$pre = $object->ReverseList($result);

//$behind = $object->FindKthToTail($result,1);

// $e = $object->readIThNode($result,2);

// echo $e;

// $newNode = new Node(6,null);

// $newList = $object->Insert($result,2,$newNode);

// $e = $object->Delete($result,2);

echo "

";

// print_r($result);

print_r($pre);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值