php+redis實現二叉樹的存儲和遍歷

本文作者:陳進堅
博客地址:https://jian1098.github.io
CSDN博客:https://blog.csdn.net/c_jian
聯繫方式:[email protected]

github地址:https://github.com/jian1098/php-redis-binary-tree

二叉樹是軟件開發過程中很常見的數據結構,本文通過php進行二叉樹的生成和遍歷,通過redis將二叉樹存儲,也可以將redis換成其他的關係型數據庫,但是讀寫速度嘛是差挺遠的。代碼中有足夠的註釋,應該不難懂,僅供參考和學習。

首先封裝二叉樹的生成和遍歷算法

tree.php

<?php

// 節點類
Class BTNode
{
    public $data;
    public $lChild;
    public $rChild;

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

// 二叉樹類
Class BinaryTree
{
    public $btData;

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

    //創建二叉樹
    public function CreateBT(&$root = null)
    {
        $elem = array_shift($this->btData);
        if ($elem == null) {
            return 0;
        } else if ($elem == '#') {
            $root = null;
        } else {
            $root = new BTNode();
            $root->data = $elem;
            $this->CreateBT($root->lChild);
            $this->CreateBT($root->rChild);
        }
        return $root;
    }

    //先序遍歷二叉樹
    public function PreOrder($root)
    {
        if ($root != null) {
            echo $root->data . " ";
            $this->PreOrder($root->lChild);
            $this->PreOrder($root->rChild);

        } else {
            return;
        }
    }

    //中序遍歷二叉樹
    public function InOrder($root)
    {
        if ($root != null) {
            $this->InOrder($root->lChild);
            echo $root->data . " ";
            $this->InOrder($root->rChild);

        } else {
            return;
        }
    }

    //後序遍歷二叉樹
    public function PosOrder($root)
    {
        if ($root != null) {
            $this->PosOrder($root->lChild);
            $this->PosOrder($root->rChild);
            echo $root->data . " ";

        } else {
            return;
        }
    }

    //層序(廣度優先)遍歷二叉樹
    function LeverOrder($root)
    {
        $queue = new SplQueue();//雙向鏈表
        if ($root == null){
            return;
        }else{
            $queue->enqueue($root);
        }

        while (!$queue->isEmpty()) {
            $node = $queue->bottom();
            $queue->dequeue();
            echo $node->data . " ";
            if ($node->lChild){
                $queue->enqueue($node->lChild);
            }else{
//                echo $node->data.'的左子樹爲空';
            }
            if ($node->rChild){
                $queue->enqueue($node->rChild);
            }else{
//                echo $node->data.'的右子樹爲空';
            }
        }
    }
}

接着封裝操作redis的類

redis.php

<?php

class MyRedis {
    private $redis;
    private $host;  //redis ip
    private $port;  //redis 端口
    private $tree;

    public function __construct($host,$port){
        $this->host=$host;
        $this->port=$port;
        //連接redis
        if(class_exists('Redis')){
            $this->redis = new \Redis();
            if($this->redis->connect($this->host, $this->port)){
                $this->connect=true;
            }
        }else{
            exit('redis擴展不存在');
        }
    }

    //添加節點
    public function addNode($id,$data){
        if(!is_array($data)){
            return [];
        }
        $resOrder=$this->redis->hMSet($id,$data);
        return $resOrder;
    }

    //查找節點
    public function getNode($id){
        return $this->redis->hGetAll($id);
    }

    //修改指定節點的屬性
    public function setNode($id,$field,$value){
        return $this->redis->hSet($id,$field,$value);
    }

    //獲取redis所有鍵
    public function getKeys(){
        return $this->redis->keys('*');
    }

    //獲取key的個數
    public function dbSize(){
        return $this->redis->dbSize();
    }

    //清空數據庫
    public function flushDB(){
        return $this->redis->flushDB();
    }

    //前序遍歷的順序取出二叉樹
    public function tree($root_id){
        $rootNode=$this->getNode($root_id);
        $this->tree[]=$root_id;
        if (isset($rootNode['left'])){
            $this->tree($rootNode['left']);
        }
        if (isset($rootNode['right'])){
            $this->tree($rootNode['right']);
        }
        return $this->tree;
    }
}

最後調用兩個類進行二叉樹的存取和遍歷

index.php

<?php
require_once 'redis.php';
require_once 'tree.php';

$myredis=new MyRedis('127.0.0.1','6379');

/*
    假設我構造一顆如下的二叉樹
            1
        2       3
      #   4   #   #
        #   #
*/

//添加節點
//$data=[
//    'left'      =>      '2',
//    'right'     =>      '3',
//];
//$res=$myredis->addNode(1,$data);
//
//$data=[
//    'left'      =>      '#',
//    'right'     =>      '4',
//];
//$res=$myredis->addNode(2,$data);
//
//$data=[
//    'left'      =>      '#',
//    'right'     =>      '#',
//];
//$res=$myredis->addNode(3,$data);
//
//$data=[
//    'left'      =>      '#',
//    'right'     =>      '#',
//];
//$res=$myredis->addNode(4,$data);
//print_r($res);

//修改節點信息
//$res=$myredis->setNode(1,'left',2);
//print_r($res);

//查詢指定節點
//$res=$myredis->getNode(1);
//print_r($res);

//清空數據
//$res=$myredis->flushDB();
//獲取redis所有鍵
//$res=$myredis->getKeys();
//print_r($res);

//前序遍歷的順序從redis讀取節點
$data=$myredis->tree(1);//$data = array(1,2,'#',4,'#','#',3,'#','#');

//生成二叉樹
$tree = new BinaryTree($data);
$root = $tree->CreateBT();

//遍歷二叉樹
echo '前序:';
$tree->PreOrder($root);
echo '<br>中序:';
$tree->InOrder($root);
echo '<br>後序:';
$tree->PosOrder($root);
echo '<br>層序:';
$tree->LeverOrder($root);

執行結果

前序:1 2 4 3 
中序:2 4 1 3 
後序:4 2 3 1 
層序:1 2 3 4
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章