go常见排序算法

本文介绍了几种经典的排序算法,包括冒泡排序、选择排序、插入排序、希尔排序、归并排序、堆排序和快速排序,详细阐述了它们的工作原理、时间复杂度和稳定性,并提供了相应的Go语言实现代码示例。此外,还探讨了如何使用快速排序求解TopK问题。
摘要由CSDN通过智能技术生成

简介

冒泡排序:两两比较相邻的数,如果反序则进行交换,知道没有反序为止,冒泡排序是一种稳定的排序算法。
选择排序:通过不断交换,每次遍历在n-i+1中选取数字最小的作为有序排列的第i个数,就是将每一趟最小的和第i进行交换。选择排序是一种稳定的排序算法。
插入排序:将一个数组分为有序和无须,将一个数插入到已经排好序的有序数组中,从而达到最终的排序。插入排序是一种稳定的排序算法。
希尔排序:希尔排序是在选择排序基础上改进的,希尔排序将一个数组分割成若干个子序列,然后对每个子序列进行插入排序,当每个子序列都基本有序时,最后在进行一次插入排序。主要将相聚某个增量的数组成一个子序列,这样就能保证在子序列内分别进行插入排序;希尔排序是不稳定的排序算法。
堆排序:每个节点的值大于或等于左右节点的称为大顶堆,每个节点值小于或等于左右节点的称为小顶堆。将待排序的数组构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点,然后将其与堆数组的末尾元素交换,此时末尾元素就是最大值,然后将剩余n-1个数重新构造成一个堆,如此反复。堆排序不是稳定的排序算法。
归并排序:将数组看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个长度为2或1的有序子序列,在两两归并,如此重复,直到长度为n的有序序列为止。归并排序是一种稳定的排序算法。
快速排序:通过一趟排序将带排序记录分割成独立的两部分,其中一部分的数比另一部分数小,则可分别对这两部分数继续排序。

复杂度

平均情况最好情况最坏情况辅助空间
冒泡排序O(n^2)O(n)O(n^2)O(1)
选择排序O(n^2)O(n)O(n^2)O(1)
插入排序O(n^2)O(n)O(n^2)O(1)
希尔排序O(nlogn)~O(n^2)O(n^1.3)O(n^2)O(1)
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)
快速排序O(nlogn)O(nlogn)O(n^2)O(logn)~O(n)

冒泡排序

func mp1(nums []int) {
	n := len(nums)
	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			if nums[j] < nums[i] {
				nums[i], nums[j] = nums[j], nums[i]
			}
		}
	}
	fmt.Println("冒泡1:", nums)
}

冒泡排序改进版

func mp2(nums []int) {
	n := len(nums)
	for i := 0; i < n; i++ {
		for j := n - 2; j >= 0; j-- {
			if nums[j] > nums[j+1] {
				nums[j], nums[j+1] = nums[j+1], nums[j]
			}
		}
	}
	fmt.Println("冒泡2:", nums)
}

选择排序

func xz(nums []int) {
	n := len(nums)
	for i := 0; i < n; i++ {
		min := i
		for j := i + 1; j < n; j++ {
			if nums[min] > nums[j] {
				min = j
			}
		}
		if min != i {
			nums[i], nums[min] = nums[min], nums[i]
		}
	}
	fmt.Println("选择:  ", nums)
}

插入排序

func cr(nums []int) {
	n := len(nums)
	for i := 1; i < n; i++ {
		tmp := nums[i]
		j := i - 1
		for ; j >= 0 && tmp < nums[j]; j-- {
			nums[j+1] = nums[j]
		}
		if j+1 != i {
			nums[j+1] = tmp
		}
	}
	fmt.Println("插入排序:", nums)
}

希尔排序

func xe(nums []int) {
	n := len(nums)
	incr := n
	for incr > 0 {
		incr = incr / 3
		for i := incr; i < n; i++ {
			tmp := nums[i]
			j := i - incr
			for ; j >= 0 && tmp < nums[j]; j -= incr {
				nums[j+incr] = nums[j]
			}
			if j+incr != i {
				nums[j+incr] = tmp
			}
		}
	}
	fmt.Println("希尔排序:", nums)
}

归并排序

func gb(nums []int) {
	msort(nums, 0, len(nums)-1)
	fmt.Println("归并:  ", nums)
}
func msort(nums []int, left, right int) {
	mid := 0
	tmp := make([]int, len(nums))
	if left < right {
		mid = (left + right) / 2
		msort(nums, left, mid)
		msort(nums, mid+1, right)
		merge(tmp, nums, left, mid, right)
	}
}
func merge(tmp, nums []int, left, mid, right int) {
	l := left
	r := mid + 1
	k := left
	for ; l <= mid && r <= right; k++ {
		if nums[l] < nums[r] {
			tmp[k] = nums[l]
			l++
		} else {
			tmp[k] = nums[r]
			r++
		}
	}
	for ; l <= mid; l++ {
		tmp[k] = nums[l]
		k++
	}
	for ; r < right; r++ {
		tmp[k] = nums[r]
		k++
	}
	for left < k {
		nums[left] = tmp[left]
		left++
	}
}

大顶堆

func swap(a, b *int) {
	*a, *b = *b, *a
}
func maxHeap(nums []int) {
	n := len(nums)
	for i := n; i > 1; i-- {
		createHeap(nums, i)
		swap(&nums[0], &nums[i-1])
	}
	fmt.Println("大顶堆排序2:", nums)
}
func createHeap(nums []int, n int) {
	for i := n/2 - 1; i >= 0; i-- {
		heapAdjust(nums, i, n)
	}
}
func heapAdjust(nums []int, m, n int) {
	max := m
	l := m*2 + 1
	r := m*2 + 2

	if l < n && nums[l] < nums[max] {
		max = l
	}
	if r < n && nums[r] < nums[max] {
		max = r
	}
	if m != max {
		swap(&nums[m], &nums[max])
		heapAdjust(nums, m, n)
	}
}

小顶堆

func swap(a, b *int) {
	*a, *b = *b, *a
}
func minHeap(nums []int) {
	n := len(nums)
	for i := n; i > 1; i-- {
		CreateHeap(nums, i)
		swap(&nums[0], &nums[i-1])
	}
	fmt.Println("小顶堆排序:", nums)
}
func CreateHeap(nums []int, n int) {
	for i := n/2 - 1; i >= 0; i-- {
		HeapAdjust(nums, i, n)
	}
}
func HeapAdjust(nums []int, m int, n int) {
	min := m
	l := m*2 + 1
	r := m*2 + 2
	if l < n && nums[l] > nums[min] {
		min = l
	}
	if r < n && nums[r] > nums[min] {
		min = r
	}
	if m != min {
		swap(&nums[m], &nums[min])
		HeapAdjust(nums, m, n)
	}
}

快速排序

func swap(a, b *int) {
	*a, *b = *b, *a
}
func quickSort(nums []int) {
	qsort(nums, 0, len(nums)-1)
	fmt.Println("快速排序:", nums)
}
func qsort(nums []int, left, right int) {
	if left < right {
		p := partition(nums, left, right)
		qsort(nums, left, p)
		qsort(nums, p+1, right)
	}
}
func partition(nums []int, left, right int) int {
	tmp := nums[left]
	for left < right {
		for left < right && nums[right] > tmp {
			right--
		}
		swap(&nums[left], &nums[right])
		for left < right && nums[left] < tmp {
			left++
		}
		swap(&nums[left], &nums[right])
	}
	return left
}

案例

求topk

func topK(nums []int, k int) {
	res := Qsort(nums, 0, len(nums)-1, k)
	fmt.Println(res, nums[:k])
}

func Qsort(nums []int, left, right, k int) int {
	// n := len(nums)
	for {
		indx := Partition(nums, left, right)
		if indx == k-1 {
			return nums[indx]
		} else if indx < k-1 {
			left = indx + 1
		} else {
			right = indx - 1
		}
	}
}
func Partition(nums []int, left, right int) int {
	tmp := nums[left]
	for left < right {
		for left < right && nums[right] <= tmp {
			right--
		}
		nums[left] = nums[right]
		for left < right && nums[left] >= tmp {
			left++
		}
		nums[right] = nums[left]
	}
	nums[left] = tmp
	return left
}

最大的k个数

func q1(nums []int, k int) {
	q2(nums, 0, len(nums)-1, k)
	fmt.Println(nums[:k])
}

func q2(nums []int, left, right, k int) {
	m := q3(nums, left, right)
	num := m - left + 1
	if k < num {
		q2(nums, left, m-1, k)
	} else if k > num {
		q2(nums, m+1, right, k-num)
	}
}
func q3(nums []int, left, right int) int {
	tmp := nums[right]
	i := left - 1
	for j := left; j < right; j++ {
		if nums[j] >= tmp { //改成<=就是求最小的k个数
			i++
			nums[i], nums[j] = nums[j], nums[i]
		}
	}
	nums[i+1], nums[right] = nums[right], nums[i+1]
	return i + 1
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值