选择排序的基本方法:
每次都从待排序对象中选出排序码最大或最小的对象,依次排列,一共进行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. 稳定性:不稳定