基础算法:冒泡排序、选择排序、插入排序、快速排序的PHP实现过程

作者: 乘风御上者 分类: PHP 发布时间: 2020-04-21 22:57

算法作为程序的核心,无论使用哪种语言都是不能忽略的。在PHP中虽然接触的不多,但是基本的四种算法还是必须要掌握的。(以下示例默认排序方式为从小到大排序)

冒泡排序

重复地走访要排序的数组,依次比较两个元素。若它们的顺序错误则交换它们位置,走访数组的工作是重复地进行直到某次走访不在发生交换位置操作,则排序完成。

思路:

  1. 遍历数组,比较相邻元素大小,前者大于后者则交换它们的位置
  2. 每遍历一轮则最后一个元素为最大元素
  3. 根据步骤二规则,下次遍历的元素截止到上一轮最大元素前即可
  4. 持续遍历数组,直到没有元素需要比较
/**
 * 冒泡排序
 * @param $arr
 * @return array
 */
function bubbleSort($arr) {

    // 首先得到数组长度,通过数组长度确定遍历几轮及每轮多少次交换操作
    $len = count($arr);

    // 确定遍历轮数
    for ($i = 1; $i < $len; $i++) {

        // 确定每轮的交换次数
        for ($k = 0; $k < $len - $i; $k++) {

            // 每次交换前比较元素大小,若前者大则交换位置(后者大则无需交换)
            if ($arr[$k] > $arr[$k + 1]) {

                // 通过一个临时变量来达到交换目的
                $tmp = $arr[$k + 1];
                $arr[$k + 1] = $arr[$k];
                $arr[$k] = $tmp;
            }
        }
    }
    
    return $arr;
}

选择排序

在未排序的数组中找到最小元素,将其放在排序数组的末尾。然后在剩余未排序的数组中继续寻找最小元素,并将其放在排序数组的末尾。重复此操作,直到所有元素都排序完成。

/**
 * 选择排序
 * @param $arr
 * @return array
 */
function selectSort($arr) {

    // 首先得到数组长度,通过数组长度确定遍历查找次数
    $len = count($arr);

    // 遍历所要排序数组(根据该算法特性,遍历到最后一个元素时已不需要继续操作)
    for ($i = 0; $i < $len - 1; $i++) {

        // 假定第$i次元素为最小元素的下标
        $minKey = $i;

        // 遍历最小元素后面的所有元素
        for ($j = $i + 1; $j < $len; $j++) {

            // 若该值小于假定的最小值,则将该值作为最小值
            $minKey = ($arr[$minKey] > $arr[$j]) ? $j : $minKey;
        }

        // 该轮最小值的下标此时已确定,并保存在$minKey中
        // 若最小值的位置不是假定位置,则将位置交换
        if ($minKey != $i) {
            $tmp = $arr[$minKey];
            $arr[$minKey] = $arr[$i];
            $arr[$i] = $tmp;
        }
    }

    return $arr;
}

插入排序

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

思路:

  1. 数组第一个元素划分为有序数组
  2. 取出下一个元素,将该元素与有序数组的元素从后向前依次比较
  3. 若该元素小于有序数组的对比元素,则交换他们的位置
  4. 重复步骤三,直到该元素大于或等于对比元素,结束有序数组遍历
  5. 重复步骤二,直到取完剩余数组元素
/**
 * 插入排序
 * @param $arr
 * @return array
 */
function insertSort($arr) {

    // 首先得到数组长度
    $len = count($arr);

    // 遍历未排序的数组元素(默认第一个元素作为有数组元素)
    for ($i = 1; $i < $len; $i++) {

        // 当前需要比较的元素
        $tmp = $arr[$i];

        // 遍历有序数组(从后向前遍历,即先遍历最大值)
        for ($j = $i - 1; $j >= 0; $j--) {

            // 若比较元素小于当前排序数组元素
            if ($tmp < $arr[$j]) {

                // 将比较元素与前面的元素互换
                $arr[$j + 1] = $arr[$j];
                $arr[$j] = $tmp;
            } else {

                // 比较元素位置不需要移动,无需再和剩余有序数组比较
                break;
            }
        }
    }

    return $arr;
}

快速排序

在平均状况下,排序n个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。

思路:

  1. 从数列中挑出一个元素,称为”基准”
  2. 重复排序数组,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置
  3. 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序
/**
 * 快速排序
 * @param $arr
 * @return array
 */
function quickSort($arr) {

    // 首先得到数组长度
    $len = count($arr);

    // 判断数组长度
    if ($len <= 1) {
        return $arr;
    }

    // 定义两个空数组
    $left = [];
    $right = [];

    // 第一个元素作为比较的对象
    $middle = $arr[0];

    // 遍历去除作为比较的第一个元素的数组
    for ($i = 1; $i < $len; $i++) {

        // 判断当前元素与比较对象的大小
        if ($arr[$i] < $middle) {
            
            // 当前值小则放入左边数组中
            $left[] = $arr[$i];
        } else {

            // 当前值大则放入右侧数组中
            $right[] = $arr[$i];
        }
    }

    //递归调用
    $left = quickSort($left);
    $right = quickSort($right);

    //将所有的结果合并
    return array_merge($left, [$middle], $right);
}

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

发表回复