常见内排序-go版本实现

1 选择排序

表现最稳定的排序算法之一 ,因为无论什么数据进去都是O(n2)的时间复杂度,O(1)的空间复杂度 ,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间,不稳定

举个例子:对于2 9 5 4 8 1 6

step1:在列表中先选择最大元9并与最后一个数字6交换 2 6 5 4 8 1 9;

step2:在剩余列表选择最大元8并与最后一个数字1交换 2 6 5 4 1 8 9;

step3:在剩下列表选择最大元6并与最后一个数字1交换 2 1 5 4 6 8 9;

step4:在剩下列表选择最大元5并与最后一个数字4交换 2 1 4 5 6 8 9;

step5:剩下列表最大元4已经在合适位置不用交换;

step6:在剩下列表选择最大元2并与最后一个数字1交换 1 2 4 5 6 8 9;

最后只剩一个数字,无需再排序,排序完成。

算法时间复杂度分析:第一步迭代需要n-1次比较操作;第二步需要n-2个比较。。。c表示其他常见操作(赋值,每次迭代的比较)

T(n)=n-1+n-2+...+1+c*(n-1)=n^2/2-n/2+c*(n-1)=O(n^2)

func selectionSort(arr []int) {
	for i := 0; i < len(arr)-1; i++ {
		//最后一个元素无需排序故len-1
		maxV := arr[0]
		maxVIdx := 0
		for j := 0; j < len(arr)-i; j++ {
			if maxV < arr[j] {
				maxV = arr[j]
				maxVIdx = j
			}
		}
		arr[maxVIdx], arr[len(arr)-1-i] = arr[len(arr)-1-i], arr[maxVIdx]
	}
}

2 冒泡排序

分len-1轮比较,每一轮两两比较,将最值沉淀。最佳时间复杂度O(N)最差O(N2),空间复杂度O(1),稳定性排序。

例子:2 9 5 4 8 1 6

step1:将2 9交换,因为已经是升序不用再动;将9 5交换成5 9;将9 4 交换成4 9;将9 8交换成8 9;将9 1交换成1 9;将9 6交换成6 9;----最大元素沉底2 5 4 8 1 6 9;

step2: 类似的将8沉底得到2 4 5 1 6 8 9;

step3:类似的将6沉底得到2 4 5 1 6 8 9;

step4:类似的将5沉底得到2 4 1 5 6 8 9;

step5:类似的将4沉底得到2 1 4 5 6 8 9;

step6:类似的将2沉底得到1 2 4 5 6 8 9;

最后完成

算法分析:

在最好情况时第一步就发现已经有序,则无需再操作,比较此时n-1,O(n);

最坏情况:总共n-1次扫描;第k次扫描需要比较n-k次比较

T(n)=1+2+...(n-1)+C*(n-1)=O(n^2);

func bubbleSort(arr []int) {
	for loop := 0; loop < len(arr)-1; loop++ {
		//重复len-1次
		for j := 0; j < len(arr)-1-loop; j++ {
			if arr[j] > arr[j+1] {
				arr[j], arr[j+1] = arr[j+1], arr[j]
			}
		}
	}
}

3 插入排序

以原始数组第一个元素为有序序列的首个元素,原始数组后面的元素都与有序序列比较,利用有序性找到该元素在有序序列中的位置然后插入,也即当插入第i(i>1)个元素时,前面的data[0],data[1]……data[i-1]已经排好序。这时用data[i]的排序码与data[i-1],data[i-2],……的排序码顺序进行比较,找到插入位置即将data[i]插入,原来位置上的元素向后顺序移动。最佳时间复杂度O(N)最差O(N2),空间复杂度O(1),稳定性排序。

还是例子2 9 5 4 8 1 6

step1:初始时,已排序列表只含列表第一个元素。将9插入:2 9;

step2:已经排序的2,9,将接下来的5插入列表:2 5 9;

step3:已经排序的2 5 9 ,将接下来的4插入列表:2 4 5 9;

step4:已经排序的2 4 5 6,将接下来的8插入列表:2 4 5 8 9;

step5:已经排序的2 4 5 8 9,将接下来的1 插入列表:1 2 4 5  8 9;

step6:已经排序的1 2 4 5 8 9,接下来的6插入列表:1 2 4 5 6 8 9.

step:整个排序完成。

算法性能:第k个迭代,需要将元素插入一个规模k的有序数组,需要k次比较k次数据移动,C是其他操作

T(n)=2*(1+2+...+n-1)+c*(n-2)=O(n^2)

func insertSort(arr []int) {
	for i := 1; i < len(arr); i++ {
		//已排序列表已经含列表第一个元素故从1开始处理
		cur := arr[i]
		j := i - 1
		for j >= 0 && arr[j] > cur {
			arr[j+1] = arr[j]
			j--
		}
		arr[j+1] = cur
	}
}

4 希尔排序

该方法是插入的改进,基本思想是:设待排序元素序列有n个元素,首先取一个整数increment(小于n)作为间隔将全部元素分为increment个子序列,所有距离为increment的元素放在同一个子序列中,在每一个子序列中分别实行直接插入排序。然后缩小间隔increment,重复上述子序列划分和排序工作。直到最后取increment=1,将所有元素放在同一个子序列中排序为止。由于开始时,increment的取值较大,每个子序列中的元素较少,排序速度较快,到排序后期increment取值逐渐变小,子序列中元素个数逐渐增多,但由于前面工作的基础,大多数元素已经基本有序,所以排序速度仍然很快。最佳时间复杂度O(NlogN)最差O(NlogN2),空间复杂度O(1),不稳定性排序。

如数组[1,0,2,10,9,70,5,6,3],

我们先选择增量 length/2,如上9/2=4,分为4组,分别是【1,9】,【0,70】,【2,5】,【10,6】加上剩下的一组【3】

然后给每个数组进行排序,得到[1,0,2,6,9,70,5,10,3]

然后再选择增量length/2/2,如上9/2/2=2,分为2组,分别是【1,0,2,6】,【9,70,5,10】,加上剩下的一组【3】

然后给每个数组进行排序,得到[0,1,2,6,5,9,10,70,3]

然后再选择增量length/2/2/2,如上9/2/2/2=1,分为1组,为[0,1,2,6,5,9,10,70,3]

然后排序,得到[0 1 2 3 5 6 9 10 70]

func shellSort(arr []int) {
	for deltaDis := len(arr) / 2; deltaDis > 0; deltaDis /= 2 {
		//min is 1
		for i := deltaDis; i < len(arr); i++ {
			cur := arr[i]
			j := i - deltaDis
			for j >= 0 && arr[j] > cur {
				arr[j+deltaDis] = arr[j]
				j -= deltaDis
			}
			arr[j+deltaDis] = cur
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值