查詢演算法之二分法

echo_dump發表於2019-12-12

查詢演算法之二分法

  • 二分法查詢的前提是待找的陣列是一個有序的陣列(這裡假設陣列是一個從小到大的陣列)

  • 遞迴的查詢需要找到的值

  • 思路:首先是一個有序的陣列,找到這個陣列的中間值,然後需要找到的值和這個中間值比較,如果是比中間值小,就向右遞迴,否則向左遞迴

  • 陣列 $arr = [2, 36, 25, 1, -1, 45, 99];

  • 待找到的值 -1

<?php
/**
 * Notes:
 * File name:${fILE_NAME}
 * Create by: Jay.Li
 * Created on: 2019/12/11 0011 17:00
 */
class dichotomy
{
    public function searchValue(array $data, int $leftIndex, int $rightIndex, int $findValue)
    {
        if (!is_array($data)) {
            return ['message' => '非陣列', 'status' => 0];
        }

        $middleIndex = floor(($leftIndex + $rightIndex) / 2);//中間值的鍵
        $middleValue = $data[$middleIndex];//中間值

        /**
         * 遞迴結束條件
         */
        if ($leftIndex > $rightIndex) {
            return -1;
        }

        if ($findValue > $middleValue) {
            return $this->searchValue($data, $middleIndex + 1, $rightIndex, $findValue);
        } elseif ($findValue < $middleValue) {
            return $this->searchValue($data, $leftIndex, $middleIndex - 1, $findValue);
        } else {
            return $middleIndex;
        }
    }
}

$obj = new dichotomy();
//$data = [2, 36, 25, 1, -1, 45, 99];
$data = [20,50,60,70,80,90,100,280,290,390,490,490,590,690,790,890,990,1000,10101,1000000];
var_dump($obj->searchValue($data, 0, count($data) - 1, 590));

上述的二分查詢法還有一定的侷限性,當它找到某個需要的值的時候,就會直接返回,如果有需要得到所有相同的鍵,目前就不滿足了,所以現在需要這樣:

<?php
/**
 * Notes:
 * File name:${fILE_NAME}
 * Create by: Jay.Li
 * Created on: 2019/12/11 0011 17:00
 */
class dichotomy
{
    public function searchValue2(array $data, int $leftIndex, int $rightIndex, int $findValue)
    {
        if (!is_array($data)) {
            return ['message' => '非陣列', 'status' => 0];
        }
        $arr = [];
        $middleIndex = floor(($leftIndex + $rightIndex) / 2);//中間值的鍵
        if ($middleIndex < $leftIndex || $middleIndex > $rightIndex) {
            return ['message' => sprintf("該 [%d] 值不在陣列內", $findValue), 'status' => 0];
        }
        $middleValue = $data[$middleIndex];//中間值

        /**
         * 遞迴結束條件
         */
        if ($leftIndex > $rightIndex) {
            return $arr[] = -1;
        }

        if ($findValue > $middleValue) {
            return $this->searchValue2($data, $middleIndex + 1, $rightIndex, $findValue);
        } elseif ($findValue < $middleValue) {
            return $this->searchValue2($data, $leftIndex, $middleIndex - 1, $findValue);
        } else {
            $tempLeft = $middleIndex - 1;
            while (true) {
                //向左迴圈,得到所有相同的鍵
                if ($tempLeft < $leftIndex || $data[$tempLeft] != $middleValue) {
                    //迴圈退出的條件,當鍵值越界或者是下一個值和中間值找到的值不相等,退出
                    break;
                }

                array_push($arr, $tempLeft);
                $tempLeft--;
            }
            array_push($arr, $middleIndex);

            $tempRight = $middleIndex + 1;
            while (true) {
                //向右迴圈,得到所有相同的鍵
                if ($tempRight > $rightIndex || $data[$tempRight] != $middleValue) {
                    break;
                }
                array_push($arr, $tempRight);
                $tempRight++;
            }
            return $arr;
        }
    }
}

try {
    $obj = new dichotomy();
//$data = [2,3,5,8,8,8, 45, 99];
    $data = [20,50,60,70,80,90,100,280,290,390,490,490,590,590,590,590,590,690,790,890,990,1000,10101,1000000];
    var_dump($obj->searchValue2($data, 0, count($data) - 1, 100000011));
    var_dump($obj->searchValue2($data, 0, count($data) - 1, 590));
} catch (\Exception $e) {
    var_dump($e->getMessage());
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結
LIYi ---- github地址

相關文章