基本概念:
选择排序是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
一、直接选择排序
1.1 直接选择排序过程
- 在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素;
- 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
- 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素
1.2 直接选择排序代码实现
元素交换位置
public static void swap(int[] array,int i,int j){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
实现方案一:
public static void selectSort(int[] array){
for (int i = 0; i <array.length ; i++) {
int minIndex = i;
//找到i下标后面的最小值,和i下标的值进行交换
for (int j = i+1; j <array.length ; j++) {
if (array[j] < array[minIndex]){
minIndex = j;
}
}
swap(array,i,minIndex);
}
}
实现方案二:
public static void selectSort2(int[] array){
int left = 0;
int right = array.length-1;
while(left < right){
int minIndex = left;
int maxIndex = left;
for (int i = left+1 ; i <= right ; i++) {
if (array[minIndex]> array[i]){
minIndex = i;
}if (array[maxIndex] < array[i]){
maxIndex = i;
}
}
swap(array,minIndex,left);
//如果第一个值是最大值,那么它的位置将会与原来最小值的位置交换,最大值就会跑到原来最小值的位置,排序就会出现错误
if (maxIndex == left){
maxIndex = minIndex;
}
swap(array,maxIndex,right);
left++;
right--;
}
}
1.3 直接选择排序复杂性分析:
1.平均时间复杂度: O(N^2);最好时间复杂度: O(N^2);最坏时间复杂度: O(N^2);
2. 空间复杂度:O(1);
3. 稳定性 :不稳定。
二、堆排序
2.1 概念
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
排序过程
- 将初始待排序关键字序列(R1,R2…Rn)构建成大顶堆,此堆为初始的无序区;(大顶堆特点:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2])
- 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,…Rn-1)和新的有序区(Rn);
- 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,…Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2…Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
给定一个列表array=[16,7,4,20,17,5],对其进行堆排序。
2.2 堆排序相关代码
1、创建堆
/**
* 创建堆
* @param array
*/
public static void creatHeap(int[] array){
for (int parent = (array.length -1-1)/2; parent >= 0 ; parent--) {
siftDown(array,parent,array.length);
}
}
向下调整(向下调整)
private static void siftDown(int[] array, int parent, int length) {
int child = 2*parent+1;
while (child < length){
if (child+1<length && array[child] < array[child+1]){
child++;
}
if (array[child] > array[parent]){
swap(array,child,parent);
parent = child;
child = 2*parent+1;
}else {
break;
}
}
}
//向上调整建立小根堆,时间复杂度O(N+NlogN)
public void siftUp(int child){
int parent = (child-1)/2;
while (child >0){
if (elem[child] >elem[parent]){
swap(child,parent);
child = parent;
parent = (child-1)/2;
}else {
break;
}
}
}
3、堆排序
public static void heapSort(int[] array){
creatHeap(array);
int end = array.length-1;
while(end > 0 ){
swap(array,0,end);
siftDown(array,0,end);
end--;
}
}
2.3 堆排序复杂度分析
- 平均时间复杂度:O(NlogN);最好时间复杂度:O(NlogN);最坏时间复杂度:O(N*logN)
- 空间复杂度:O(1)
- 稳定性:不稳定
总结
以上就是今天要讲的选择选择的相关内容:其中,直接选择排序是表现最稳定的排序算法之一,因为无论什么数据进去都是O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间。而堆排序不同于其他排序算法,它利用了完全二叉树的性质进行排序。