實戰PHP資料結構基礎之雙連結串列

daxuesheng發表於2021-09-09

什麼是雙連結串列?

上一篇說到

單連結串列由一個一個的作為節點的物件構成的,每一個節點都有指向下一個節點的指標,最後一個節點的指標域指向空。每個節點可以儲存任何資料型別。

而雙連結串列每個節點有兩個指標域,分別指向前驅和後繼節點。單連結串列是單向的,而雙連結串列是雙向的。

常見操作

對雙連結串列我們常見的操作有如下:

  • insert

  • insertBefore

  • insertAfter

  • insertAtFirst

  • insertAtLast

  • deleteFirst

  • deleteLast

  • delete

  • reverse

  • getNthNode

  • ...

PHP語言實現

首先我們根據定義實現一個雙連結串列的ListNode類。

class ListNode{    public $data = null;    public $next = null;    public $prev = null;    public function __construct(string $data)
    {        $this->data = $data;
    }
}

再來看連結串列類,首先需要3個私有屬性,分別是頭節點、尾巴節點和長度。

class DoubleLinkedList{    private $head = null;    private $last = null;    private $length = 0;
}

接下來還是老規矩,直接看如何實現第一個即常用的插入,這是是一個平均時間複雜度為O(n)的操作。

/**
 * 插入一個節點
 * @param string|null $data
 * @return bool
 * complexity O(n)
 */public function insert(string $data = null){
    $newNode = new ListNode($data);    if ($this->head) {
        $currentNode = $this->head;        while ($currentNode) {            if ($currentNode->next === null) {
                $currentNode->next = $newNode;
                $newNode->prev = $currentNode;                $this->last = $newNode;                $this->length++;                return true;
            }

            $currentNode = $currentNode->next;
        }
    } else {        $this->head = &$newNode;        $this->last = $newNode;        $this->length++;        return true;
    }

}

再來看如何刪除節點。

/**
 * 刪除一個節點
 * @param string $data
 * @return bool|ListNode
 * complexity O(n)
 */public function delete(string $query = null){    if ($this->head) {
        $currentNode = $this->head;
        $prevNode = null;    
        while ($currentNode) {            if ($currentNode->data === $query) {                if ($nextNode = $currentNode->next) {                    if ($prevNode) {
                        $prevNode->next = $nextNode;
                        $nextNode->prev = $prevNode;
                    } else {                        $this->head = $nextNode;
                        $nextNode->prev = null;
                    }    
                    unset($currentNode);
                } else {                    if ($prevNode) {                        $this->last = $prevNode;
                        $prevNode->next = null;                        unset($currentNode);
                    } else {                        $this->head = null;                        $this->last = null;
                    }
                }    
                $this->length--;                return true;
            }
    
            $prevNode = $currentNode;
            $currentNode = $currentNode->next;
        }
    }    return false;
}

反轉雙連結串列也不是很複雜。

public function reverse(){    if ($this->head !== null) {        if ($this->head->next !== null) {
            $reversedList = null;
            $currentNode = $this->head;            while ($currentNode !== null) {
                $next = $currentNode->next;
                $currentNode->next = $reversedList;
                $currentNode->prev = $next;

                $reversedList = $currentNode;
                $currentNode = $next;

            }            $this->last = $this->head;            $this->head = $reversedList;
        }
    }
}

雙連結串列其他操作的詳細實現可以參考 。

雙連結串列是連結串列這種鏈式存取資料結構中相對於單連結串列比較特殊的部分,同樣屬於連結串列結構的還有單連結串列,環形連結串列和多連結串列。

專題系列

PHP基礎資料結構專題系列目錄地址: 主要使用PHP語法總結基礎的資料結構和演算法。還有我們日常PHP開發中容易忽略的基礎知識和現代PHP開發中關於規範、部署、最佳化的一些實戰性建議,同時還有對Javascript語言特點的深入研究。



作者:肖瀟_
連結:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4692/viewspace-2804966/,如需轉載,請註明出處,否則將追究法律責任。

相關文章