介绍
- 链表(Linked List)是以节点的方式存储,是链式存储
- 节点不一定是连续存储
- 链表分带头节点的链表和不带头节点的链表
链表有单向链表,双向链表,单向环形链表.

单向链表
每个节点包含data域和next域:指向下一个节点
下面一个简单的实例来解释单向链表的增加,删除和修改.
举例实现
我们通过一个简单的水浒英雄排行管理的实例,来实现一个单向链表.

先创建一个类来存储每个节点中存储的英雄的信息:
<?php
//水浒英雄对象
class HeroNode {
//英雄编号
public $no;
//英雄名称
public $name;
//昵称
public $nickName;
//next域,指向下一个节点
public $next;
public function __construct($no,$name,$nickName)
{
$this->no = $no;
$this->name = $name;
$this->nickName = $nickName;
}
//重写__toString方便打印
public function __toString()
{
return '编号: '.$this->no.' 姓名:'.$this->name.' 昵称:'.$this->nickName."\n";
}
}
创建一个类用来管理英雄
/**
* 水浒英雄链表
* Class SingleLinkedList
*/
class SingleLinkedList
{
public $header;
//
public function __construct()
{
//先初始化一个头节点,头节点不动,不存放具体的数据
$this->header = new HeroNode(0,'','');
}
}
接下来,来添加英雄到链表中,直接将英雄插入到链表的尾部.
/**
* 水浒英雄链表
* Class SingleLinkedList
*/
class SingleLinkedList
{
...
/**
* 插入到链表尾部
* @param $hero
*/
public function add($hero)
{
//创建一个临时变量指向头节点
$temp = $this->header;
//遍历链表找到链表的尾部
while(true){
// 如果next域为空则找到尾部,退出循环
if($temp->next == null){
break;
}
$temp = $temp->next;
}
//将英雄添加到链表的尾部
$temp->next = $hero;
}
}
还有另外一种添加的方式,是按照英雄的编号,从小到大添加
/**
* 水浒英雄链表
* Class SingleLinkedList
*/
class SingleLinkedList
{
...
/**
* 按照编号从小打到大插入
* @param $hero
*/
private function addByOrder($hero)
{
$temp = $this->header;
$flag = false;
while(true){
if($temp->next == null){
break;
}
//如果下个节点的编号大于插入英雄的号,则插入到下个节点的前面
if($temp->next->no > $hero->no){
break;
}
if($temp->next->no == $hero->no){
$flag = true;
break;
}
$temp = $temp->next;
}
if($flag == true){
echo '编号'.$hero->no.'已经存在,不能插入';
}else{
$hero->next = $temp->next;
$temp->next = $hero;
}
}
}
修改节点
同样是通过遍历链表,通过要修改的编号来进行修改
/**
* 修改节点
* @param $hero
*/
public function update($hero)
{
$temp = $this->header;
$flag = false;
while(true){
if($temp->next == null){
break;
}
if($temp->next->no == $hero->no){
$flag = true;
break;
}
$temp = $temp->next;
}
if($flag == true){
$temp->next->name = $hero->name;
$temp->next->nickName = $hero->nickName;
}else{
echo '没有找到编号为'.$hero->no.'的英雄,无法修改';
}
}
删除节点
通过遍历找到编号,然后将temp的next域指向temp的next的next域,实现删除
/**
* 删除节点
* @param $no
*/
public function del($no)
{
$temp = $this->header;
$flag = false;
while(true){
if($temp->next === null){
break;
}
if($temp->next->no == $no){
$flag = true;
break;
}
$temp = $temp->next;
}
if($flag == true) {
$temp->next = $temp->next->next;
}else{
echo "没有找到编号为".$no."的英雄,删除失败";
}
}
添加一个打印链表的功能
/**
* 打印链表
*/
public function lists()
{
$temp = $this->header;
while(true){
if($temp->next == null){
break;
}
$temp = $temp->next;
echo $temp;
}
}
扩展一个反转链表的功能
通过新增一个链表,将原来链表进行遍历,每遍历一个节点,将该节点插入到新链表的头部,最后将原来链表的next域指向新链表的next域
/**
* 链表反转
*/
public function reverse()
{
if($this->header->next == null || $this->header->next->next == null){
return;
}
$reverseHeader = new HeroNode('','','','');
$cur = $this->header->next;
$next = null;
while($cur != null){
$next = $cur->next;
$cur->next = $reverseHeader->next;
$reverseHeader->next = $cur;
$cur = $next;
}
$this->header->next = $reverseHeader->next;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。