php算法

<?php
/**
 * Created by PhpStorm.
 * User: ckzbfhq919
 * Date: 2017/10/18
 * Time: 12:50
 * https://www.cnblogs.com/onepixel/articles/7674659.html
 */
/*排序算法
排序算法有内部排序和外部排序,内部排序是数据记录在内存中进行排序,外部排序是因排序的数据很大,一次不能容纳全部
排序记录,在排序过程中需要访问外存
我们这里说的八大排序就是内部排序

排序:
       1.内部排序
        插入排序
        选择排序
        交换排序
        归并排序
        基数排序
*/

/*
 * 插入排序 直接插入排序
 * 基本思想 将1个记录插入到已排好的有序表中,从而得到1个新的,记录数增加1的有序表。即先将序列的第一个记录看成是
 *         1个有序的子序列,然后从第二个记录逐个进行插入,直至整个序列有序为止
 * 要点:设立哨兵,作为临时存储和判断数组边界之用
 * 如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放到相等元素的后面,所以,相等元素的前后顺序没有改变,从原无序序列
 * 出去的顺序就是排好序后的顺序,所以插入排序是稳定的
 *
 */
function insertSort(array $arr,$n){
    //区分哪部分是排好的,哪部分是没有排序的
    //找到其中一个需要排序的元素
    //这个元素就是从第二个元素开始,到最后一个元素都是需要排序的元素
    //利用这个循环就可以标志出来
    //i循环控制,每次需要插入的元素,一旦需要插入的元素控制好了,间接已经把数组分成了两部分,下标小于当前的是已经排好的序列
    for($i = 1; $i < $n;$i++){
        $tmp = $arr[$i];

        //内层循环控制并比较
        for($j = $i-1;$j >= 0;$j--){
            //$arr[$i] 需要插入的元素
            //$arr[$j] 需要比较的元素
            //监视哨的值 比 查找的值小 并且 没有到此次查询的第一个
            if($tmp < $arr[$j]){
                //发现插入的元素要小,交换位置
                //将后边的元素与前面的元素交换
                $arr[$j+1] = $arr[$j];
            }else{
                //碰到不需要移动的元素
                //由于是已经排好的数组,则前面的就不需要再次比较了
                break;
            }
        }

        //插入
        $arr[$j+1] = $tmp;
    }
    return $arr;
}

$arr = [3,2,42,56,8,2];
$arr2 = insertSort($arr,count($arr));
print_r($arr2);


/*
 * 希尔排序
 * 基本思想:先将整个待排的序列分割成若干序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体记录进行依次直接排序
 * 实质是分组插入排序
 * 操作方法:
 *  1.选择1个增量序列,t1,t2,t3,t4,...,tk,其中ti>tj,tk=1
 *  2.按增量序列个数k,对序列进行k趟排序
 *  3.每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各子序列进行直接插入排序,仅增量因子为1时,整个序列作为1个
 *     表来处理,表长度即为整个序列的长度
 *
 */
function shell_sort(array $arr){
    // 将$arr按升序排列
    $len = count($arr);
    $f = 4;// 定义因子
    $h = 1;// 最小为1
    while ($h < $len/$f){
        $h = $f*$h + 1; // 1, 4, 13, 40, 121, 364, 1093, ...
    }
    while ($h >= 1){  // 将数组变为h有序
        for ($i = $h; $i < $len; $i++){  // 将a[i]插入到a[i-h], a[i-2*h], a[i-3*h]... 之中 (算法的关键
            for ($j = $i; $j >= $h;  $j -= $h){
                if ($arr[$j] < $arr[$j-$h]){
                    $temp = $arr[$j];
                    $arr[$j] = $arr[$j-$h];
                    $arr[$j-$h] = $temp;
                }
                //print_r($arr);echo '<br/>'; // 打开这行注释,可以看到每一步被替换的情形
            }
        }
        $h = intval($h/$f);
    }
    return $arr;
}

function shellSort3($arr)
{
    //计算长度
    $n = count($arr);
    //计算增量
    for ($gap = floor($n / 2); $gap > 0; $gap = floor($gap / 2)) { //步长

        //分组 第一次5组 第二次2组 第三次1组
        for ($i = 0; $i < $gap; $i++)
        {
            //分组之后的数据,每组内部进行直接插入排序
            for ($j = $i + $gap; $j < $n; $j += $gap)
            {

                $tmp = $arr[$j];

                for ($k = $j - $gap;$k >= 0 && $arr[$k] > $tmp;$k -= $gap)
                {
                    $arr[$k + $gap] = $arr[$k];
                }

                $arr[$k + $gap] = $tmp;
            }
        }
    }
    return $arr;
}


$arr = array(14, 29, 1, 4, 6, 2,1);

$shell = shellSort3($arr);
print_r($shell);

/*
 * 选择排序
 * 要点:在要排序的一组数中,选出最小或者最大的一个数与第一个位置的数交换,然后在剩下的数当中再找最小的与第二个位置的数交换,
 *       直到第n-1个元素和第n个元素比较为止
 *
 */

function selectSort($arr) {
    //实现思路 双重循环完成,外层控制轮数,当前的最小值。内层 控制的比较次数
    //$i 当前最小值的位置, 需要参与比较的元素
    for($i=0, $len=count($arr); $i<$len-1; $i++) {
        //先假设最小的值的位置
        $p = $i;
        //$j 当前都需要和哪些元素比较,$i 后边的。
        for($j=$i+1; $j<$len; $j++) {
            //$arr[$p] 是 当前已知的最小值
            if($arr[$j]<$arr[$p]) {
                //比较,发现更小的,记录下最小值的位置;并且在下次比较时,
                // 应该采用已知的最小值进行比较。
                $p = $j;
            }
        }
        //已经确定了当前的最小值的位置,保存到$p中。
        //如果发现 最小值的位置与当前假设的位置$i不同,则位置互换即可
        if($p != $i) {
            $tmp = $arr[$p];
            $arr[$p] = $arr[$i];
            $arr[$i] = $tmp;
        }
    }
    //返回最终结果
    return $arr;
}

$arr = array(14, 29, 1, 4, 6, 2,1);
$arr2 = selectSort($arr);
print_r($arr2);


/*
 * 二元选择排序 这个有问题
 * 改进为每趟循环确定两个元素(当前趟最小和最大的记录)的位置,从而减少排序的所需次数。
 */
function selectSort2($arr){
    $n = count($arr);
    for($i=1;$i<floor($n/2);$i++)
    {
        $max = $i;$min = $i; //分别记录最大和最小的关键字记录位置
        for($j = $i+1;$j<$n-$i;$j++)
        {
            if($arr[$j]>$arr[$max])
            {
                $max = $j;
                continue;
            }

            if($arr[$j]<$arr[$min]){
                $min = $j;
            }
        }

        $tmp1 = $arr[$i-1];
        $arr[$i-1] = $arr[$min];
        $arr[$min] = $tmp1;

        $tmp2 = $arr[$n-1];
        $arr[$n-$i] = $arr[$max];
        $arr[$max] = $tmp2;
    }

    return $arr;
}



/**
 * 冒泡排序
 */
function getPao($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;
}
/*
 * 快速排序 交换排序
 * 思想:1.选择一个基准元素,通常选第一个元素或者最后一个元素
 *      2.通过1趟排序将待排序的元素
 */

// 寻找分割点,并交换值
function slicearr(&$arr, $low, $high)
{

    $i = $low;
    $j = $high + 1;
    $choosen = $arr[$low];
    while (1) {
        while ($arr[++$i] < $choosen) {// 从左边要找大的,把大的交换到右边去
            if ($i >= $high) break;
        }

        while ($arr[--$j] > $choosen) {// 从右边要找小的,交换到左边去
            if ($j <= $low) break;
        }

        // 从左往右找,或者从右往左找,如果i>j了,表示此处顺序对了,就不替换i,j位置的元素了,break掉
        if ($i >= $j) break;

        $temp = $arr[$i];
        $arr[$i] = $arr[$j];
        $arr[$j] = $temp;
    }

    $temp = $arr[$low];
    $arr[$low] = $arr[$j];
    $arr[$j] = $temp;

    //echo '<pre>';print_r($arr);   // 查看每次切分后的数组排序情况
    //echo $j,'<br/>'; // 查看切分点

    return $j;// 返回分割点
}

// 递归快速排序
function qsort(&$arr, $low, $high)
{
    if ($low >= $high) return;
    $i = slicearr($arr, $low, $high);// 该步骤的分割点
    qsort($arr, $low, $i - 1);// 递归调用
    qsort($arr, $i + 1, $high);

}
$arr3 = array(10, 292, 13, 24, 6, 2,1);
qsort($arr3,0, count($arr)-1);
print_r($arr3);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值