选择排序(直接选择排序、堆排序)

选择排序的基本方法:
每次都从待排序对象中选出排序码最大或最小的对象,依次排列,一共进行n-1次即可将n个对象排序完成。
选择排序的实施方案:
1. 直接选择排序
2. 堆排序

一、直接选择排序
1. 算法代码:

/**
* 直接选择排序
**/
func SelectSort(data []int) {
	for i := 0; i < len(data)-1; i++ {
		minIndex := i //保存最小值的索引
		for j := i + 1; j < len(data); j++ {
			if data[j] < data[minIndex] {
				minIndex = j
			}
		}
		if minIndex != i {
			data[minIndex], data[i] = data[i], data[minIndex]
		}
	}
}

2. 时间复杂度:O(n*n)
缺陷:每次都要从n-i+1个记录中选一个排序码最小的对象,从而需要进行n-i次比较,当n很大时,其效率很低。
3. 稳定性:不稳定

二、堆排序
关于堆的介绍与实现可以先查看我的另一篇博文:https://www.cnblogs.com/wujuntian/p/12286502.html
1. 算法描述:
使用最小堆或最大堆来选出待排序对象的最小或最大排序码对象。
2. 算法代码:
可以使用最小堆或者最大堆实现,其中使用最大堆算法的空间复杂度更优,因为只需在原来数组上对数据位置进行调整即可,而使用最小堆排序的话还需要使用一个额外的数组来存储排序结果。所以这里只给出使用最大堆的算法。

/**
* 堆排序(使用最大堆)
**/
func HeapSort(data []int) {
	count := len(data)                      //最大堆数据个数
	for i := (count - 2) / 2; i >= 0; i-- { //从拥有孩子节点的最后一个父节点开始,向下调整,初始化最大堆
		shiftDown(data, i, count-1)
	}
	for count > 1 {
		data[0], data[count-1] = data[count-1], data[0] //将堆顶元素与最后一个元素交换位置
		count--                                         //最大堆数据个数减少
		shiftDown(data, 0, count-1)                     //向下调整最大堆
	}
}

/**
* 向下调整最大堆
**/
func shiftDown(data []int, start, end int) {
	i, j := start, start*2+1 //j为i的左孩子
	temp := data[i]
	for j <= end {
		if j+1 <= end && data[j+1] > data[j] { //取左右孩子的最大值
			j++
		}
		if data[j] > temp { //孩子比父节点大,交换数值,继续向下调整
			data[i] = data[j]
			i, j = j, j*2+1
		} else {
			break
		}
	}
	data[i] = temp
}

3. 时间复杂度:O(nlogn)
直接选择排序进行了很多重复的比较,而堆则相当于保存了比较结果,避免太多重复比较,所以比较次数较少,但是由于建立初始堆所需的比较次数较多,所以堆排序对记录数较少的序列并不值得提倡,但对于数目较大的序列来说还是很有效的。
4. 空间复杂度:O(1)
5. 稳定性:不稳定

猜你喜欢

转载自www.cnblogs.com/wujuntian/p/12303192.html