数据结构-图 12.图-php实现最小生成树(普利姆算法)

1、图类:Graph

class Graph
{
    /**
     * @var int 定点的数量
     */
    private $vertexSize;
    /**
     * @var array 定点数组
     */
    public $vertexs = [];
    /**
     * @var array 矩阵
     */
    public $matrix = [];

    /**
     * @var int 最大权值
     */
    public $MAX_WEIGHT = 1000;
    /**
     * @var array 是否被遍历了
     */
    private $isVisited = [];
    /**
     * Graph constructor.
     *
     * @param int $vertexSize
     */
    public function __construct($vertexSize)
    {
        $this->vertexSize = $vertexSize;
        for($i=0 ;$i<$vertexSize; $i++){
            $this->vertexs[$i] = $i;
        }
    }

    /**
     * @return array
     */
    public function getVertexs()
    {
        return $this->vertexs;
    }

    /**
     * @param array $vertexs
     */
    public function setVertexs($vertexs)
    {
        $this->vertexs = $vertexs;
    }

    /**
     * Function:getOutDegree
     * 获取某个定点的出度
     *
     * @param $index
     *
     * @return int
     */
    public function getOutDegree($index){
        $degree = 0;
        for( $j = 0; $j<count($this->matrix[$index]); $j++){
            $weight = $this->matrix[$index][$j];
            if($weight!=0 && $weight != $this->MAX_WEIGHT)
            {
                $degree++;
            }
        }
        return $degree;
    }

    /**
     * Function:getInDegree
     * 计算出度
     *
     * @param $index
     *
     * @return int
     */
    public function getInDegree($index){
        $degree = 0;
        for( $j = 0; $j<count($this->matrix); $j++){
            $weight = $this->matrix[$j][$index];
            if($weight!=0 && $weight != $this->MAX_WEIGHT)
            {
                $degree++;
            }
        }
        return $degree;
    }

    /**
     * Function:getWeight
     * 获取两个定点的权值
     *
     * @param $v1
     * @param $v2
     *
     * @return mixed
     */
    public function getWeight($v1, $v2)
    {
        $weight = $this->matrix[$v1][$v2];
        return $weight == 0
            ? 0
            : ($weight == $this->MAX_WEIGHT ? -1
                : $weight);
    }

    /**
     * Function:depthFirstSearch
     * 图的深度优先遍历算法-迭代(类似于二叉树的前序遍历)
     *
     * @return void
     */
    public function depthFirstSearch(){
        //强制的每个节点都遍历-防止不是连通图
        for ($i=0;$i<$this->vertexSize;$i++)
        {
            if(empty($this->isVisited[$i]))
            {
                $this->_depthFirstSearch($i);
            }
        }
    }
    /**
     * 图的广度优先算法-类似于树的层序
     */
    public function broadFirstSearch(){
        //强制的每个节点都遍历-防止不是连通图
        for ($i=0;$i<$this->vertexSize;$i++)
        {
            if(empty($this->isVisited[$i]))
            {
                $this->_broadFirstSearch($i);
            }
        }
    }
    /**
     * 普里姆算法
     * 1、先把顶点的数据存在待定的最小权值数组中,暂定为最小,
     * 2、从暂定数组中找最小权值的节点(去除已经找到的)
     * 3、得到最小的节点后,获取这个节点的边,与待定的最小权值数组对应的值进行对比,如果小则替换待定的最小权值数组的权值
     * 4、循环3,4的操作
     *
     *
     * 用一个待定的最小权值数组,来保存每一个有可能相连的最小权值,直到最后找到最小的哪一个不断的去连接
     */
    public function prim(){
        //最小代价定点权值的数组,为0表示已经获取最小权值
        $lowcost = [0,0,0,0,0,0,0,0,0];
        //放定点权值
        $adjvex = [];
        $min = $minId = $sum = 0;
        //将v0的第一排数据,存放在$lowcost中
        for ($i=1;$i<$this->vertexSize;$i++){
            $lowcost[$i] = $this->matrix[0][$i];
        }

        for ($i = 1;$i<$this->vertexSize;$i++)
        {
            $min = $this->MAX_WEIGHT;
            $minId = 0;
            //找出每一行最小的权值
            for ($j = 1;$j<$this->vertexSize;$j++)
            {
                //找出每一行最小的权值
                if($lowcost[$j]<$min && $lowcost[$j]>0)
                {
                    $min = $lowcost[$j];
                    $minId = $j;
                }
            }
//            echo "顶点".$adjvex[$minId].";权值:"+$min.PHP_EOL;
            $sum+= $min;
            //获取到最小的设置成0
            $lowcost[$minId] = 0;
//            print_r([$minId,$sum,$lowcost]);die;
            //寻找下一排,各个位置比$lowcost小的,暂时占位$lowcost中
            for ($j = 1;$j<$this->vertexSize;$j++)
            {
                if($lowcost[$j]!=0&&$this->matrix[$minId][$j]<$lowcost[$j])
                {
                    $lowcost[$j] = $this->matrix[$minId][$j];
                    $adjvex[$j] = $minId;
                }
            }
            print_r([$adjvex,$lowcost]);
        }
        echo "最小生成树,权值和:".$sum.PHP_EOL;
    }
    /**
     * 实现图的广度优先算法
     */
    private function _broadFirstSearch($i){

        $this->isVisited[$i] = true;
        $queue = new \SplQueue();
        echo "访问到了:".$i."顶点".PHP_EOL;
        $queue->push($i);
        while (!$queue->isEmpty())
        {
            $u = $queue->shift();
            $w = $this->_getFirstNeightbor($u);
            while ($w != -1){
                if(empty($this->isVisited[$w]))
                {
                    echo "访问到了:".$w."顶点".PHP_EOL;
                    $this->isVisited[$w] = true;
                    $queue->push($w);
                }
                $w = $this->_getNextNeighbor($u,$w);
            }
        }


    }

    /**
     * Function:depthFirstSearch
     * 图的深度优先遍历算法-迭代
     *
     * @return void
     */
    private function _depthFirstSearch($i){
        $this->isVisited[$i] = true;
        //寻找第一个节点
        $w = $this->_getFirstNeightbor($i);
        while ($w!=-1){
            if(empty($this->isVisited[$w]))
            {
                echo "访问到了:".$w."顶点".PHP_EOL;
                $this->_depthFirstSearch($w);
            }
            $w = $this->_getNextNeighbor($i,$w); //第一个相对于w的邻接节点
        }
    }
    /**
     * Function:getFirstNeightbor
     * 获取某个定点的第一个邻接点
     *
     * @param $index
     *
     * @return array
     */
    private function _getFirstNeightbor($index)
    {
        for ($j = 0; $j<$this->vertexSize; $j++)
        {
            if($this->matrix[$index][$j]>0&&$this->matrix[$index][$j]<$this->MAX_WEIGHT){
                return $j;
            }
        }
        return -1;
    }

    /**
     * Function:getNextNeighbor
     * 根据顶点,相对于一个邻接获取下一个邻接点的
     *
     * @param int $v 表示要找到顶点
     * @param int $index 表示该定点相对于哪个邻接点去获取下一个邻接点
     *
     * @return int
     */
    private function _getNextNeighbor($v,$index){

        for ($j = $index+1; $j<$this->vertexSize; $j++)
        {
            if($this->matrix[$v][$j]>0&&$this->matrix[$v][$j]<$this->MAX_WEIGHT){
                return $j;
            }
        }
        return -1;
    }
}

2、调用类


$graph = new \DataStructure\Graph\Graph(5);
$a1 = [0,$graph->MAX_WEIGHT,$graph->MAX_WEIGHT,$graph->MAX_WEIGHT,6];
$a2 = [9,0,3,$graph->MAX_WEIGHT,$graph->MAX_WEIGHT];
$a3 = [2,$graph->MAX_WEIGHT,0,5,$graph->MAX_WEIGHT];
$a4 = [$graph->MAX_WEIGHT,$graph->MAX_WEIGHT,$graph->MAX_WEIGHT,0,1];
$a5 = [$graph->MAX_WEIGHT,$graph->MAX_WEIGHT,$graph->MAX_WEIGHT,$graph->MAX_WEIGHT,0];
$graph->matrix[0] = $a1;
$graph->matrix[1] = $a2;
$graph->matrix[2] = $a3;
$graph->matrix[3] = $a4;
$graph->matrix[4] = $a5;

$degree = $graph->getOutDegree(4);
echo "V0的出度:".$degree.PHP_EOL;
$weight = $graph->getWeight(0,4);
echo "V0-V4的权值:".$weight.PHP_EOL;
$degree = $graph->getInDegree(4);
echo "V0的入度:".$degree.PHP_EOL;

3、github地址

git@github.com:wonlon/DataStructure.git

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
普利算法是一种用于求解无向最小生成树的基本算法。它以一个起始节点开始,每次将一个未被访问的节点加入到最小生成树集合中,并选择与该集合相邻的边中权重最小的边和它连接的未访问节点,直到最小生成树集合包含了中的所有节点。普利算法的时间复杂度为O(n^2)。 以下是普利算法的步骤: 1. 选择一个起始节点作为最小生成树的起点。 2. 将该起始节点加入最小生成树集合,并将其标记为已访问。 3. 在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点。 4. 将该边和节点加入最小生成树集合,并将该节点标记为已访问。 5. 重复步骤3和步骤4,直到最小生成树集合包含了中的所有节点。 以下是Python实现普利算法的代码: ```python def prim(graph): # 选择一个起始节点作为最小生成树的起点 start_node = list(graph.keys())[0] # 将该起始节点加入最小生成树集合,并将其标记为已访问 visited = [start_node] # 初始化最小生成树的权重为0 min_weight = 0 # 初始化最小生成树的边为空 min_tree = [] # 重复步骤3和步骤4,直到最小生成树集合包含了中的所有节点 while len(visited) < len(graph): # 在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点 min_edge = None for node in visited: for neighbor, weight in graph[node].items(): if neighbor not in visited: if min_edge is None or weight < min_edge[2]: min_edge = (node, neighbor, weight) # 将该边和节点加入最小生成树集合,并将该节点标记为已访问 visited.append(min_edge[1]) min_weight += min_edge[2] min_tree.append(min_edge) # 返回最小生成树的权重和边 return min_weight, min_tree ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值