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

原创
2019/06/22 01:24
阅读数 163

常用算法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));

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部