PHP開發中的數據類型 ( 第2篇 ) :Trees

參考自: http://www.sitepoint.com/data-structures-2/  (PublishedJuly 5, 2013) php

第二篇開始搬到OSC上面來 node

數據結構管理常常遇到三種類型的操做: 數據庫

- 插入, 即向結構中插入數據
- 刪除, 即從結構中刪除數據
- 查詢, 即從結構中查詢數據
數據結構

好比說有這麼一張表: 數據庫設計

何歡 13911111111
吳佳旻 13922222222
徐琦怡 13933333333

這時,用stack 或者 queue 數據結構都不適合了,要查找一個值,必須遍歷該表,因此平均消耗是要查詢n/2(n是列表長度)條記錄。列表越長,查詢越慢。咱們須要一種對查詢優化的數據結構,tree應運而生。

咱們能夠把一張表抽象成四種類型的操做(這跟數據庫的crud操做很是相似)post

- 新建, 即新建一張表
- 插入, 即向表中插入數據
- 刪除, 即從表中刪除數據
- 查詢, 即從表中查詢數據 優化

這種表叫作線性植入,早期的數據庫設計)IBM’s Indexed Sequential Access Method (ISAM),MS-DOS’s File Allocation Table (FAT)等)等採用的就是這種方式。其缺點是插入和刪除的時候消耗比較大,由於值的長度是可大可小的。 this

而Tree的設計避免了這個問題(Why?),許多數據庫(如MySQL的MYISAM,Apple's HFS+, Microsoft’s NTFS, and btrfs for Linux等)都用Tree數據結構來構建索引。 spa

tree-02

Tree是按等級劃分的,有父、子級,沒有父的節點稱做root(根),沒有子的節點稱做leaf(葉),擁有相同父的節點叫作siblings。二叉樹(binary tree)就是有雙向節點的樹形數據結構,它是最簡單的樹結構。

把它們變成PHP代碼: 設計

class BinaryNode
{
    public $value;    // contains the node item
    public $left;     // the left child BinaryNode
    public $right;     // the right child BinaryNode
 
    public function __construct($item) {
        $this->value = $item;
        // new nodes are leaf nodes
        $this->left = null;
        $this->right = null;
    }
}
 
class BinaryTree
{
    protected $root; // the root node of our tree
 
    public function __construct() {
        $this->root = null;
    }
 
    public function isEmpty() {
        return $this->root === null;
    }
}
插入節點的邏輯

1 若是Tree是空的,就在root節點插入一個新節點
2 只要Tree不爲空:
    a 若是當前節點是空的,就在這裏插入新節點,停止
    b 不然,若是新節點 > 當前節點,就嘗試插入新節點到該節點的右側,而後重複步驟2
    c 不然,若是新節點  < 當前節點,就嘗試插入新節點到該節點的左側,而後重複步驟2
    d 不然,就說明值已經在Tree裏存在了,插不插都同樣,因此不插

插入節點的代碼

class BinaryTree
{
...
    public function insert($item) {
        $node = new BinaryNode($item);
        if ($this->isEmpty()) {
            // special case if tree is empty
            $this->root = $node;
        }
        else {
            // insert the node somewhere in the tree starting at the root
            $this->insertNode($node, $this->root);
        }
    }
   
    protected function insertNode($node, &$subtree) {
        if ($subtree === null) {
            // insert node here if subtree is empty
            $subtree = $node;
        }
        else {
            if ($node->value > $subtree->value) {
                // keep trying to insert right
                $this->insertNode($node, $subtree->right);
            }
            else if ($node->value < $subtree->value) {
                // keep trying to insert left
                $this->insertNode($node, $subtree->left);
            }
            else {
                // reject duplicates
            }
        }
    }
}

查詢樹的四種策略

- pre-order,即先查詢當前節點,而後查詢左右子節點 (比較適合於節點的插入 和 子樹克隆)
- in-order,即先查詢左節點,再查當前節點,再查右節點 (比較適合於搜索二叉樹)
- post-order,即先查詢左右節點,再查詢中節點 (比較適合於刪除節點)
- level-order,即先查詢當前節點,再查詢所有的相鄰節點,最後查詢下一級節點

下面的代碼演示了用 in-order 方式查詢:

class BinaryNode
{
...
    // perform an in-order traversal of the current node
    public function dump() {
        if ($this->left !== null) {
            $this->left->dump();
        }
        var_dump($this->value);
        if ($this->right !== null) {
            $this->right->dump();
        }
    }
}
 
class BinaryTree
{
...
    public function traverse() {
        // dump the tree rooted at "root"
        $this->root->dump();
    }
}

調用 traverse() 方法會顯示從root節點開始的按順序排序的整個Tree。

最後,這tmd有啥用? 誰能告訴我一下?

EOF

相關文章
相關標籤/搜索