(2)Go实现递归排序及改进

递归排序的思想是分治法,即将问题划分为若干相互独立的个小问题,这些问题和该问题具有相同的特征,将这些小问题解决后,该问题也解决了。
按照这种思想,递归排序分为自上而下,自下而上2种
如下图示:
自上而下
自下而上

递归排序的实现
// 递归排序: 自上向下
func MergerSort1(arr []int) (resp []int) {
	l1 := len(arr)
	if l1 < 2 {
		return arr
	}
	mid := l1 / 2
	return Merger(MergerSort1(arr[:mid]), MergerSort1(arr[mid:]))
}

// 递归排序和插入排序相结合的排序
func MergerSort2(arr []int) (resp []int) {
	l1 := len(arr)

	if l1 < 100 {
		return InsertionSort(arr, l1)
	}

	mid := l1 / 2
	return Merger(MergerSort2(arr[:mid]), MergerSort2(arr[mid:]))
}

// 递归排序:自下向上
func MergerSortBU(arr []int) []int {
	l1 := len(arr)

	if l1 < 100 {
		return InsertionSort(arr, l1)
	}

	for sz := 1; sz < l1; sz += sz {
		for i := 0; i < l1-sz; i += sz + sz {
			copy(arr[i:min(i+sz+sz, l1)], Merger(
				arr[i:i+sz],
				arr[i+sz:min(i+sz+sz, l1)]))
		}
	}
	return arr
}

func Merger(arr1, arr2 []int) (resp []int) {
	l1 := len(arr1)
	l2 := len(arr2)

	i, j := 0, 0
	for i < l1 || j < l2 {
		switch {
		case j == l2:
			resp = append(resp, arr1[i])
			i++
		case i == l1:
			resp = append(resp, arr2[j])
			j++
			// 能到这里说明i<l1,j<l2
		case arr1[i] <= arr2[j]:
			resp = append(resp, arr1[i])
			i++
		default: // arr2[i] > arr2[j]
			resp = append(resp, arr2[j])
			j++
		}
	}
	return resp
}

// 插入排序
func InsertionSort(s []int, l int) []int {
	for i := 1; i < l; i++ {
		buf := s[i]
		var j int
		for j = i; j > 0 && s[j-1] > buf; j-- {
			s[j] = s[j-1]
		}
		s[j] = buf
	}
	return s
}

func min(i1, i2 int) int {
	if i1 > i2 {
		return i2
	}
	return i1
}
测试
const count = 1000

func main() {
	nums2 := [count]int{}
	for i := 0; i < count; i++ {
		nums2[i] = rand.Intn(count)
	}

	for i := 0; i < 4; i++ {
		nums3 := nums2
		nums := nums3[:]
		t := time.Now()
		switch i {
		case 0:
			nums = merger.InsertionSort(nums, count)
			fmt.Println("插入排序花费时间:", t.Sub(time.Now()))
			isTrue(nums)
		case 1:
			nums = merger.MergerSort1(nums)
			fmt.Println("递归排序花费时间:", t.Sub(time.Now()))
			isTrue(nums)
		case 2:
			nums = merger.MergerSort2(nums)
			fmt.Println("递归插入结合自上而下花费时间:", t.Sub(time.Now()))
			isTrue(nums)
		case 3:
			nums = merger.MergerSortBU(nums)
			fmt.Println("递归结合插入自下向上花费时间:", t.Sub(time.Now()))
			isTrue(nums)
		}
		fmt.Println("----")
	}
}

func isTrue(nums []int) {
	b := true
	for i := 1; i < count; i++ {
		if nums[i-1] > nums[i] {
			fmt.Println("排序错误", nums[i-1], nums[i])
			b = false
			break
		}
	}
	if b {
		fmt.Println("排序正确")
	}
}
// 分别令count=100,1000,10000
1)count=100
插入排序花费时间: -3.818µs
排序正确
----
递归排序花费时间: -46.523µs
排序正确
----
递归插入结合自上而下花费时间: -4.383µs
排序正确
----
递归结合插入自下向上花费时间: -29.861µs
排序正确

2)count=1000
插入排序花费时间: -221.893µs
排序正确
----
递归排序花费时间: -409.8µs
排序正确
----
递归插入结合自上而下花费时间: -110.996µs
排序正确
----
递归结合插入自下向上花费时间: -403.085µs

3)count=10000
插入排序花费时间: -22.420067ms
排序正确
----
递归排序花费时间: -8.385759ms
排序正确
----
递归插入结合自上而下花费时间: -6.942241ms
排序正确
----
递归结合插入自下向上花费时间: -6.024227ms
排序正确

结论:在数据量较小时,插入排序速度较快,在数据量大时候,递归排序较快,因此两者可以结合起来,
在数据量较大时,用递归排序,在数据量较小时,用插入排序,两者结合速度比单一的递归排序更快些,
而递归排序自上而下和自下而上两种速度差不多。
时间复杂度分析 //
插入排序为O(n^2),递归排序时间复杂度为nlogn

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值