php-二叉樹

二叉樹的基本知識就不說了,談一些有意思的問題!

想要存儲一棵二叉樹,我們有兩種方法

一種是基于指針或者引用的二叉鏈式存儲法,
一種是基于數組的順序存儲法。

鏈式存儲 大部分二叉樹代碼都是通過這種結構來實現的。

鏈式存儲

每個節(jié)點有 3 個字段,data 存儲數據,另外兩個是指向左右子節(jié)點的指針

順序存儲 存儲適用性不強,一般只用于完全二叉樹

順序存儲

二叉樹的遍歷

二叉樹的遍歷方式有很多,如果限制了從左到右的習慣方式,那么主要就分為四種:

  • 前序遍歷(DLR):根結點,遍歷左子樹,遍歷右子樹【根左右】百度百科

    前序遍歷: ABDGHCEIF

  • 中序遍歷(LDR):遍歷左子樹,根結點,遍歷右子樹【左根右】百度百科

    中序遍歷: GDHBAEICF

  • 后序遍歷(LRD):遍歷左子樹,遍歷右子樹,根結點【左右根】百度百科

    后序遍歷:GHDBIEFCA

  • 層序遍歷:從根結點,從上而下逐層遍歷


    層序遍歷:ABCDEFGHI

那為什么要有這么多遍歷方法呢

我們用圖形的方式來表現樹的結構,可以非常直觀的理解,但是對于計算機來說,它只有循環(huán)、判斷等方式來處理,換種方式說,就是它只會處理線性序列,而剛才四種遍歷方法,都是把樹中的結點變成某種意義的線性結構。

推導二叉樹

很多面試會問這個問題。給出前序ABCDEF,中序CBAEDF,問后序是什么?
其實很簡單前序先訪問根結點 A,中序 A 左邊就是左子樹,可以根據上面的圖自己推導著畫一下,結果CBEFDA

簡單的二叉樹代碼實現

class node
{
    public $data   = null;
    public $left   = null;
    public $right  = null;
    public $parent = null;

    function __construct($data)
    {
        $this->data = $data;
    }
}

class tree
{
    public $root  = null;
    public $size  = 0;
    public $depth = null;

    function __construct($data)
    {
        $this->root = new node($data);
        $this->size++;
        $this->depth++;
    }

    function addNode($arr)
    {
        foreach ($arr as $value) {
            $current     = $this->root;
            $parent      = null;
            $currentDept = 1;

            while ($current !== null) {
                $parent = $current;
                if ($value == $current->data) {
                    continue 2;
                } elseif ($current->data > $value) {
                    $current = $current->left;
                } else {
                    $current = $current->right;
                }
                $currentDept++;
            }
            $node         = new node($value);
            $node->parent = $parent;
            if ($parent->data > $value) {
                $parent->left = $node;
            } else {
                $parent->right = $node;
            }

            if ($this->depth < $currentDept) {
                $this->depth++;
            }
            $this->size++;
        }

        return true;
    }

    function showTree()
    {
        return $this->root;
    }
}

二叉查找樹

查找樹其實就是在規(guī)則上限制了數據。它不僅僅支持快速查找一個數據,還支持快速插入、刪除一個數據。

它是怎么做到這些的呢?

二叉查找樹要求,在樹中的任意一個節(jié)點,其左子樹中的每個節(jié)點的值,都要小于這個節(jié)點的值,而右子樹節(jié)點的值都大于這個節(jié)點的值。

時間復雜度其實都跟樹的高度成正比 O(logn)

散列表和二叉查找樹

散列表的插入、刪除、查找操作的時間復雜度可以做到常量級的 O(1)
二叉查找樹在比較平衡的情況下,插入、刪除、查找操作時間復雜度才是 O(logn)
相對散列表,好像并沒有什么優(yōu)勢,那我們?yōu)槭裁催€要用二叉查找樹呢?

  • 如果要輸出有序數據,散列表就要先排序,二叉樹則可以通過中序遍歷在 O(n) 時間復雜度內輸出
  • 散列表擴容耗時很多,而且當遇到散列沖突時,性能不穩(wěn)定,盡管二叉查找樹的性能不穩(wěn)定,但我們最常用的平衡二叉查找樹的性能非常穩(wěn)定,時間復雜度穩(wěn)定在 O(logn)。
  • 盡管散列表的查找等操作的時間復雜度是常量級的,平衡二叉查找樹是 O(logn) 但因為哈希沖突的存在,這個常量不一定比 logn 小,所以實際的查找速度可能不一定快
  • 散列表的構造比二叉查找樹要復雜,需要考慮的東西很多。比如散列函數的設計、沖突解決辦法、擴容、縮容等。平衡二叉查找樹只需要考慮平衡性這一個問題,而且這個問題的解決方案比較成熟、固定。
  • 為了避免過多的散列沖突,散列表裝載因子不能太大,特別是基于開放尋址法解決沖突的散列表,不然會浪費一定的存儲空間。

平衡二叉查找樹,紅黑樹?紅黑樹

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容