之前我在javase基础中初步了解了一下冒泡排序,现在想根据创建的排序算法总结出它们在各方面的优劣性。
下图为java常见的几种排序:
之前我们在刘老师的数据结构课程上也有学过时间复杂度和空间复杂度的概念,时间复杂度用来描述一个算法的执行时间,空间复杂度则是是对一个算法在运行过程中临时占用存储空间大小的一个度量。
一、交换排序
1、冒泡排序
核心思想是:
1、从第一个元素开始,比较相邻的两个元素。如果第一个比第二个大,则进行交换。
3、轮到下一组相邻元素,执行同样的比较操作,再找下一组,直到没有相邻元素可比较为止,此时最后的元素应是最大的数。
4、除了每次排序得到的最后一个元素,对剩余元素重复以上步骤,直到没有任何一对元素需要比较为止。算法代码如下:
public void bubbleSortOpt(int[] arr) {
if(arr == null) {
throw new NullPoniterException();
}
if(arr.length < 2) {
return;
}
int temp = 0;
for(int i = 0; i < arr.length - 1; i++) {
for(int j = 0; j < arr.length - i - 1; j++) {
if(arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
这段代码还有不足的地方,就是如果经过一轮交换之后,序列已经是是有序排列了,那么将不用执行剩下的交换。改进之后代码:
public static int bubbleSortOpt2(int[] arr) {
if (arr == null) {
throw new NullPointerException();
} else if (arr.length < 2) {
return 0;
}
int temp;
int count = 0;
for (int i = 0; i < arr.length - 1; i++) {
int flag = 1;
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = 0;
}
count++;
}
// 没有发生交换,排序已经完成
if (flag == 1) {
return count;
}
}
return count;
}
2、快速排序
快速排序的思想很简单,就是先把待排序的数组拆成左右两个区间,左边都比中间的基准数小,右边都比基准数大。接着左右两边各自再做同样的操作,完成后再拆分再继续,一直到各区间只有一个数为止。一般取首位元素作为基准数。
用java实现快速排序:
public void quicksort(int[] arr, int start, int end) {
if(start < end) {
// 把数组中的首位数字作为基准数
int stard = arr[start];
// 记录需要排序的下标
int low = start;
int high = end;
// 循环找到比基准数大的数和比基准数小的数
while(low < high) {
// 右边的数字比基准数大
while(low < high && arr[high] >= stard) {
high--;
}
// 使用右边的数替换左边的数
arr[low] = arr[high];
// 左边的数字比基准数小
while(low < high && arr[low] <= stard) {
low++;
}
// 使用左边的数替换右边的数
arr[high] = arr[low];
}
// 把标准值赋给下标重合的位置
arr[low] = stard;
// 处理所有小的数字
quickSort(arr, start, low);
// 处理所有大的数字
quickSort(arr, low + 1, end);
}
}
二、插入排序
插入排序是一种简单的排序方法,其基本思想是将一个记录插入到已经排好序的有序表中,使得被插入数的序列同样是有序的。按照此法对所有元素进行插入,直到整个序列排为有序的过程。
因为插入排序还没有仔细学,所以就不放代码了
1、直接插入排序
直接插入排序就是插入排序的粗暴实现。对于一个序列,选定一个下标,认为在这个下标之前的元素都是有序的。将下标所在的元素插入到其之前的序列中。接着再选取这个下标的后一个元素,继续重复操作。直到最后一个元素完成插入为止。我们一般从序列的第二个元素开始操作。
2、希尔排序
希尔排序把序列按下标的一定增量(步长)分组,对每组分别使用插入排序。随着增量(步长)减少,一直到一,算法结束,整个序列变为有序。因此希尔排序又称缩小增量排序。
一般来说,初次取序列的一半为增量,以后每次减半,直到增量为一。
三、选择排序
选择排序是一种简单直观的排序算法,首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
1、简单选择排序
选择排序思想的暴力实现,每一趟从未排序的区间找到一个最小元素,并放到第一位,直到全部区间有序为止。
java实现代码如下:
public static void selectSort(int[] arr) {
// 遍历所有的数
for (int i = 0; i < arr.length; i++) {
int minIndex = i;
// 把当前遍历的数和后面所有的数进行比较,并记录下最小的数的下标
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
// 记录最小的数的下标
minIndex = j;
}
}
// 如果最小的数和当前遍历的下标不一致,则交换
if (i != minIndex) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
2、堆排序
我们需要把一个普通数组转换为大顶堆,调整的起始点是最后一个非叶子结点,然后从左至右,从下至上,继续调整其他非叶子结点,直到根结点为止。
步骤如下:
1)根据初始数组构造堆
2)每次交换第一个和最后一个元素,然后将除最后一个元素以外的其他元素重新调整为大顶堆
重复以上两个步骤,没有元素可操作,就完成排序了。
四、总结
因为暂时还没有学习到所以的排序方法,所以有些排序就没有写出来了。
快速排序是最快的的排序算法
各算法时间复杂度和空间复杂度比较如下: