排序算法

冒泡排序 O n 2 O_{n^2} On2

1.循环比较相邻值,符合条件就交换位置,一次循环至少让一个元素移动到它应该在的位置
2.若在一次循环中没有位置发生交换,则认为该排序已完成

PHP

function bubble_sort(&$nums)
{
    $len = count($nums);
    for ($i = 0; $i < $len; $i++) {
        $change = false;
        for ($j = 0; $j < $len - $i - 1; $j++) {
            if ($nums[$j] > $nums[$j + 1]) {
                $tmp = $nums[$j];
                $nums[$j] = $nums[$j + 1];
                $nums[$j + 1] = $tmp;
                $change = true;
            }
        }
        if ($change === false) {
            break;
        }
    }
}

$nums = [4, 5, 6, 3, 2, 1];
bubble_sort($nums);
var_dump($nums);

GO

package main

import "fmt"

func main(){
    nums := []int{4, 5, 6, 3, 2, 1}
    bubble_sort(&nums)
    fmt.Println(nums)
}

func bubble_sort(nums *[]int) {
    len := len(*nums)
    for i := 0; i < len; i++ {
        change := 0
        for j := 0; j < len - i - 1; j++ {
            if (*nums)[j] > (*nums)[j+1] {
                tmp := (*nums)[j]
                (*nums)[j] = (*nums)[j+1]
                (*nums)[j+1] = tmp
                change = 1
            }
        }
        if change == 0 {
            break
        }
    }
}

插入排序 O n 2 O_{n^2} On2

1.将数组中的数据分为两个区间,已排序区间和未排序区间
2.初始已排序区间只有一个元素,就是数组的第一个元素
3.取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入,并保证已排序区间数据一直有序
4.重复这个过程,直到未排序区间中元素为空,算法结束

PHP

function insertion_sort(&$nums)
{
    $len = count($nums);
    for ($i = 0; $i < $len; $i++) {
        $value = $nums[$i];
        for ($j = $i - 1; $j >= 0; $j--) {
            if ($nums[$j] > $value) {
                $nums[$j + 1] = $nums[$j];
            } else {
                break;
            }
        }
        $nums[$j + 1] = $value;
    }
}

$nums = [4, 5, 6, 3, 2, 1];
insertion_sort($nums);
var_dump($nums);

GO

package main

import "fmt"

func main(){
    nums := []int{4, 5, 6, 3, 2, 1}
    insertion_sort(&nums)
    fmt.Println(nums)
}

func insertion_sort(nums *[]int) {
    var j int
    len := len(*nums)
    for i := 0; i < len; i++ {
        value := (*nums)[i]
        for j = i - 1; j >= 0; j-- {
            if ((*nums)[j] > value) {
                (*nums)[j + 1] = (*nums)[j]
            } else {
                break
            }
        }
        (*nums)[j + 1] = value
    }
}

选择排序 O n 2 O_{n^2} On2

选择排序算法的实现思路有点类似插入排序,也分已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾

PHP

function selection_sort(&$nums)
{
    $len = count($nums);
    for ($i = 0; $i < $len; $i++) {
        $min = $i;
        for ($j = $i + 1; $j < $len; $j++) {
            if ($nums[$j] < $nums[$min]) {
                $min = $j;
            }
        }
        if ($min != $i) {
            $tmp = $nums[$min];
            $nums[$min] = $nums[$i];
            $nums[$i] = $tmp;
        }
    }
}

$nums = [4, 5, 6, 3, 2, 1];
selection_sort($nums);
var_dump($nums);

快速排序 O n l o g n O_{nlogn} Onlogn

1.通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小
2.然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

双路快排

从当前数组中,找到一个元素作为基准比较值(key),分别从两个方向进行比较。从后往前找,比key小元素放在数组前面。然后从前往后找,比key大的元素放在数组后面。最终两个方向交汇到中间,让key交换到数组的中间位置。

常见的取key方式是,取当前排序数组范围的最左边第一位,key是从前边取的,所以先要从后边(右边)开始往前找数字。

1.令left为第一位0(first),令right为最末位数组长度n。
2.key是从前边取,我们就需要先从right开始,从后往前走。
3.如果 a[right]>=key(即34),说明是正常的,因为大数字就应该放后面。因此,right继续往前走,也就是right–。
4.直到出现 a[right]<key,这就说明有一个小数字出现在了后面,至于它是不是真的属于后面?这个还暂时不知道,所以先停下来,这时候的right就标记了这个位置。
5.从后往前找小数,已经找到了一个位置了,那么就换一个方向,从前往后找大数。因此从left开始,从前往后走。
6.如果 a[left]<=key(即34),说明是正常的,因为小数字就应该放前面。因此,left 继续往后走,也就是left++。(这里可以看出,left 和 right 的操作是对称的)
7.直到出现 a[left]>key, 这就说明有一个大数字出现在了前面,至于它是不是真的属于前面?这个就需要判断 left 和 right 的关系。
8.如果 left < right 此时,一个大数字出现在了前面,一个小数字出现在了后面,因此我们直接将其互换,将 a[left] 和 a[right] 互换。
9.互换完之后,当前的标记位left和right 继续两边往中间走。同理,先从right继续从后往前走,直到遇见一个小数字(比key小)。然后换方向从left继续从前往后走,直到遇见一个大数字(比key大)
10.如果left = right,说明以及抵达了数值的中心(now)
11.如果 first != now, 则交换位置
12.完成了这一轮的快速排序之后,就会发现,这个数组可以拆分成左半部分和右半部分。
13.左半部分是 从 第一位 到 now-1,里面的数字都比中心的a[now]小。
14.右半部分是 从 now+1 到 最末位 ,里面的数字都比中心的a[now]大。
15.因此,我们就可以继续递归地对左半部分和右半部分使用快速排序即可。
16.直到最终, 开始的left >= 开始right ,说明已经是拆成1个数字了,就没必要再比下去了。

PHP
sort() 当数据量较小时(小于等于16),会使用插入排序,因为此时插入排序性能更好;否则会使用快速排序

//非原地
function quick_sort($nums)
{
    if (count($nums) <= 1) {
        return $nums;
    }
    $left = [];
    $right = [];
    $len = count($nums);
    $pivot = $nums[0];
    for ($i = 1; $i < $len; $i++) {
        if ($nums[$i] > $pivot) {
            array_push($right, $nums[$i]);
        } else {
            array_push($left, $nums[$i]);
        }
    }

    return array_merge(quick_sort($left), array($pivot), quick_sort($right));
}

$nums = [4, 5, 6, 3, 2, 1];
$nums = quick_sort($nums);
var_dump($nums);

//双路快排(原地)
function quickSort(&$nums, $left = 0, $right = null) {
    if ($right === null) {
        $right = count($nums) - 1;
    }
    if ($left >= $right) {
        return;
    }
    $firstIndex = $left;
    $lastIndex = $right;
    $pivot = $nums[$firstIndex];
    while ($left != $right) {
        while ($pivot <= $nums[$right] && $left != $right) {
            $right--;
        }
        while ($pivot >= $nums[$left] && $left != $right) {
            $left++;
        }
        if ($left < $right) {
            $tmp = $nums[$right];
            $nums[$right] = $nums[$left];
            $nums[$left] = $tmp;
        }
    }
    if ($firstIndex != $left) {
            $tmp = $nums[$firstIndex];
            $nums[$firstIndex] = $nums[$left];
            $nums[$left] = $tmp;
    }
    quickSort($nums, $firstIndex, $left - 1);
    quickSort($nums, $firstIndex + 1, $lastIndex);
}

$nums = [34, 5, 5, 555, 5, 4, 14, 5, 88, 89, 54];
quickSort($nums);
print_r($nums);

GO

package main

import "fmt"

func main() {
	nums := []int{4, 5, 6, 3, 2, 1}
	nums2 := []int{4, 5, 6, 3, 2, 1}
	nums = quick_sort(nums)
	fmt.Println(nums)
	quickSort(&nums2, 0, len(nums2)-1)
	fmt.Println(nums2)
}

//非原地
func quick_sort(nums []int) []int {
	var left, right []int
	len := len(nums)
	if len <= 1 {
		return nums
	}
	pivot := nums[0]
	for i := 1; i < len; i++ {
		if nums[i] <= pivot {
			left = append(left, nums[i])
		} else {
			right = append(right, nums[i])
		}
	}
	left = quick_sort(left)
	right = quick_sort(right)
	return append(append(left, pivot), right...)
}

//双路快排(原地)
func quickSort(nums *[]int, left int, right int) {
	if left >= right {
		return
	}
	firstIndex := left
	lastIndex := right
	pivot := (*nums)[firstIndex]
	for {
		if left == right {
			break
		}
		for {
			if (*nums)[right] < pivot || left == right {
				break
			}
			right--
		}
		for {
			if (*nums)[left] > pivot || left == right {
				break
			}
			left++
		}
		if left < right {
			tmp := (*nums)[left]
			(*nums)[left] = (*nums)[right]
			(*nums)[right] = tmp
		}
	}
	if firstIndex != left {
		tmp := (*nums)[firstIndex]
		(*nums)[firstIndex] = (*nums)[left]
		(*nums)[left] = tmp
	}
	quickSort(nums, firstIndex, left-1)
	quickSort(nums, left+1, lastIndex)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值