介绍

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

u=2725936833,1602779079&fm=26&gp=0.jpg

单向链表

每个节点包含data域和next域:指向下一个节点
下面一个简单的实例来解释单向链表的增加,删除和修改.

举例实现

我们通过一个简单的水浒英雄排行管理的实例,来实现一个单向链表.

微信图片_20191217171913.png

先创建一个类来存储每个节点中存储的英雄的信息:
<?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;
    }

Jzzzzzzzzz
29 声望0 粉丝

有的时候学习就是为了活着