class Node
{
public $data;
public $next;
public function __construct($data,$next)
{
$this->data = $data;
$this->next = $next;
}
}
class singleLinkList{
/**
* 头插法创建链表
*/
public function headInsert($n)
{
$head = new node(null,null);
for($i=0;$i<$n;$i++)
{
$newNode = new node($i,null);
$newNode->next = $head->next;
$head->next=$newNode;
}
return $head;
}
/**
* 尾插法创建链表
* @param $n int 链表元素个数
* @return $rear 返回链表对象
*/
public function rearInsert($n)
{
//指向表尾节点的指针
$head = $rear = new Node(null,null);
for($i=0;$i<$n;$i++)
{
$newNode = new Node($i+1,null);
//将表尾节点的指针指向新节点
$rear->next = $newNode;
//将当前的新节点定义为表尾终端节点
$rear = $newNode;
}
//循环结束后最终的尾节点的指针赋值null
$rear->next = null;
return $head;
}
/**
* 读取第i个元素
* @param $list
* @param $i
*/
public function readNode($list,$i)
{
if ($list == null || $i <= 0)
{
return;
}
$p = $list->next;
$j=0;
while($p && $j<$i)
{
$p = $p->next;
$j++;
}
if($p == null)
{
echo 'i长度大于链表长度';
return;
}else{
$e = $p->data;
return $e;
}
}
/**
* 删除链表的第i个元素 并返回该节点的值
* @param $list
* @param $i
* @return mixed
*/
public function delete($list,$i)
{
if ($list == null || $i < 0)
{
echo '参数不合法';
exit;
}
$p = $list->next;
$j = 1;
while($p && $j<$i)
{
$p = $p->next;
$j++;
}
if($p == null)
{
echo '不存在节点i';
}else{
$q = $p->next;
$p->next = $q->next;
$e = $q->data;
unset($q);
return $e;
}
}
/**
* 删除整张链表
*/
public function deleteAll($list)
{
if ($list == null)
{
echo '参数不合法';
return;
}
$p = $list->next;
while ($p != null)
{
//保证节点在向后移动
$q = $p->next;
unset($p);
$p = $q;
}
return;
}
/**
* 输出倒数第K个节点
*/
public function findNodeToTail($list,$k)
{
if($list == null || $k<0)
{
echo '参数不合法';
return;
}
/* 这里采用了复杂度为O(n)的算法,需要准备两个节点 */
$behind = $list;#指向链表的第一个节点
/*
* 算法思路:准备两个指针,假如第一个指针走到n-1(即链表末尾),
* 第二个指针走到倒数k的位置,两者之间相差(n-1)-(n-k) = k-1
*/
for($i=0;$i<$k-1;$i++)
{
/*
* 让第一个指针先走k-1个单位 如果不为空 则指针向后移动
* 注意 这里有个隐藏条件 就是链表的长度有可能小于k ,所以不遍历整个链表是不知道其长度的
*/
if($list->next != null)
{
$list = $list->next;
}else{
return;
}
}
while($list->next != null)
{
$list = $list->next;
$behind = $behind->next;
}
return $behind;
}
/**
* 反转链表
*
* a-->b-->c-->d-->e-->f
*
* 将e的next指向d :
* 当把e的next指针指向d的同时,原先指向的f就不能被正常访问了
* 为了避免断链,我们必须在更改指向之前,保存修改节点的下一个节点。
* 同时我们也必须存储上一个节点,因为next域即将修改指向该节点。
* 因此定义三个指针,分别指向
* 当前遍历的节点,
* 前一个节点,
* 后一个节点
*/
public function reverseList($list)
{
if($list == null)
{
echo '参数不合法';
return ;
}
//前一节点 这里是根节点
$pre = null;
//当前节点
$cur = $list->next;
//后一节点
$next = null;
/*
* 链表存在且不为空
*/
while($cur->next)
{
$next = $cur->next; //用一个变量暂时存放后一个节点 因为一旦前面反转,就断链了
$cur->next = $pre; //将前一个节点作为当前节点的后一节点 是为反转
#指针后移
$pre = $cur;
$cur = $next;
}
$cur->next = $pre;
return $cur;
}
}
$linkIns = new singleLinkList();
$arr2 = $linkIns->headInsert(5);print_r($arr2);
//$nodeData = $linkIns->readNode($arr2,2);
//$deleteNode = $linkIns->delete($arr2,2);
//print_r($deleteNode);
//$knode = $linkIns->findNodeToTail($arr2,3);
$arr3 = $linkIns->reverseList($arr2);
print_r($arr3);