1. 选择排序
选择排序的思想如下:
在元素集合array[i]~array[n-1]中选择关键码最大(小)的数据元素;
若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换;
在剩余的array[i]~array[n-2]集合中,重复上述步骤,直到集合剩余1个元素。
注:这里所讲的排序是以升序为例的。
图示如下:
很明显,这种做法是可以优化的,可以同时找到最大和最小的数,把它们放在数组的两侧。
代码如下:
/**
* 选择排序
*
* 时间复杂度:O(N^2) 空间复杂度:O(1) 不稳定
*/
public class SelectSort {
public void selectSort(int[] arr){
//选择排序,每次排最大的和最小的
int minSpace = 0;
int maxSpace = arr.length-1;
while(minSpace < maxSpace){
//最大值和最小值的下标
int minPos = minSpace;
int maxPos = minSpace;
for (int i = minSpace+1; i <= maxSpace; i++){
if(arr[i] < arr[minPos])
minPos = i;
if (arr[i] > arr[maxPos])
maxPos = i;
}
//将找到的最大值和最小值与maxSpace和minSpace交换
int tmp1 = arr[minPos];
arr[minPos] = arr[minSpace];
arr[minSpace] = tmp1;
//最大值在第一个数为特殊情况,最小值交换时将最大的数移动了位置
if (minSpace == maxPos)
maxPos = minPos;
int tmp2 = arr[maxPos];
arr[maxPos] = arr[maxSpace];
arr[maxSpace] = tmp2;
minSpace++;
maxSpace--;
}
}
}
可以根据代码看出来,它的时间复杂度是O(N^2),因为没有使用额外的空间,所以空间复杂度为O(1)。它是一种不稳定的排序算法。
2. 堆排序
堆排序的思想如下:
创建堆:
把堆顶array[0]元素和当前堆的最后一个元素交换;
堆元素的个数减1;
由于第一步后根节点不再满足堆定义,向下调整根节点;
执行上述步骤,直到数组为空。
排序:
建好堆后,将堆顶元素放在结果数组的最后一个位置上。
堆一直在重建,插入数组的位置也在一直向前移动。
注:升序建大堆,降序建小堆。
关于堆的相关问题,在这里就不做过多的阐述了,直接看代码:
/**
* 堆排序
*
* 时间复杂度:O(N*lgN) 空间复杂度:O(1) 不稳定
*/
public class HeapSort {
public void heapSort(int[] arr){
//1.建堆
//找到最后一个非叶子节点
int size = arr.length;
int root = (size-2)/2;
//开始向上建堆
for (; root >= 0; root--){
HeapAdjust(arr,size,root);
}
//2.堆排序
//每次将堆顶元素和堆后面的元素进行交换,然后继续建堆
int end = size - 1;
while (end > 0){
int tmp = arr[end];
arr[end] = arr[0];
arr[0] = tmp;
HeapAdjust(arr,end,0);
end--;
}
}
private void HeapAdjust(int[]arr, int size, int parent){
int child = parent*2+1;
while (child < size){
//查看是否有右孩子并且右孩子是否大于左孩子
if ((child+1) < size && arr[child+1] > arr[child])
child = child+1;
if (arr[child] > arr[parent]){
int tmp = arr[child];
arr[child] = arr[parent];
arr[parent] = tmp;
}
//继续向下建堆
parent = child;
child = parent*2+1;
}
}
}
根据代码可以看出来,堆排序的时间复杂度为O(N*logN),空间复杂度为O(1)。它是一种不稳定的排序算法。