golang归并排序+冒泡排序 Day2

文章介绍了如何在Golang中实现归并排序的迭代和递归版本,以及冒泡排序的优化方法。归并排序的时间复杂度为O(nlogn),而冒泡排序在最佳情况下可达到O(n)。文章提供了完整的源码示例,并讨论了两种排序算法的时间复杂度。
摘要由CSDN通过智能技术生成


源码仓库

github仓库
https://github.com/jackzcai/golang-interview

归并排序

概述

归并排序也是一种基于分治法的排序算法。为了排序长度为n的数组,就先排序两个长度为n/2的子数组,然后合并这两个排序的子数组。

迭代

核心思想在于迭代的时候第一层循环定义seg的长度,每次循环seg乘二。内层循环定义排序的起始位置和终止位置,显然和seg的长度有关。排序的方式是设置两个指针放在src数组的start位置和mid位置,将两个指针中较小的数填入dst数组中对应的位置,然后对应指针右移,迭代执行直到两个指针都到达mid或者end的位置。注意每次迭代的时候dst数组的指针都要右移。最后要交换src和dst数组的位置,因为此时从以dst数组的内容开始排序。

// 迭代实现归并排序
func mergeSortIteration(nums []int) {
	lenth := len(nums)
	src := nums //src源数组 dst目标数组 操作后要交换两个数组
	dst := make([]int, lenth)
	for seg := 1; seg < lenth; seg = seg << 1 {
		for start := 0; start < lenth; start += seg * 2 {
			mid := min(start+seg, lenth)
			end := min(start+seg*2, lenth)
			i, j, k := start, mid, start //注意start,end左闭右开
			for i < mid || j < end {
				if j == end || (i < mid && (src[i] < src[j])) {
					dst[k] = src[i]
					i++
				} else {
					dst[k] = src[j]
					j++
				}
				k++
			}
		}
		src, dst = dst, src
	}
	nums = src
}

递归

核心思想在于先排序两个长度为n/2的数组,然后合并这两个数组。注意先定义dst数组为src数组的copy,递归目的在于将src数组的start到end之间的数字排序好放到dst数组的start到end之间,所以内部递归的时候dst和src的位置还是要调换,最后是从dst数组中取得结果。

// 递归实现归并排序
func mergeSortRecursion(src, dst []int, start, end int) { //注意start,end左闭右开
	if start+1 >= end {
		return
	}
	mid := (start + end) / 2
	mergeSortRecursion(dst, src, start, mid) //注意交换src,dst    这一步的目的是为了将src的start, mid变成顺序的,所以要交换dist和mid
	mergeSortRecursion(dst, src, mid, end)
	i, j, k := start, mid, start
	for i < mid || j < end {
		if j == end || (i < mid && (src[i] < src[j])) {
			dst[k] = src[i]
			i++
		} else {
			dst[k] = src[j]
			j++
		}
		k++
	}
}

时间复杂度

由于长度为n的数组每次都被分为一半,所以不管输入什么样的数组,归并排序的时间复杂度都是Onlogn。归并排序需要创建一个长度为n的辅助数组,如果用递归实现,递归的调用栈需要Ologn的空间。因此归并排序的时间复杂度是On。
同时,这种分治的思想可以用来解决很多其他问题。比如合并排序链表,也是用到了merge的思想。

冒泡排序

概述

冒泡排序是一种简单的排序算法,它也是一种稳定排序算法。其实现原理是重复扫描待排序序列,并比较每一对相邻的元素,当该对元素顺序不正确时进行交换。一直重复这个过程,直到没有任何两个相邻元素可以交换,就表明完成了排序。

优化

在循环的过程中可能已经完成排序,后续就可能发生很多无意义的比较和交换。
所以第一次优化:设置标记位,某次内循环完成后没有发生任何交换可以直接return
第二次优化:设置每趟内循环最后比较的位置,下一趟内循环只需要循环到这个位置即可

func newBubbleSort(nums []int) {
	lenth := len(nums) - 1
	tempPosition := 0 //优化内循环次数,只需要循环到最后一次交换的位置即可
	for i := 0; i < len(nums)-1; i++ {
		flag := 1 //优化标记位  如果某次内循环没有发生比较,说明已经排序完毕,可以直接退出。
		for j := 0; j < lenth; j++ {
			if nums[j] > nums[j+1] {
				nums[j], nums[j+1] = nums[j+1], nums[j]
				flag = 0
				tempPosition = j
			}
		}
		if flag == 1 {
			return
		}
		lenth = tempPosition
	}
}

在优化过后,时间复杂度由On2到最优情况下可以达到On。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值