排序法【PHP】

1. 插入排序法

<?php
/**
 * 插入排序
 * 思路:从第二个数起,把当前数插入到前面已排好序的序列中
 * 算法复杂度:
 * 空间复杂度:原址操作
 * 时间复杂度:n^2
 * @param array $arr
 * @return array
 */
function InsertSort(Array $arr)
{
    if(empty($arr)) {
        return [];
    }
    $len =count($arr);
    for($i = 1; $i < $len; $i++) {
        $j = $i - 1;
        $tmp = $arr[$i];
        while ($tmp < $arr[$j] && $j > -1) {
            $arr[$j + 1] = $arr[$j];
            $j--;
        }
        $arr[$j + 1] = $tmp;
    }
    return $arr;
}

//测试
$arr = [8,32,12,35,66,77,2,4];
print_r(InsertSort($arr));
/**
 * output:
 * Array
(
[0] => 2
[1] => 4
[2] => 8
[3] => 12
[4] => 32
[5] => 35
[6] => 66
[7] => 77
)
 */

2. 归并排序法

<?php
/**
 * 归并排序法
 * 思路:分治法,核心算法在合, 即总的数组的排序可由两个已经排好序的子数组的合并得到。
 * 复杂度:
 * 空间复杂度:合并时需要额外两个子数组,O(n)
 * 时间复杂度:O(nlogn) 稳定排序法
 * @param $arr 数组
 * @param $start 初始下标
 * @param $end 结束下标
 */
function MergeSort(&$arr, $start, $end)
{
    if($start < $end) {
        $mid = (int)(($start + $end) / 2);
        MergeSort($arr, $start, $mid);
        MergeSort($arr, $mid + 1, $end);
        Merge($arr, $start, $mid, $end);
    }
}

/**
 * 合并两个子数组
 * @param $arr 数组
 * @param $start 初始下标
 * @param $mid  两个子数组的分割点
 * @param $end 结束下标
 */
function Merge(&$arr, $start, $mid, $end)
{
    $left = $right = [];
    for($i = $start; $i <= $mid; $i++) {
        $left[] = $arr[$i];
    }
    for($i = $mid+1; $i <= $end; $i++) {
        $right[] = $arr[$i];
    }
    $lenLeft = $mid - $start + 1;
    $lenRight = $end - $mid;
    $l = $r = 0;
    $j = $start;
    while ($l < $lenLeft && $r < $lenRight) {
        $arr[$j++] = $left[$l] < $right[$r] ? $left[$l++] : $right[$r++];
    }
    while ($l < $lenLeft) {
        $arr[$j++] = $left[$l++];
    }
    while ($r < $lenRight) {
        $arr[$j++] = $right[$r++];
    }
}

//测试
$arr = [8,32,12,35,66,77,2,4];
MergeSort($arr, 0, count($arr) - 1);
print_r($arr);

/**
 * output:
 * Array
(
[0] => 2
[1] => 4
[2] => 8
[3] => 12
[4] => 32
[5] => 35
[6] => 66
[7] => 77
)
 */

3. 快速排序

/**
 * 快速排序法
 * 思路:分治法,核心算法在分。总的数组的排序可以对子数组的排序得到,子数组的排序又可以由子子数组的排序得到...
 * 复杂度:
 * 空间复杂度:原址操作
 * 时间复杂度:平均 O(nlogn),最差 n^2, 不稳定的排序法
 * @param $arr 数组
 * @param $start 初始下标
 * @param $end 结束下标
 */
function QuickSort(&$arr, $start, $end)
{
    if($start < $end) {
        $mid = Partition($arr, $start, $end);
        QuickSort($arr, $start, $mid - 1);
        QuickSort($arr, $mid + 1, $end);
    }
}

/**
 * 将数组分为两部分,小于基准数值的在左边, 大于基准数值的在右边,然后返回基准数值的位置
 * @param $arr
 * @param $start
 * @param $end
 */
function Partition(&$arr, $start, $end)
{
    $measure = $arr[$end]; //基准数值
    $p = $start - 1; //p用于表示小于基准数值的数的下标,比如有一个比基准数值小,那么该数下标为0,两个则是1,以此类推...
    for($i = $start; $i <= $end; $i++) {
        if($arr[$i] < $measure) {
            $tmp = $arr[$i];
            $arr[$i] = $arr[$p + 1];
            $arr[$p + 1] = $tmp;
            $p ++;
        }
    }
    $arr[$end] = $arr[$p + 1];
    $arr[$p + 1] = $measure;
    return $p + 1;
}

//测试
$arr = [8,32,12,35,66,77,2,4];
QuickSort($arr, 0, count($arr) - 1);
print_r($arr);

/**
 * output:
 * Array
(
[0] => 2
[1] => 4
[2] => 8
[3] => 12
[4] => 32
[5] => 35
[6] => 66
[7] => 77
)
 */

4. 堆排序

<?php
/**
 * 堆排序法
 * 思路:最大堆,将顶点(即最大值)放到最后,然后最剩下的再运行保持最大堆特性,然后在取最大值到倒数第二... 直到将所有节点值取出。
 * 复杂度:
 * 空间复杂度:原址操作
 * 时间复杂度:O(nlogn) 程序的空间局部性不好,不利于缓存,因为处理的数组元素都不是相邻的
 * @param $arr 数组
 */
function HeapSort(&$arr)
{
    $len = count($arr);
    BuildMaxHeap($arr, $len);
    for($i = $len - 1; $i > 0; $i--)
    {
        $tmp = $arr[$i];
        $arr[$i] = $arr[0];
        $arr[0] = $tmp;
        MaxHeapify($arr, 0, --$len);
    }
}

/**
 * 父节点下标
 * @param int $index
 * @return int
 */
function Parent($index)
{
    return (int)(($index - 1)/2);
}

/**
 * 左子节点下标
 * @param int $index
 * @return int
 */
function Left($index)
{
    return 2 * $index + 1;
}

/**
 * 右子节点下标
 * @param int $index
 * @return int
 */
function Right($index)
{
    return 2 * $index + 2;
}

/**
 * 保持最大堆的性质
 * @param array $arr
 * @param int $index 下标
 * @param int $len 数组长度
 */
function MaxHeapify(&$arr, $index, $len)
{
    $left = Left($index);
    $right = Right($index);
    $largest  = $index;
    if($left < $len && $arr[$left] > $arr[$index]) {
        $largest = $left;
    }
    if($right < $len && $arr[$right] > $arr[$largest]) {
        $largest = $right;
    }
    if($index != $largest) {
        $tmp = $arr[$index];
        $arr[$index] = $arr[$largest];
        $arr[$largest] = $tmp;
        MaxHeapify($arr, $largest, $len);
    }
}

/**
 * 建堆
 * @param array $arr
 * @param int $len 数组长度
 */
function BuildMaxHeap(&$arr, $len)
{
    $start = (int)($len/2) - 1;
    for($i = $start; $i >= 0; $i--) {
        MaxHeapify($arr, $i, $len);
    }
}


//测试
$arr = [8,32,12,35,66,77,2,4];
HeapSort($arr);
print_r($arr);

/**
 * output:
 * Array
(
[0] => 2
[1] => 4
[2] => 8
[3] => 12
[4] => 32
[5] => 35
[6] => 66
[7] => 77
)
 */

附上部分算法的go实现

package main

import "fmt"

func main() {
    arr := []int{8,6,12,35,66,77,2,32}
    //fmt.Println(InsertSort(arr))
    //MergeSort(&arr, 0, len(arr) -1)

    QuickSort(&arr, 0, len(arr) -1)
    fmt.Println(arr)
}



func InsertSort(arr []int) []int {
    total := len(arr)
    if total == 0 {
        return arr
    }
    for i:=1; i < total; i++ {
        j := i - 1
        tmp := arr[i]
        for j >= 0 && tmp < arr[j]  {
            arr[j+1] = arr[j]
            j--
        }
        arr[j+1] = tmp
    }
    return arr
}

func MergeSort(arr *[]int, start, end int) {
    if start < end {
        mid := (start + end) / 2
        MergeSort(arr, start, mid)
        MergeSort(arr, mid + 1, end)
        Merge(arr, start, mid, end)
    }
}

func Merge(arr *[]int, start, mid, end int) {
    var left, right []int
    for i := start; i <= mid; i++ {
        left = append(left, (*arr)[i])
    }
    for i := mid + 1; i <= end; i++ {
        right = append(right, (*arr)[i])
    }
    l, r := 0,0
    lenLeft := len(left)
    lenRight := len(right)
    j := start
    for l<lenLeft && r<lenRight  {
        if left[l] < right[r] {
            (*arr)[j] = left[l]
            j++
            l++
        } else {
            (*arr)[j] = right[r]
            j++
            r++
        }
    }
    for l < lenLeft {
        (*arr)[j] = left[l]
        j++
        l++
    }
    for r < lenRight {
        (*arr)[j] = right[r]
        j++
        r++
    }
}

func QuickSort(arr *[]int, start, end int) {
    if start < end {
        mid := Partition(arr, start, end)
        QuickSort(arr, start, mid - 1)
        QuickSort(arr, mid + 1, end)
    }
}

func Partition(arr *[]int, start, end int) int {
    measure := (*arr)[end]
    p := start - 1 //p用于表示小于基准数值的数的下标,比如有一个比基准数值小,那么该数下标为0,两个则是1,以此类推...
    for i := start; i <= end; i++ {
        if (*arr)[i] < measure {
            if i > p+1 {
                tmp := (*arr)[i]
                (*arr)[i] = (*arr)[p+1]
                (*arr)[p+1] = tmp
            }
            p++
        }
    }
    (*arr)[end] = (*arr)[p+1]
    (*arr)[p+1] = measure
    return p+1
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,729评论 0 15
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,170评论 0 52
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,245评论 0 2
  • 一、 单项选择题(共71题) 对n个元素的序列进行冒泡排序时,最少的比较次数是( )。A. n ...
    貝影阅读 9,043评论 0 10
  • 1 初级排序算法 排序算法关注的主要是重新排列数组元素,其中每个元素都有一个主键。排序算法是将所有元素主键按某种方...
    深度沉迷学习阅读 1,397评论 0 1