排序算法总结

原文

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

稳定:排序不改变相等元素的相对位置关系;如a=b,a原本在b前面,排序后a任然在b后面。

不稳定:排序可能改变相等元素的相对位置关系;如a=b,a原本在b前面,排序后a可能在b后面。

内排序:所有排序都在内存中完成。

外排序:数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行。

n:数据规模。

k:“桶”个数。

In-place:占用常数内存,不占用额外内存。

Out-place:占用额外内存。

冒泡排序

在这里插入图片描述

算法描述:

比较相邻元素并交换。

每次都会将最大的元素放到正确的位置。

一共要进行n-1趟比较。

最好情况:o(n)

最坏情况: o ( n 2 ) o(n^2) o(n2)

平均情况: o ( n 2 ) o(n^2) o(n2)

func BubbleSort(input []int) []int {
	n := len(input)
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-1-i; j++ {
			if input[j] > input[j+1] {
				input[j], input[j+1] = input[j+1], input[j]
			}
		}
	}
	return input
}

选择排序

在这里插入图片描述

算法描述:

从当前元素开始,找到最小的元素与当前元素交换。

选择最小的与第一个元素交换,选择次小的与第二个元素交换…

一共需要比较n-1趟。

最稳定的排序算法之一,无论什么数据都是 o ( n 2 ) o(n^2) o(n2)的时间复杂度,数据规模越小越好。

最佳、最坏、平均都是: o ( n 2 ) o(n^2) o(n2)

func SelectSort(input []int) []int {
    n, min := len(input), 0
    for i := 0; i < n; i++ {
        min = i
        for j := i+1; j < n; j++ {
            if input[j] < input[min] {
                min = j
            }
        }
        input[i], input[min] = input[min], input[i]
    }
    return input
}

冒泡排序和选择排序都是在做交换。

插入排序

在这里插入图片描述

算法描述:

以当前元素为基准,向前扫描,比当前元素大的都向后移动一位,遇到比当前元素小的就把它放到这个元素后面。

也就是当前元素之前都是有序的,然后将当前元素插入到有序集合的适当位置。

需要比较n-1趟。

需要o(1)的额外空间。

最好情况:o(n)

最坏情况: o ( n 2 ) o(n^2) o(n2)

平均情况: o ( n 2 ) o(n^2) o(n2)

func InsertSort(input []int) []int {
    n, cur, index := len(input), 0, 0
    for i := 1; i < n; i++ {
        cur, index = input[i], i - 1
        for index >= 0 && input[index] > cur {
            input[index+1] = input[index]
            index--
        }
        input[index+1] = cur
    }
    return input
}

插入排序是在做移动。

希尔排序(缩小增量排序)

在这里插入图片描述

算法描述:

首先选择一个间隔(gap)对数据进行分组,[i, i+gap, i+2×gap, i+3×gap…]为一组,共分为gap组;

分别对每一组进行选择排序;

缩小间隔gap,重复上述过程,直到gap = 1;

gap的取法,每次取gap = gap/2;或每次取gap = gap/3 + 1

希尔排序也是一种插入排序

func ShellSort(input []int) []int {
	n := len(input)
	for gap := n / 2; gap > 0; gap /= 2 {
		for i := gap; i < n; i++ {
			cur, j := input[i], i-gap
			for j >= 0 && input[j] > cur {
				input[j+gap] = input[j]
				j -= gap
			}
			input[j+gap] = cur
		}
	}
	return input
}

在这里插入图片描述

归并排序

在这里插入图片描述

算法描述:

将原数组拆成两个序列然后归并

递归的进行

需要额外的空间

func MergeSort(input []int) []int {
	n := len(input)
	if n < 2 {
		return input
	}
	mid := n / 2
	left, right := input[0:mid], input[mid:]
	return merge(MergeSort(left), MergeSort(right))
}

func merge(left, right []int) (output []int) {
	for i, j := 0, 0; i < len(left) || j < len(right); {
		if i >= len(left) {
			output = append(output, right[j])
			j++
		} else if j >= len(right) {
			output = append(output, left[i])
			i++
		} else if left[i] < right[j] {
			output = append(output, left[i])
			i++
		} else {
			output = append(output, right[j])
			j++
		}
	}
	return
}

快速排序

在这里插入图片描述

算法描述:

每次找一个基准数,将大于基准数的元素放到基准数右边,小于基准数的元素放到基准数左边,这一趟下来就相当于是把基准数放到它应该在的位置上。

具体来说,首先选择最左边的元素作为基准,然后j从最后一个元素开始向后找比基准小的数,i从第一个元素开始找比基准大的数,然后将它们交换,每次必须j先行动!

如果i、j相遇就将它与基准交换,这样基准就在正确的位置上了,然后以基准为界,左右两边分别同样处理。

func QuickSort(input []int, left, right int) []int {
	if left < right {
		index := left + 1
		for i := index; i <= right; i++ {
			if input[i] < input[left] {
				input[i], input[index] = input[index], input[i]
				index++
			}
		}
		input[left], input[index-1] = input[index-1], input[left]

		QuickSort(input, left, index-2)
		QuickSort(input, index, right)
	}
	return input
}

在这里插入图片描述

堆排序

在这里插入图片描述

算法描述:

用数组构建一个堆,然后依次删除堆顶元素组成有序数组。

func HeapSort(input []int) (output []int) {
	h := heap.NewMinHeap(input...)
	for !h.Empty() {
		if data, err := h.Get(); err == nil {
			output = append(output, data)
		}
	}
	return
}

计数排序

在这里插入图片描述

算法描述:

将每个元素作为下标映射到数组,数组中存的是下标对应数字出现的次数

适合大量重复且范围有限的数组

稳定排序算法,时间复杂度和空间复杂度都是o(n+k),速度快于任何比较排序算法

func CountSort(input []int) (output []int) {
	max := input[0]
	for i := range input {
		if input[i] > max {
			max = input[i]
		}
	}
	bucket := make([]int, max+1, max+1)
	for _, v := range input {
		bucket[v]++
	}
	for i := range bucket {
		for bucket[i] > 0 {
			output = append(output, i)
			bucket[i]--
		}
	}
	return
}

桶排序

在这里插入图片描述

算法描述:

定义一定数量的空桶,每个桶表示一个范围,gap=(max-min)/桶数+1

将数据装到对应范围的桶中,下标=(num-min)/gap

对非空桶内的数据排序

最好情况下为o(n)时间复杂度,主要取决于桶内数据排序的时间复杂度

桶划分的越小,桶内数据越少,时间越短,空间消耗越大

func BucketSort(input []int) (output []int) {
	min, max, size := input[0], input[0], len(input)/2
	for _, v := range input {
		if v < min {
			min = v
		}
		if v > max {
			max = v
		}
	}
	gap := (max-min)/size + 1
	bucket := make([][]int, size, size)
	for _, v := range input {
		index := (v - min) / gap
		bucket[index] = append(bucket[index], v)
	}
	for i := 0; i < size; i++ {
		if len(bucket[i]) > 0 {
			bucket[i] = InsertSort(bucket[i])
		}
	}
	for i := 0; i < size; i++ {
		output = append(output, bucket[i]...)
	}
	return
}

基数排序

在这里插入图片描述

算法描述:

先按个位大小排序,再按十位大小排序,依次直到最高位

相当于各个位的优先级是不同的,先按低优先级排序,再按高优先级排序,最后就是高优先级在低优先级之前,高优先级相同的,低优先级高的在前

以各个位为基准进行计数排序,直到最高位

func RadixSort(input []int) []int {
	max := input[0]
	for _, v := range input {
		if v > max {
			max = v
		}
	}
	bits := len(strconv.Itoa(max))
	bucket := make([][]int, 10, 10)
	for i, mod := 0, 1; i < bits; i, mod = i+1, mod*10 {
		for _, v := range input {
			index := v / mod % 10
			bucket[index] = append(bucket[index], v)
		}
		pos := 0
		for j := 0; j < 10; j++ {
			for len(bucket[j]) > 0 {
				input[pos] = bucket[j][0]
				bucket[j] = bucket[j][1:]
				pos++
			}
		}
	}
	return input
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值