一、简单选择排序。
1、介绍。
在简单选择排序过程中,所需移动记录的次数比较少。最好情况下,即待排序记录初始状态就已经是正序排列了,则不需要移动记录。最坏情况下,即待排序记录初始状态是按第一条记录最小,之后的记录从小到大顺序排列,则需要移动记录的次数最多为3(n-1)。简单选择排序过程中需要进行的比较次数与初始状态下待排序的记录序列的排列情况无关。当i=1时,需进行n-1次比较;当i=2时,需进行n-2次比较;依次类推,共需要进行的比较次数是(n-1)+(n-2)+…+2+1=n(n-1)/2,即进行比较操作的时间复杂度为O(n^2),进行移动操作的时间复杂度为O(n)。
简单选择排序是不稳定排序,不需要额外内存,空间复杂度O(1)。时间复杂度,最佳情况:O(n^2) 最差情况:O(n^2) 平均情况:O(n^2)。
2、步骤。
(1)初始状态:无序区为R[1..n],有序区为空;
(2)第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
(3)n-1趟结束,数组有序化了。
3、代码。
public static void main(String[] args) {
System.out.println("------开始------");
//生成生成两份一模一样的随机数组,其中一组用系统自带的方法进行排序,到时候进行验证。
final int number = 100000;
int[] sortArray = new int[number];
int[] sortArrayCopy = new int[number];
for (int i = 0; i < sortArray.length; i++) {
sortArray[i] = (int) (Math.random() * number);
}
System.arraycopy(sortArray, 0, sortArrayCopy, 0, number);//数组复制
Arrays.sort(sortArrayCopy);
//开始排序
long startTime = System.currentTimeMillis();
selectSort(sortArray);//简单选择排序
System.out.println("花费时间:" + (System.currentTimeMillis() - startTime));
//跟系统排序之后数组进行比较,查看是否排序成功。
if (Arrays.equals(sortArray, sortArrayCopy)) {
System.out.println("排序成功");
} else {
System.out.println("排序失败");
}
System.out.println("------结束------");
}
//简单选择排序 最佳情况:T(n) = O(n2) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)
private static void selectSort(int[] array) {
for (int i = 0; i < array.length-1; i++) {//n-1轮 最后一个无序排序
int minIndex=i;
for (int j=i+1;j<array.length;j++){
if (array[j]<array[minIndex]){
minIndex=j;
}
}
//交换位置
if (i != minIndex) {//感谢用户:EthanZzzz... 的提醒,加上这个判断
int flag = array[minIndex];
array[minIndex] = array[i];
array[i] = flag;
}
}
}
4、结果。
二、堆排序
1、介绍。
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序排序是不稳定排序,不需要额外内存,空间复杂度O(1)。时间复杂度,最佳情况:O(nlogn) 最差情况:O(nlogn) 平均情况:O(nlogn)。
2、步骤。
(1)最大堆调整(Max Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点。
(2)创建最大堆(Build Max Heap):将堆中的所有数据重新排序。
(3)堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算。
3、代码。
public static void main(String[] args) {
System.out.println("------开始------");
//生成生成两份一模一样的随机数组,其中一组用系统自带的方法进行排序,到时候进行验证。
final int number = 15;//要满足条件:array.length==2^n-1
int[] sortArray = new int[number];
int[] sortArrayCopy = new int[number];
for (int i = 0; i < sortArray.length; i++) {
sortArray[i] = (int) (Math.random() * number);
}
System.arraycopy(sortArray, 0, sortArrayCopy, 0, number);//数组复制
Arrays.sort(sortArrayCopy);
//开始排序
long startTime = System.currentTimeMillis();
heapSort(sortArray);//堆排序
System.out.println("花费时间:" + (System.currentTimeMillis() - startTime));
//跟系统排序之后数组进行比较,查看是否排序成功。
if (Arrays.equals(sortArray, sortArrayCopy)) {
System.out.println("排序成功");
} else {
System.out.println("排序失败");
}
System.out.println("------结束------");
}
//堆排序,要满足条件:array.length==2^n-1
private static void heapSort(int[] array) {
System.out.println("初始状态:");
printHeap(array);
//第一次初始化最大堆
for (int i = array.length / 2 - 1; i >= 0; i--) {
heap(array, array.length, i);
}
System.out.println("第1次堆的调整:");
printHeap(array);
//循环将堆首位(最大值)与末位交换,然后在重新调整最大堆
int len = array.length;
while (len > 0) {
len--;
//将最后一个未排序的跟第一个进行交换
int flag = array[0];
array[0] = array[len];
array[len] = flag;
//
System.out.println(String.format("第%d次堆的调整:", array.length - len + 1));
printHeap(array);
heap(array, len, 0);
}
}
private static void heap(int[] array, int len, int i) {
int maxIndex = i, left = i * 2 + 1, right = i * 2 + 2;
//如果有左子树,且左子树大于父节点,则将最大指针指向左子树
if (left < len && array[left] > array[maxIndex]) {
maxIndex = left;
}
//如果有右子树,且右子树大于父节点或者大于左子树(左子树已经比父节点大的情况),则将最大指针指向右子树
if (right < len && array[right] > array[maxIndex]) {
maxIndex = right;
}
//如果父节点不是最大值
if (maxIndex != i) {
//交换array[maxIndex]和array[i],即将父节点与最大值交换
int flag = array[maxIndex];
array[maxIndex] = array[i];
array[i] = flag;
//递归调整与父节点交换的位置
heap(array, len, maxIndex);
}
}
4、结果(直接给打印的日志)。
------开始------
初始状态:
14
5 6
11 1 0 9
3 7 0 2 0 2 13 10
第1次堆的调整:
14
11 13
7 2 2 10
3 5 0 1 0 0 9 6
第2次堆的调整:
6
11 13
7 2 2 10
3 5 0 1 0 0 9 14
第3次堆的调整:
6
11 10
7 2 2 9
3 5 0 1 0 0 13 14
第4次堆的调整:
0
7 10
6 2 2 9
3 5 0 1 0 11 13 14
第5次堆的调整:
0
7 9
6 2 2 0
3 5 0 1 10 11 13 14
第6次堆的调整:
1
7 2
6 2 0 0
3 5 0 9 10 11 13 14
第7次堆的调整:
0
6 2
5 2 0 0
3 1 7 9 10 11 13 14
第8次堆的调整:
1
5 2
3 2 0 0
0 6 7 9 10 11 13 14
第9次堆的调整:
0
3 2
1 2 0 0
5 6 7 9 10 11 13 14
第10次堆的调整:
0
2 2
1 0 0 3
5 6 7 9 10 11 13 14
第11次堆的调整:
0
1 2
0 0 2 3
5 6 7 9 10 11 13 14
第12次堆的调整:
0
1 0
0 2 2 3
5 6 7 9 10 11 13 14
第13次堆的调整:
0
0 0
1 2 2 3
5 6 7 9 10 11 13 14
第14次堆的调整:
0
0 0
1 2 2 3
5 6 7 9 10 11 13 14
第15次堆的调整:
0
0 0
1 2 2 3
5 6 7 9 10 11 13 14
第16次堆的调整:
0
0 0
1 2 2 3
5 6 7 9 10 11 13 14
花费时间:188
排序成功
------结束------
5、结果。将main方法中的number改成131071,即2^17-1。并将多余的打印日志注释掉,因为打印太多日志会影响测试的结果。