1. 程式人生 > >常用演算法PHP版本-排序演算法和查詢演算法

常用演算法PHP版本-排序演算法和查詢演算法

常用演算法PHP版本

常用排序演算法

排序演算法說明

//排序演算法
//幾種排序演算法的結果都是一樣的,都可以進行升序或降序操作
//排序速度: 快速排序(在有序陣列時效率是最差的) > 直接插入排序演算法 > 選擇排序 > 冒泡

氣泡排序(升序)

<?php
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];

/**
 * 氣泡排序(升序)
 * 主要思路:
 * 1.遍歷陣列,遍歷次數為陣列長度
 * 2.遍歷陣列,每次將將當前元素和後一個做對比
 * 3.從頭開始, 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個,再比第二個和第三個,以此類推。
 *
 * @param array $data
 */
function bubbleSort(array $data)
{
    //統計陣列長度
    $length = count($data);
    //控制要冒泡的總輪數
    for ($i = 1; $i < $length; ++$i) {
        /**
         * 在本輪中遍歷所有剩餘的元素,$length - $i是因為對比過的就不用對比了, 因為對比過的他肯定比後面的小
         * 比如:
         * 這裡說的是升序
         * 第一步驟,下標為0對比下標為1,如果0>1,就把1挪到0,再把0挪到1.
         * 第二步, 在用下標1和下標2的對比,如果1>2,就把2挪到1,再把1挪到2.
         */
        for ($j = 0; $j < $length - $i; ++$j) {
            //如果第一個比第二個大,這裡是升序排序
            if ($data[$j] > $data[$j + 1]) {
                //將第二個放到一個臨時變數中
                $tmp = $data[$j + 1];
                //將第一個放到第二個位置中
                $data[$j + 1] = $data[$j];
                //將第二個放到第一個的位置中
                $data[$j] = $tmp;
            }
        }
    }

    return $data;
}

選擇排序(升序)

<?php
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];

/**
 * 選擇排序(升序)
 * 主要思路:
 * 1.先在未排序序列中找到最小元素,存放到排序序列的起始位置.
 * 2.然後,再從剩餘未排序元素中繼續尋找最小元素,然後放到排序序列末尾。
 * 3.以此類推,直到所有元素均排序完畢。
 *
 * @param [type] $data
 */
function selectSort($data)
{
    //獲取陣列長度
    $length = count($data);
    //按照長度,從0開始遍歷陣列
    for ($i = 0; $i < $length - 1; ++$i) {
        //假設當前元素的下標為最小元素的下標
        $minIndex = $i;
        //逐個遍歷當前下標後面的所有元素,這就是為了判斷當前元素是不是所有元素裡面最小的元素
        for ($j = $i + 1; $j < $length; ++$j) {
            //如果該元素<最小元素
            if ($data[$j] < $data[$minIndex]) {
                //則把該元素的下標放到最小下標裡面
                $minIndex = $j;
            }
        }
        //已經確定了當前的最小值的位置,儲存到$p中。
        //如果 最小值的下標與當前假設的下標$i不同,則互換位置
        if ($minIndex != $i) {
            $tmp = $data[$minIndex];
            $data[$minIndex] = $data[$i];
            $data[$i] = $tmp;
        }
    }

    return $data;
}

快速排序(升序)

<?php
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];

/**
 * 快速排序(升序).
 * 主要思路:
 * 從數列中挑出一個元素,稱為 "基準"(pivot);
 * 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。
 * 在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作;
 * 遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序;
 *
 * @param [type] $data
 */
function fastSort($data)
{
    $length = count($data);
    //必須滿足長度,否則返回原陣列
    if ($length <= 1) {
        return $data;
    }
    //定義空陣列
    $leftArray = [];
    $rightArray = [];
    //遍歷陣列,遍歷次數為陣列的長度
    for ($i = 1; $i < $length; ++$i) {
        //判斷當前元素是否小於陣列的第一個元素
        if ($data[$i] < $data[0]) {
            //當前元素<陣列的第一個元素,把當前元素放入$leftArray中
            $leftArray[] = $data[$i];
        } else {
            //當前元素>=陣列的第一個元素,把當前元素放入$rightArray中
            $rightArray[] = $data[$i];
        }
    }

    //遞迴呼叫
    $leftArray = fastSort($leftArray);
    //同時把$data[0]也追加進leftArray數組裡
    $leftArray[] = $data[0];
    $rightArray = fastSort($rightArray);
    //合併陣列
    $mergeArr = array_merge($leftArray, $rightArray);

    return $mergeArr;
}

直接插入排序(升序) 撮合引擎最常用的演算法

<?php
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];

/**
 * 直接插入排序(升序) 撮合引擎最常用的演算法.
 * 主要原理:
 * 工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。
 * 因而在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。
 *
 * @param [type] $data
 */
function insertSrot($data)
{
    //獲取陣列長度
    $length = count($data);
    //遍歷陣列,遍歷次數為陣列的長度
    for ($i = 1; $i < $length; ++$i) {
        //當前元素
        $current = $data[$i];
        //另一個遍歷方式,這種方式其實看起來更加的清晰,更容易理解
        // for ($j = $i - 1; $j >= 0; --$j) {
        //     if ($current < $data[$j]) {
        //         $data[$j + 1] = $data[$j];
        //         $data[$j] = $current;
        //     } else {
        //         break;
        //     }
        // }

        //前一個鍵
        $prefix = $i - 1;

        //如果下標不為0 並且前一個元素比當前元素大
        //這裡這個邏輯,基本上就是不斷的用前一個元素和當前元素比大小,如果前一個元素>當前元素,則把當前元素當到前面,然後在用當前元素繼續和前一個的前一個做對比
        //直到比到前一個元素不比當前元素小,則將當前元素放在這個元素的後面
        while ($prefix >= 0 && $data[$prefix] > $current) {
            //將前一個元素插入到當前位置
            $data[$prefix + 1] = $data[$prefix];
            --$prefix;
        }
        //否則將當前元素放到,最後一個比當前元素大的位置,再進行下一個迴圈
        $data[$prefix + 1] = $current;
    }

    return $data;
}

echo '氣泡排序'.PHP_EOL;
print_r(bubbleSort($arr));
echo '選擇排序'.PHP_EOL;
print_r(selectSort($arr));
echo '快速排序'.PHP_EOL;
print_r(fastSort($arr));
echo '插入排序'.PHP_EOL;
print_r(insertSrot($arr));

常用查詢演算法

二分查詢(不支援亂序查詢,所以要做好排序)

<?php

//二分查詢,因為每次可以捨去一半查詢區間,所以會將時間複雜度減少到O(logn),演算法更優。

//十個數,索引陣列下標到9
$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];
$arr1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

/**
 * 非遞迴的二分查詢,對亂序陣列無效.
 * 主要思路:
 * 先取陣列中間的值floor((lower+higher)/2),
 * 然後通過與所需查詢的數字進行比較,若比中間值大,則將首值替換為中間位置下一個位置,繼續第一步的操作;若比中間值小,則將尾值替換為中間位置上一個位置,繼續第一步操作
 * 重複第二步操作直至找出目標數字.
 *
 * @param array  $data   被查詢的內容
 * @param [type] $search 要查詢的內容
 */
function binarySearch(array $data, $search)
{
    $length = count($data);
    $lower = 0;
    $higher = $length - 1;

    while ($lower <= $higher) {
        //取出陣列中間的下標
        $middle = floor(($lower + $higher) / 2);
        //判斷屬於左右哪個部分
        if ($data[$middle] > $search) {
            //如果當前元素>搜尋元素, 向左移動一位即刪除右邊的資料
            $higher = $middle - 1;
        } elseif ($data[$middle] < $search) {
            //如果當前元素<搜尋元素, 向又移動一位即刪除左邊的資料
            $lower = $middle + 1;
        } else {
            //等於這個數,即為找到, 則返回
            return $middle;
        }
    }

    //沒有找到,返回 -1
    return -1;
}
echo '非遞迴的二分查詢'.PHP_EOL;
//不支援亂序
print_r(binarySearch($arr, 7));
echo PHP_EOL;
//支援順序
print_r(binarySearch($arr1, 7));
echo PHP_EOL;

/**
 * 遞迴二分查詢,對亂序陣列無效.
 *
 * @param [type] $data   被查詢的資料
 * @param [type] $search 要查詢的元素
 * @param [type] $lower  最小的鍵
 * @param [type] $higher 最大的鍵
 */
function binarySearchRecursion($data, $search, $lower, $higher)
{
    //上面看懂了這裡就不用說什麼了
    $middle = floor(($lower + $higher) / 2);
    if ($lower > $higher) {
        return -1;
    }
    if ($search > $data[$middle]) {
        $result = binarySearchRecursion($data, $search, $middle + 1, $higher);
    } elseif ($search < $data[$middle]) {
        $result = binarySearchRecursion($data, $search, $lower, $middle - 1);
    } else {
        $result = $middle;
    }

    return $result;
}

echo '遞迴二分查詢'.PHP_EOL;
//不支援亂序
print_r(binarySearchRecursion($arr, 7, 0, count($arr) - 1));
echo PHP_EOL;
//支援順序
print_r(binarySearchRecursion($arr1, 7, 0, count($arr1) - 1));

順序查詢

<?php

$arr = [5, 6, 3, 4, 2, 0, 1, 8, 9, 7];

/**
 * 順序查詢, 很顯然順序查詢就是從頭到尾挨個對比,比二分查詢的效能差很多倍
 * 基本上沒什麼難度,這裡在PHP中其實可以直接用foreach更好.
 *
 * @param [type] $data   被查詢的陣列
 * @param [type] $search 要查詢的內容
 */
function sequenceSearch($data, $search)
{
    $length = count($data);
    for ($i = 0; $i < $length; ++$i) {
        if ($data[$i] == $search) {
            return $i + 1;
        }
    }

    return -1;
}
print_r('順序查詢'.PHP_EOL);
print_r(sequenceSearch($arr, 9));

二叉樹查詢