一,前言
排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减地排列起来的操作。而对于一个排序算法 而言,我们通常会从以下三个方面分析其性能:
- 稳定性:假设待排序序列中存在多个重复值,若是经过排序后,重复值之间的相对位置不变,则称这个排序算法是稳定的,否则就是不稳定。
- 时间复杂度:代码执行次数随n的增长趋势,通常使用大O的渐进法表示
- 空间复杂度:额外存储随n的增长趋势,其中递归算法空间=递归栈的最大深度,通常使用大O渐进表示法
常见的基于比较的排序算法有七种,对于这七种排序算法,又因其实现方式不同划分为以下四类 :
- 插入排序:直接插入排序、希尔排序
- 选择排序:选择排序、堆排序
- 交换排序:冒泡排序、快速排序
- 归并排序:归并排序
本节内容主要讲解选择排序,并且都是以排升序为例进行讲解。
二,选择排序
1,算法思想
每一趟从待排序序列中选出最小(或最大)的元素,放到已排序序列的末尾(或开头),直到全部元素排完。
2,算法特性
该排序的比较次数与初始序列无关,且交换次数少,在元素移动成本高时更有优势。
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:不稳定
交换操作可能把相等元素的相对次序打乱。
3,排序过程演示

4,算法实现
java
/**
* 选择排序
* @param array 待排序序列
*/
public static void selectionSort(int[] array) {
if(array == null) return;
int n = array.length;
for(int i = 0; i < n - 1; i ++) {
// 在待排序序列中找到最小值下标
int minIndex = i;
for(int j = i + 1; j < n; j ++) {
if(array[j] < array[minIndex]) {
minIndex = j;
}
}
// 将最小值交换至有序位置
if(minIndex != i) {
swap(array, i, minIndex);
}
}
}
/**
* 交换数组中两个下标的元素
* @param array 待操作序列
* @param i 下标1
* @param j 下标2
*/
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
三,堆排序
1,算法思想
利用堆这种完全二叉树结构进行排序,排升序建大根堆,排降序建立小根堆。以排升序为例,由于大根堆堆顶元素为整个数组最大值,则有:
1,将数组调整为大根堆
2,将堆顶元素与当前堆的最后一个元素交换,此时堆顶元素位于待排序序列尾部,有序
3,缩小堆的范围,对新的堆顶执行向下调整,使其重新恢复为大根堆
4,重复2,3操作,直到堆中只剩一个元素
2,算法特性
时间复杂度稳定,不受初始序列有序程度明显影响,适合数据量较大的场景,但实际性能通常不如快排。
时间复杂度:O(N * log N),底数为2
空间复杂度:O(1)
稳定性:不稳定
交换堆顶和末尾元素可能改变相同值元素的相对次序
3,排序过程演示
建堆略,之前的博客有,此处直接从排序开始演示。

4,算法实现
java
/**
* 堆排序
* @param array 待排序序列
*/
public static void heapSort(int[] array) {
if(array == null) return;
int n = array.length;
// 向下调整建堆(排升序,建大根堆)
for(int parent = (n - 1 - 1) / 2; parent >= 0; parent --) {
siftDown(array, parent, n);
}
// 堆排序
for(int end = n - 1; end > 0; end --) {
// -交换首尾节点,尾节点有序
swap(array, 0, end);
// -向下调整(传递end,则有序的尾节点不在本次调整范围内)
siftDown(array, 0, end);
}
}
/**
* 向下调整-大根堆
* @param array 待操作序列
* @param parent 父节点下标
* @param len 有效长度,调整范围为 [0, len)
*/
private static void siftDown(int[] array, int parent, int len) {
int child = parent * 2 + 1;
while(child < len) {
// child指向值最大的子节点
if(child + 1 < len && array[child + 1] > array[child]) {
child ++;
}
// 不符合大根堆则交换并继续向下调整,若是符合则无需调整退出循环
if(array[child] > array[parent]) {
swap(array, child, parent);
parent = child;
child = parent * 2 + 1;
} else {
break;
}
}
}
/**
* 交换数组中两个下标的元素
* @param array 待操作序列
* @param i 下标1
* @param j 下标2
*/
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}