目录
排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的cha任意序列,重新排列成一个关键字有序的序列。
选择排序
选择排序就是对于一个任意的序列,从第一个元素开始,寻找整个序列中最小的元素放在第一个,然后从第二个元素开始,选取从第二个元素开始,到最后一个元素其中的最小值放在第二个位置,依次类推,对于n个元素,执行n-1次后,最后一个元素已经是最大值,不需要继续选择,所以这个过程一共执行了n-1次。
public static void selectionSort(int[] arr) {
if (arr == null || arr.length < 2) {//对于数组为空或者只有一个元素的数组直接返回
return;
}
for (int i = 0; i < arr.length - 1; i++) {//外层循环为一共执行的次数,为n-1次
int minIndex = i;//先定义每次循环的第一个开始元素为最小值
for (int j = i + 1; j < arr.length; j++) {//在arr[i,n-1]中选择最小的元素
minIndex = arr[j] < arr[minIndex] ? j : minIndex;//更新最小元素的位置
}//其中那个三目运算符的含义为,如果?前面的表达式成立,结果就是后面冒号前面的值,否则就是冒号后面的值。
swap(arr, i, minIndex);//找到最小值以后,交换二者位置。
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}//交换
对于这个程序的时间复杂度进行分析,关注最深层循环的语句,两层循环,数量级达到,而对于空间复杂度,不需要额外的空间,即空间复杂度为。
冒泡排序
冒泡排序就是对于一个任意的序列,从第一个元素开始,两两比较,第一个和第二个元素比较,小的放在前面,第二个元素和第三个元素比较,小的放在前面,依次类推,经过第一轮比较,最大的元素排在最后一个位置,下次继续从第一个元素开始进行两两比较,最后一个元素不用比较,依次进行下去,进行n-1次后,第一个元素自然是最小的元素,故程序只需要执行n-1次。
public static void bubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {//处理数组元素为空或者只有一个元素的情况,直接返回
return;
}
for (int i = 0;i < arr.length-1 i++) {//一共执行n-1次
for (int j=0; j < arr.length-i-1; j++) {//比较次数,第一次循环比较n-1次,第二次循环比较n-2次,故而第m次循环比较n-m次
if (arr[j] > arr[j + 1]) {//如果后面的元素比前面的元素小,进行交换
swap(arr, j, j + 1);
}
}
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}//交换两个位置的值
对于这个程序的时间复杂度进行分析,关注最深层循环的语句,两层循环,数量级达到,而对于空间复杂度,不需要额外的空间,即空间复杂度为。
而对于这个过程,可以思考一下,如果经过仅有的几次排序已经达到有序,但是上面的这个程序依然还是会执行完所有的过程,浪费时间,所以我们可以对这个算法进行改进,即增加一个标志量,当某一次循环中没有执行比较,那么表示此时的序列已经有序,不需要继续执行后面的循环,此时对冒泡排序算法进行了优化。
优化后的代码如下
public static void bubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {//处理数组元素为空或者只有一个元素的情况,直接返回
return;
}
for (int i = 0;i < arr.length-1 i++) {//一共执行n-1次
boolean flag=false;//对程序的比较过程进行标记
for (int j=0; j < arr.length-i-1; j++) {//比较次数,第一次循环比较n-1次,第二次循环比较n-2次,故而第m次循环比较n-m次
if (arr[j] > arr[j + 1]) {//如果后面的元素比前面的元素小,进行交换
swap(arr, j, j + 1);
flag=ture;
}
}
if(flag==false){//如果没有进行交换,表示此时序列已经有序,直接返回
return;
}
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}//交换两个位置的值
对于改进后的程序,在实际应用中运行时间会有所降低,但是时间复杂度通常指的是最坏情况下需要的时间,所以时间复杂度并不会受到影响。
插入排序
插入排序是对于一个任意的序列,从0~0开始使序列有序,0~0只有一个数字有序,然后是让0~1有序,第二个数字和前一个数字比较,如果比它小,那么和它交换,不小,那么有序,然后让0~2有序,让第三个数字依次与前一个数字比较,按照这个操作,对数组中的数字进行操作,最后0~n-1个数字全部有序。
public static void insertionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}//对数组为空和只有一个元素的情况直接返回
//0~0有序的
//0~i想有序
for (int i = 1; i < arr.length; i++) {//0~i做到有序
for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
swap(arr, j, j + 1);//对于刚进入循环,将i-1位置的数字,也就是i位置的前一个数字和它进行比较,如果比它大,那么两者交换,然后j-1,往前继续比较,直到新比较的i位置的数字找到比它小的数字,或者走到第一个位置前面没有数字,循环结束。
}
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}//交换两个位置的数
这个程序的时间复杂度为,间复杂度为
插入排序当新比较的数字和前一个进行比较时,如果比前一个数字大,那么已经有序,不会再往前面进行比较。在实际应用中算法的运行时间,会优于上面两种排序算法,使用更广泛。
三种简单排序算法的总结
对于上面的三种排序算法,时间复杂度均为,空间复杂度均为,在使用中如果没有特殊要求优先使用插入排序。