选择排序(Selection Sort)
选择排序大致就是,每次循环找出最大值,然后与最后一个元素进行交换。然后再在除最后一个元素的数组里面,再找出最大值,与倒数第二个元素进行交换,以此类推。
执行流程:
1 从序列中找出最大的那个元素,然后与最末尾的元素交换位置。
执行完一轮后,最末尾的那个元素就是最大的元素
2 忽略1中曾经找到的最大元素,重复执行步骤1
不难写出代码:
public class test {
public static void main(String[] args) {
int[] array = {1, 3, 4, 19, 8 ,6};
for (int end = array.length - 1; end > 1; end--) {
int maxIndex = 0;
for (int begin = 1; begin <= end; begin++) {
//假如数组是:3 3 1
//如果是<号,array[0] = array[1],将第一个3放在了最后,显然不是稳定的。
//因此,此处需要是<=
if (array[maxIndex] <= array[begin]) {
maxIndex = begin;
}
}
//交换
int temp = array[maxIndex];
array[maxIndex] = array[end];
array[end] = temp;
}
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
}
虽然array[maxIndex] <= array[begin]一定程度上保证了选择排序的稳定性,但选择排序终究还是不稳定排序
例如:
10, 2a, 4, 2b
2b, 2a, 4, 10
不稳定了
因此,array[maxIndex] <= array[begin]写<=或者<都可以。
选择排序复杂度分析
选择排序的最好、最坏、平均时间复杂度为O(n2)
空间复杂度为O(1)
属于不稳定排序
与冒泡排序比较
选择排序与冒泡排序相比,比较次数要少很多。
冒泡排序需要每一次循环都要两两比较,如果前大后小,则交换。
选择排序只需要每一次循环找出最大值,最大值与最后值相交换即可。
如何优化?
从代码可以看出,选择排序每次都要选出最大元素。那么,我们是否可以使用大顶堆,因为对于大顶堆,最上面的元素就是最大值。而且,每次取最大值的平均时间复杂度为O(logn),比现在的选择最大值的时间复杂度O(n)要小。
这就是堆排序
堆排序(Heap Sort)
堆排序可以认为是对选择排序的一种优化
优化在于,每次取最大值的时候,是使用堆来取。
执行流程:
1 对序列进行原地建堆(heapify)
2 重复执行以下操作,直到堆的元素数量为1
- 交换堆顶元素与尾元素
- 堆的元素数量减1
- 堆0位置进行1次siftDown操作
堆排序的最好、最坏、平均时间复杂度为O(nlogn),空间复杂度为O(1),属于不稳的排序。
可以看出,堆排序的所用时间比冒泡少了很多,也优于选择排序。