数组需要一块连续的内存空间来存储,对内存的要求比较高。而链表恰恰相反,它并不需要一块连续的内存空间,它通过指针将一组零散的内存块串联起来使用。链表结构五花八门,三种最常见的链表结构,它们分别是:单链表、双向链表和循环链表。本文来看最简单、最常用的单链表。

/**
 * 单链表
 */
class SinglyLinkedList
{

    /**
     * 链表头结点|哨兵节点
     *
     * @var SinglyLinkedListNode
     */
    public $head;

    /**
     * 链表长度
     *
     * @var int
     */
    private $length;

    /**
     * 初始化
     *
     * @param null $head            
     */
    public function __construct($head = null)
    {
        $this->head = $head === null ? (new SinglyLinkedListNode()) : $head;
        $this->length = 0;
    }

    /**
     * 获取链表长度
     *
     * @return int
     */
    public function getLength()
    {
        return $this->length;
    }

    /**
     * 插入|头插法
     *
     * @param mixed $data            
     * @return SinglyLinkedListNode
     */
    public function insert($data)
    {
        return $this->insertDataAfter($this->head, $data);
    }

    /**
     * 删除节点
     *
     * @param SinglyLinkedListNode $node            
     * @return bool
     */
    public function delete(SinglyLinkedListNode $node)
    {
        if ($node === null) {
            return false;
        }
        $prev_node = $this->getPrevNode($node);
        $prev_node->next = $node->next;
        unset($node);
        $this->length --;
        return true;
    }

    /**
     * 获取前置节点
     *
     * @param SinglyLinkedListNode $node            
     * @return SinglyLinkedListNode|null
     */
    public function getPrevNode(SinglyLinkedListNode $node)
    {
        if ($node === null) {
            return null;
        }
        $curr = $this->head;
        $prev = $this->head;
        while ($curr !== $node && $curr !== null) {
            $prev = $curr;
            $curr = $curr->next;
        }
        return $prev;
    }

    /**
     * 通过索引获取节点
     *
     * @param int $index            
     * @return SinglyLinkedListNode|null
     */
    public function getNodeByIndex($index)
    {
        if ($index >= $this->length) {
            return null;
        }
        $curr = $this->head->next;
        for ($i = 0; $i < $index; $i ++) {
            $curr = $curr->next;
        }
        return $curr;
    }

    /**
     * 在指定节点后插入新节点
     *
     * @param SinglyLinkedListNode $origin_node            
     * @param SinglyLinkedListNode $node            
     * @return SinglyLinkedListNode|null
     */
    public function insertNodeAfter(SinglyLinkedListNode $origin_node, SinglyLinkedListNode $node)
    {
        if ($origin_node === null || $node === null) {
            return null;
        }
        $node->next = $origin_node->next;
        $origin_node->next = $node;
        $this->length ++;
        return $node;
    }

    /**
     * 在指定节点后插入新节点(插入数据)
     *
     * @param SinglyLinkedListNode $origin_node            
     * @param mixed $data            
     * @return SinglyLinkedListNode|null
     */
    public function insertDataAfter(SinglyLinkedListNode $origin_node, $data)
    {
        if ($origin_node === null) {
            return null;
        }
        $node = new SinglyLinkedListNode();
        $node->data = $data;
        $node->next = $origin_node->next;
        $origin_node->next = $node;
        $this->length ++;
        return $node;
    }

    /**
     * 打印链表
     *
     * @return null
     */
    public function print()
    {
        if ($this->head->next === null) {
            return;
        }
        $curr = $this->head;
        $length = $this->length;
        while ($curr->next !== null && $length --) {
            // 假设data均为可输出字符串格式
            echo $curr->next->data . ' -> ';
            $curr = $curr->next;
        }
        echo 'NULL', PHP_EOL;
    }
}

/**
 * 单链表节点
 */
class SinglyLinkedListNode
{

    /**
     * 节点的数据域
     *
     * @var mixed
     */
    public $data;

    /**
     * 节点的指针域|指向下一个节点
     *
     * @var SinglyLinkedListNode
     */
    public $next;

    /**
     * 构造函数
     */
    public function __construct($data = null)
    {
        $this->data = $data;
        $this->next = null;
    }
}

// 【调用示例】
$linked_list = new SinglyLinkedList();
$a = $linked_list->insert('A');
$linked_list->print();
$b = $linked_list->insert('B');
$linked_list->print();
$c = $linked_list->insertDataAfter($b, 'C');
$linked_list->print();
$d = $linked_list->insert('D');
$linked_list->print();
$new_node = new SinglyLinkedListNode('E');
$linked_list->insertNodeAfter($d, $new_node);
$linked_list->print();

输出如下:

A -> NULL
B -> A -> NULL
B -> C -> A -> NULL
D -> B -> C -> A -> NULL
D -> E -> B -> C -> A -> NULL

标签:数据结构