【比較類排序算法】冒泡排序、選擇排序、快速排序、插入排序、希爾排序(PHP)

常見的經(jīng)典比較類排序算法有冒泡排序選擇排序快速排序插入排序希爾排序。這幾種排序中快速排序和希爾排序的平均時(shí)間復(fù)雜度都突破了O(n^2),主要得益于這兩種排序每輪排序都對(duì)下一輪產(chǎn)生影響,而其余的排序如選擇排序每輪排序只是單純從數(shù)組中找出最值,而沒有對(duì)下一次的數(shù)組排序做出貢獻(xiàn)。
<輸入的最好方式就是輸出>,本著學(xué)習(xí)的態(tài)度表達(dá)一下自己淺顯的理解。下面主要介紹每種算法的中心思想,具體的代碼實(shí)現(xiàn)(PHP),并分析對(duì)應(yīng)的時(shí)間復(fù)雜度和空間復(fù)雜度。

1.冒泡排序

以升序?yàn)槔ê竺嫱恚芭菖判虻乃悸肥牵合噜弮蓚€(gè)元素進(jìn)行比較實(shí)現(xiàn)左小右大,交換完一輪得到最大值位于最后一位,按這個(gè)方式交換n-1輪(n為元素總數(shù),后面同理)即完成排序。

代碼如下:

function bubbleSort(array $arr)
{
    $len = count($arr);
    for ($i = 0; $i < $len - 1; $i++) {
        for ($k = 0; $k < $len - 1 - $i; $k++) {
            //交換位置條件
            if ($arr[$k] > $arr[$k + 1]) {
                $tmp = $arr[$k];
                $arr[$k] = $arr[$k + 1];
                $arr[$k + 1] = $tmp;
            }
        }
    }
    return $arr;
}

記憶關(guān)鍵詞: 左右交換、每輪最值、n-1輪
性能分析:時(shí)間復(fù)雜度O(n^2),空間復(fù)雜度O(1)

2.選擇排序

選擇排序的思路是:從左邊第1個(gè)元素開始,與右邊剩下的數(shù)組元素進(jìn)行比較,每一輪得到最小值位于左側(cè),總共比較n-1輪完成排序。

代碼如下:

function selectSort(array $arr)
{
    $len = count($arr);
    for ($i = 0; $i < $len - 1; $i++) {
        $min = $arr[$i];//最小值
        $minIndex = $i;//最小值下標(biāo)
        for ($k = $i + 1; $k < $len; $k++) {
            if ($min > $arr[$k]) {
                $min = $arr[$k];
                $minIndex = $k;
            }
        }
        //比較完一輪后,交換左側(cè)位置的最小值
        $tmp = $arr[$i];
        $arr[$i] = $arr[$minIndex];
        $arr[$minIndex] = $tmp;
    }
    return $arr;
}

記憶關(guān)鍵詞: 左元素、右數(shù)組、左側(cè)累加最值
性能分析:時(shí)間復(fù)雜度O(n^2),空間復(fù)雜度O(1)

3.快速排序

快速排序的核心思想是遞歸和二分,思路是:先將待排數(shù)組分為左右分區(qū),并獲得中間基準(zhǔn),使得左分區(qū)元素均小于中間基準(zhǔn),右分區(qū)元素均大于中間基準(zhǔn)。同樣地,左右兩分區(qū)按照相同的方式,遞歸劃分各自的左右分區(qū),最后完成排序。
快速排序的關(guān)鍵在于中間基準(zhǔn)的確定,方法是:取數(shù)組左邊第一位作為初始基準(zhǔn),把它與右邊剩下的所有元素比較,依次將小于該基準(zhǔn)的元素進(jìn)行替換并記錄位置,最后把獲取到的位置元素與初始基準(zhǔn)元素交換,完成左右分區(qū),返回該中間基準(zhǔn)位置。

代碼如下:

function quickSort(array $arr, $left = null, $right = null)
{
    $len = count($arr);
    //初始化左右下標(biāo)位置
    $left = $left ?? 0;
    $right = $right ?? $len - 1;

    //遞歸條件
    if ($left < $right) {
        //獲取中心基準(zhǔn)
        $partitionIndex = getPartitionIndex($arr, $left, $right);
        //左分區(qū)遞歸
        $arr = quickSort($arr, $left, $partitionIndex - 1);
        //右分區(qū)遞歸
        $arr = quickSort($arr, $partitionIndex + 1, $right);
    }

    return $arr;
}

/**
 * 將數(shù)組進(jìn)行左右分區(qū),并返回中心基準(zhǔn)位置
 * @param array $arr
 * @param int $left
 * @param int $right
 * @return int
 */
function getPartitionIndex(array &$arr, int $left, int $right)
{
    $pivot = $left;//初始基準(zhǔn)
    $index = $left + 1;//初始化游標(biāo)位置,中心基準(zhǔn)交換位置的下一位
    for ($i = $index; $i <= $right; $i++) {
        //將元素與初始基準(zhǔn)比較
        if ($arr[$i] < $arr[$pivot]) {
            //小于基準(zhǔn),與游標(biāo)元素交換
            $tmp = $arr[$i];
            $arr[$i] = $arr[$index];
            $arr[$index++] = $tmp;//移動(dòng)游標(biāo)
        }
    }

    //比較結(jié)束獲得中心基準(zhǔn)位置,與初始基準(zhǔn)交換
    $resultIndex = $index - 1;
    $tmp = $arr[$pivot];
    $arr[$pivot] = $arr[$resultIndex];
    $arr[$resultIndex] = $tmp;
    return $resultIndex;
}

記憶關(guān)鍵詞: 二分、遞歸、左右分區(qū),中間基準(zhǔn)
性能分析:時(shí)間復(fù)雜度O(nlog2n),因?yàn)槔枚诌f歸進(jìn)行排序,時(shí)間復(fù)雜度突破n^2;空間復(fù)雜度O(log2n),與遞歸次數(shù)相關(guān)。

4.插入排序

插入排序的思路是:左邊先構(gòu)建有序數(shù)組(初始為左邊第一個(gè)元素),右邊元素從其下一位開始與其比較,若大于其末位元素則直接在末尾插入,否則繼續(xù)往左遍歷比較,確認(rèn)插入位置,最后交換插入,構(gòu)建新的有序數(shù)組。右邊元素依次按照該方式插入有序數(shù)組,完成排序。

代碼如下:

function insertSort(array $arr)
{
    $len = count($arr);
    for ($i = 1; $i < $len; $i++) {
        $index = $i - 1;//左邊數(shù)組末位元素
        $current = $arr[$i];//右邊第一個(gè)元素
        //當(dāng)前值遍歷左邊數(shù)組,進(jìn)行比較
        while ($index >= 0 && $current < $arr[$index]) {
            $arr[$index + 1] = $arr[$index];//左邊數(shù)組擴(kuò)大,最大值右移
            $index--;//左邊數(shù)組比較位往前移
        }
        //插入左邊數(shù)組結(jié)果位置
        $arr[$index + 1] = $current;
    }
    return $arr;
}

記憶關(guān)鍵詞: 左有序數(shù)組、右元素遍歷、右移插入
性能分析:時(shí)間復(fù)雜度O(n^2),由代碼可看出右移次數(shù)越少,右元素掃描遍歷的次數(shù)就越少(由此引出插入排序的改良版希爾排序),最好的時(shí)間復(fù)雜度是O(n); 空間復(fù)雜度O(1)。

5.希爾排序

希爾排序是插入排序的改良版,也稱縮小增量排序。思路是:將待排數(shù)組,按照指定的增量進(jìn)行分組,每組分別進(jìn)行插入排序,由于每個(gè)分組都經(jīng)過(guò)排序,從而導(dǎo)致整個(gè)數(shù)組宏觀上相對(duì)有序。最后將整個(gè)數(shù)組再進(jìn)行一次插入排序。因?yàn)榍懊娣纸M排序?qū)ψ詈笠淮闻判虍a(chǎn)生了積極影響,所以整體的排序速度得到提升。

代碼如下:

function shellSort(array $arr)
{
    $len = count($arr);
    //增量確定,這里取數(shù)組長(zhǎng)度一半;
    //增量gap即為分組數(shù),每趟下來(lái)分組數(shù)減半,直到分組數(shù)為1進(jìn)行最后一次插入排序
    for ($gap = intval($len / 2); $gap > 0; $gap = intval($gap / 2)) {
        //對(duì)gap個(gè)數(shù)組分別進(jìn)行插入排序
        for ($i = $gap; $i < $len; $i++) {
            $current = $arr[$i];//當(dāng)前比較值
            $index = $i;//游標(biāo)位置
            //當(dāng)前值與上一個(gè)值比較(因?yàn)榘凑誫ap分組,所以分組內(nèi)上一個(gè)值為index-gap)
            while ($index - $gap >= 0 && $current < $arr[$index - $gap]) {
                $arr[$index] = $arr[$index - $gap];
                $index = $index - $gap;
            }
            $arr[$index] = $current;
        }
    }
    return $arr;
}

記憶關(guān)鍵詞: 確定增量、分組插入排序、縮小增量
性能分析:時(shí)間復(fù)雜度:O(nlogn)~O(n^2), 空間復(fù)雜度O(1)

非比較類排序算法傳送門:http://www.lxweimin.com/p/8de11b38ff18

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容