插入排序和希尔排序 Day3


源码

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

插入排序

对于插入排序来说,(升序为例)其原理就是找出小的值从后面移动到前面。
这个前移是通过保存x的值,end指针的值后移,然后将end指针前移,最后将end指针下一个位置的值再改成x实现的

复杂度

首先我们知道,如果有一串降序的数组,我们升序排序的话,也就是最坏的情况。此时每一趟排序都需要 end 都需要移动到小于 0 的位置。此时可以求出时间复杂度为 O(N^2)。
而因为直接插入排序只开辟了可计算的几个变量的空间,所以空间复杂度是O(1)。

稳定性

因为直接插入只是将每个可能需要移动的元素,只往前或者往后移动,没有乱移动,也没有往前移动一次,下次又往后移动一次。所以说是稳定的。

优化

如果当前数组是一组比较有序的数组,那么此时直接插入排序是很高效的,因为移动不是很大。所以接下来的希尔排序就是做了这样一个优化操作。引入希尔排序。

希尔排序

希尔排序是在直接插入排序的基础上改进的,因为直接插入排序的时间复杂度确实太高了。所以希尔排序是提出了一种改进方法,减少每一次排序的次数,将时间复杂度改进到O(N)。

概述

因为是对直接插入排序的优化,所以首先我们需要将其进行预排序,预排序之后,当前的序列是相对比较有序的,我们再进行直接插入,这样就达到了简化时间复杂度的操作。同时也就达到了对于比较有序的序列的排序。

代码

package main

import "fmt"

func main() {
	nums := []int{1234, 34345, 345, 241, 756, 77, 4, 5234, 346, 35, 25, 3, 58, 33, 423, 41, 3567, 35, 26, 1, 6, 2, 3, 5, 67, 8, 4, 8, 9, 4356}
	shellSort(nums)
	fmt.Printf("%v\n", nums)
}

func shellSort(nums []int) {
	gap := len(nums)
	for gap > 1 {
		gap = gap/3 + 1
		for i := 0; i < len(nums)-gap; i++ {
			end := i
			x := nums[end+gap]
			for end >= 0 {
				if nums[end] > x {
					nums[end+gap] = nums[end]
					end -= gap
				} else {
					break
				}
			}
			nums[end+gap] = x
		}
	}
}

复杂度

对于希尔排序来说,最主要的就是将整组数进行了分组预排序,这样使得我们当前数组变成了一个比较有序的数组,而且在这个过程中时间复杂度是远小于 O(N^2) 的。

而对于一个比较有序的数组来说,直接插入排序的效率是很高的,因为不需要移动很多次。这里我们求得希尔排序最后的时间复杂度约为 O(N^1.3),因为是一个范围值,所以我们取中间值。

稳定性

我们知道,分组预排序的时候,因为每一组之间的间距是比较大的,所以在移动时,每个元素的相对位置移动是比较灵活的。这也就导致了希尔排序的稳定性是比较差的。所以希尔排序是不稳定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值