导航

算法

Posted on 2020-11-12 20:31  玻璃星  阅读(69)  评论(0编辑  收藏  举报
<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2020/10/28
 * Time: 10:45
 */

namespace App\Http\Controllers;

use Illuminate\Routing\Controller as BaseController;

class Sort extends BaseController
{
    public function index()
    {
        echo "There is Sort";
        echo "<br>";
        echo "<pre/>";

        $arr = [4, 8, 5, 7, 3, 1, 5, 6, 7, 8];
        $arr = [677, 51, 24, 344, 455, 200, 576, 36, 226, 81];
        print_r($arr);
//        $arr = $this->shell_sort($arr); //**********
//        $this->heap_sort($arr);

//        $arr = $this->radix_sort($arr);
//        $arr = $this->bucket_sort($arr);
//        $arr = $this->counting_sort($arr);
//        $arr = $this->insertion_sort($arr);
//        $arr = $this->merge_sort($arr);
        $this->bubble_sort($arr);
//        $arr = $this->selection_sort($arr);
//        $arr = $this->quick_sort($arr);

        print_r($arr);
    }


    /**
     * 使用异或交换2个值,原理:一个值经过同一个值的2次异或后,原值不变
     * @param int $a
     * @param int $b
     */
    function swap(&$a,&$b){
        $a = $a^$b;
        $b = $a^$b;
        $a = $a^$b;
    }

    /**
     * 整理当前树节点($n),临界点$last之后为已排序好的元素
     * @param int $n
     * @param int $last
     * @param array $arr
     *
     */
    function adjustNode($n,$last,&$arr){
        $l = $n<<1;   // 左孩子
        if( !isset($arr[$l])||$l>$last ){
            return ;
        }
        $r = $l+1;  // 右孩子
        // 如果右孩子比左孩子大,则让父节点与右孩子比
        if( $r<=$last&&$arr[$r]>$arr[$l] ){
            $l = $r;
        }
        // 如果其中子节点$l比父节点$n大,则与父节点$n交换
        if( $arr[$l]>$arr[$n] ){
            $this->swap($arr[$l],$arr[$n]);
            // 交换之后,父节点($n)的值可能还小于原子节点($l)的子节点的值,所以还需对原子节点($l)的子节点进行调整,用递归实现
            $this->adjustNode($l, $last, $arr);
        }
    }

    /**
     * 堆排序(最大堆)
     * @param array $arr
     */
    function heap_sort(&$arr)
    {
        // 最后一个蒜素位
        $last = count($arr);
        // 堆排序中常忽略$arr[0]
        array_unshift($arr, 0);
        // 最后一个非叶子节点
        $i = $last >> 1;
        // 整理成最大堆,最大的数放到最顶,并将最大数和堆尾交换,并在之后的计算中,忽略数组最后端的最大数(last),直到堆顶(last=堆顶)
        while (true) {
            $this->adjustNode($i, $last, $arr);
            if ($i > 1) {
                // 移动节点指针,遍历所有节点
                $i--;
            } else {
                // 临界点$last=1,即所有排序完成
                if ($last == 1) {
                    break;
                }
                $this->swap($arr[$last], $arr[1]);
                $last--;
            }
        }
        // 弹出第一个元素
        array_shift($arr);
    }
    function radix_sort($arr)
    {
        $max = max($arr);
        $count = count($arr);

        //创建空桶
        for ($i = 0; $i < 10; $i++) {
            $buckets[$i] = [];
        }
        //最多几位数
        $digit = 0;
        while ($max > 0) {
            $max = intval($max / 10);
            $digit++;
        }
        for ($j = 0; $j < $digit; $j++) {   //最多几位数,就循环几轮
            $ten = pow(10, $j);  //取余10,100,1000...
            for ($k = 0; $k < $count; $k++) {    //遍历被排序的数组,分别塞进10个桶里
                for ($l = 0; $l < 10; $l++) {
                    if ($arr[$k]/$ten%10 === $l) {
                        array_push($buckets[$l], $arr[$k]);
                    }
                }
            }
            $arr = [];
            for ($m = 0; $m < 10; $m++) {
                while (!empty($buckets[$m])) {
                    array_push($arr, array_shift($buckets[$m]));
                }
            }
        }
        return $arr;
    }

    function bucket_sort($arr, $bucketSize = 5)
    {
        $count = count($arr);
        if ($count === 0) {
            return $arr;
        }
        $min = min($arr);
        $max = max($arr);
        $buckets = array();

        //创建空桶  20 5 3   17/5   3  4
        $bucketCount = intval(($max - $min) / $bucketSize) + 1;
        for ($i = 0; $i < $bucketCount; $i++) {
            $buckets[$i] = [];
        }

        //利用映射函数将数据分配到各个桶中
        for ($j = 0; $j < $count; $j++) {
            array_push($buckets[intval(($arr[$j] - $min) / $bucketCount)], $arr[$j]);
//            array_push($buckets[ceil(($arr[$i] - $min)/$bucketSize)],$arr[$i]);
        }

        $result = [];
        for ($k = 0; $k < count($buckets); $k++) {
            //桶内排序
            $buckets[$i] = $this->insertion_sort($buckets[$k]);
            //合并桶
            $result = array_merge($result, $buckets[$i]);
        }
        return $result;
    }

    /**
     * Time Complexion O(n+k)
     */
    function counting_sort($arr)
    {
        $min = min($arr);
        $max = max($arr);
        $temp = array();
        $result = array();

        for ($i = $min; $i <= $max; $i++) {
            $temp[$i] = 0;
        }
        for ($j = 0; $j < count($arr); $j++) {
            $temp[$arr[$j]]++;
        }
        for ($k = $min; $k < $max; $k++) {
            while ($temp[$k] > 0) {
                array_push($result, $k);
                $temp[$k]--;
            }
        }
        return $result;
    }
    /**
     * Time Complexion O(n²)
     */
    public function insertion_sort($arr)
    {
        $count = count($arr);
        for ($i = 0; $i < $count - 1; $i++) {
            for ($j = $i; $j >= 0; $j--) {
                if ($arr[$j + 1] < $arr[$j]) {
                    $temp = $arr[$j];
                    $arr[$j] = $arr[$j + 1];
                    $arr[$j + 1] = $temp;
                }
            }
        }
        return $arr;
    }

    /**
     * @param $arr
     * @return mixed
     *          654321
     *         654 321
     *        6 54  -
     *       - 5 4  -
     *       - - -  3  21
     *       - - -  -  2 1
     *       6 45  3  2  1
     *       645   3  2  1
     *       645   3  12
     *       645    123
     *         123456
     */
    public function merge_sort($arr)
    {
        $count = count($arr);
        if ($count <= 1) {
            return $arr;
        }

        $middle = intval($count / 2);
        $left = array_slice($arr, 0, $middle);
        $right = array_slice($arr, $middle);

        $left = $this->merge_sort($left);
        $right = $this->merge_sort($right);

        $output = $this->merge($left, $right);

        return $output;
    }

    public function merge($left, $right)
    {
        $result = array();
        while (count($left) > 0 && count($right) > 0) {
            if ($left[0] < $right[0]) {
                array_push($result, array_shift($left));
            } else {
                array_push($result, array_shift($right));
            }
        }
        array_splice($result, count($result), 0, $left);
        array_splice($result, count($result), 0, $right);

        return $result;
    }

    /**
     * 4321 1432 1243 1234 (最小放到前面)
     */
    public function selection_sort($arr)
    {
        $count = count($arr);
        for ($i = 0; $i < $count - 1; $i++) {
            for ($j = $i + 1; $j < $count; $j++) {
                if ($arr[$j] < $arr[$i]) {
                    $temp = $arr[$j];
                    $arr[$j] = $arr[$i];
                    $arr[$i] = $temp;
                }
            }
        }
    }

    /**
     * 4321  321 4 []
     *     21 3 []
     *   1 2 []
     *   1234
     * Time Complexity O(nlogn)?
     */
    public function quick_sort($arr)
    {

        $count = count($arr);
        if ($count <= 1) {
            return $arr;
        }

        $left = [];
        $right = [];
        $middle = $arr[0];

        for ($i = 1; $i < $count; $i++) {
            if ($arr[$i] < $middle) {
                array_push($left, $arr[$i]);
            } else {
                array_push($right, $arr[$i]);
            }
        }

        $left = $this->quick_sort($left);
        $right = $this->quick_sort($right);

        array_push($left, $middle);
        $result = array_merge($left, $right);
        return $result;
    }


    /**
     * 4321 3214 2134 1234 (最大放到后面)
     * 从第一个依次对比相邻两个元素到arr[n],大的移到,排好最大的元素
     * 从第一个依次对比相邻两个元素到arr[n-1],大的移到最后,排好最大和第二大的元素
     * ...
     * 从第一个依次对比相邻两个元素到arr[2],大的移到
     * Time Complexity O(n²)
     */
    public function bubble_sort(&$arr)
    {
        $count = count($arr);
        //比较次数(count-1次)
        for ($i = 0; $i < $count - 1; $i++) {
            //第一次比较count-1次,第二次比较count-2次....第count-1次比较1次
            for ($j = 1; $j < $count - $i; $j++) {
                if ($arr[$j - 1] > $arr[$j]) {
                    $temp = $arr[$j - 1];
                    $arr[$j - 1] = $arr[$j];
                    $arr[$j] = $temp;
                }
            }
        }
    }
}