PHP使用二分搜索樹實現映射

namespace map;
/**
 * 基於搜索二叉樹實現的映射類
 * @package map
 */
class BSTMap implements Map
{

    private $root;
    private $size;

    public function __construct()
    {
        $this->root = null;
        $this->size = 0;
    }

    public function isEmpty()
    {
        return $this->size == 0;
    }

    public function getSize()
    {
        return $this->size;
    }

    public function contains($key)
    {
        return $this->getNode($this->root, $key) != null;
    }

    /**
     * 添加元素到而二分搜索樹
     * @param mixed $key
     * @param mixed $value
     */
    public function add($key, $value)
    {
        $this->root = $this->addNode($this->root, $key, $value);
    }

    /**
     * 往以node爲根的二分搜索樹添加元素(key,value),遞歸算法
     * 返回插入新節點後二分搜索樹的根
     * @param BSTNode|null $node
     * @param null|mixed $key 映射的鍵
     * @param null|mixed $value 映射的值
     * @return BSTNode
     */
    private function addNode(BSTNode $node = null, $key = null, $value = null)
    {
        if ($node == null) {
            $this->size++;
            return new BSTNode($key, $value);
        }

        if ($key < $node->key)
            $node->left = $this->addNode($node->left, $key, $value);
        else if ($key > $node->key)
            $node->right = $this->addNode($node->right, $key, $value);
        else // $key == $node->key
            $node->value = $value;

        return $node;
    }


    /**
     * 返回以node爲根的二分搜索樹中key所在的節點
     * @param BSTNode|null $node
     * @param null|mixed $key
     * @return BSTNode|null
     */
    private function getNode(BSTNode $node = null, $key = null)
    {
        if ($node == null)
            return null;

        if ($key == $node->key)
            return $node;
        else if ($key < $node->key)
            return $this->getNode($node->left, $key);
        else // $key > $node->key
            return $this->getNode($node->right, $key);
    }

    public function set($key, $newValue)
    {
        $node = $this->getNode($this->root, $key);
        if ($node == null)
            throw new \InvalidArgumentException($key . " does't exist");

        $node->value = $newValue;
    }


    /**
     * 獲取鍵爲key的值
     * @param $key
     * @return mixed|null
     */
    public function get($key)
    {
        $node = $this->getNode($this->root, $key);
        return $node == null ? null : $node->value;
    }

    /**
     * 從二分搜索樹中刪除鍵爲key的節點
     * @param $key
     * @return mixed|null
     */
    public function remove($key)
    {
        $node = $this->getNode($this->root, $key);
        if ($node == null)
            return null;

        $this->root = $this->removeNode($this->root, $key);
        return $node->value;
    }


    /**
     * 從以node爲根節點的二分搜索樹中刪除鍵爲key的節點,遞歸算法
     * 返回刪除節點後新的二分搜索樹的根節點
     * @param BSTNode|null $node
     * @param null $key
     * @return BSTNode|null
     */
    private function removeNode(BSTNode $node = null, $key = null)
    {
        if ($node == null)
            return null;

        if ($key < $node->key) {
            $node->left = $this->removeNode($node->left, $key);
            return $node;
        } else if ($key > $node->key) {
            $node->right = $this->removeNode($node->right, $key);
            return $node;
        } else {
            if ($node->left == null) {
                $rightNode   = $node->right;
                $node->right = null;
                $this->size--;
                return $rightNode;
            }

            if ($node->right == null) {
                $leftNode   = $node->left;
                $node->left = null;
                $this->size--;
                return $leftNode;
            }

            $successor        = $this->minNum($node->right);
            $successor->right = $this->removeMin($node->right);
            $successor->left  = $node->left;

            $node->right = $node->left = null;
            return $successor;
        }
    }

    /**
     * 查找最小元素
     * @param BSTNode|null $node
     * @return BSTNode
     */
    private function minNum(BSTNode $node = null)
    {
        if ($node->left == null)
            return $node;

        return $this->minNum($node->left);
    }

    /**
     * 刪除最小元素
     * @param BSTNode|null $node
     * @return BSTNode|null
     */
    private function removeMin(BSTNode $node = null)
    {
        if ($node->left == null) {
            $rightNode   = $node->right;
            $node->right = null;
            $this->size--;
            return $rightNode;
        }

        $node->left = $this->removeMin($node->left);
        return $node;
    }
}

namespace map;
interface Map
{
    function add($key, $value);

    function remove($key);

    function contains($key);

    function get($key);

    function set($key, $newValue);

    function getSize();

    function isEmpty();
}

namespace map;
/**
 * 二分搜索樹的節點類
 * @package map
 */
class BSTNode
{
    /**
     * 左孩子
     * @var BSTNode
     */
    public $left;

    /**
     * 右孩子
     * @var BSTNode
     */
    public $right;

    /**
     * 映射鍵
     * @var mixed
     */
    public $key;


    /**
     * 映射值
     * @var mixed
     */
    public $value;

    /**
     * BSTNode constructor.
     * @param $key
     * @param $value
     */
    public function __construct($key, $value)
    {
        $this->key   = $key;
        $this->value = $value;
        $this->left  = null;
        $this->right = null;
    }
}
複製代碼

測試用例1node

$words=[
    'jack','jackson','jack','huan','wang','li','jack','li','king','tom'
];

$map = new \map\BSTMap();
foreach ($words as $word){
    if($map->contains($word))
        $map->set($word,$map->get($word)+1);
    else
        $map->add($word,1);
}

echo 'total words:'.count($words),'<br/>';
echo 'total different words:'.$map->getSize(),'<br/>';
echo 'Frenquency of jack: '. $map->get('jack'),'<br/>';
echo 'Frenquency of li: '. $map->get('li'),'<br/>';
echo 'Frequency of huan: '. $map->get('huan'),'<br/>';
複製代碼

測試用例2算法

給定兩個數組,編寫一個函數來計算它們的交集。數組

輸入: nums1 = [1,2,2,1], nums2 = [2,2] 輸出: [2,2]bash

$nums1 = [1,2,2,1];
$nums2 = [2,2];
$map = new map\BSTMap();

foreach ($nums1 as $n) {
    if ($map->contains($n))
        $map->set($n, $map->get($n) + 1);
    else
        $map->add($n, 1);
}

$arr = [];
foreach ($nums2 as $n) {
    if ($map->contains($n)) {
        $arr[] = $n;
        $map->set($n, $map->get($n) - 1);
        if ($map->get($n) == 0)
            $map->remove($n);
    }
}
複製代碼
相關文章
相關標籤/搜索