CSDN话题挑战赛第2期 参赛话题:学习笔记
目录
前言
一、希尔排序
二、快速排序
三、归并排序
总结
前言
在Java学习之初,我们了解了几种常见的排序方法,如:冒泡排序法、选择排序法、插入排序法......但是这些排序法真的高效吗?我们看一看他们处理庞大数组的排序的时候,他们分别的运行时间是多少。在这里,我们生成了一个长度为10w的数组,分别用了这三种排序法进行测试,此时发现他们三种运行时间如下:
可以看到,这里使用冒泡排序法花了14000毫秒,选择排序法用了3300毫秒,插入排序法用了650毫秒。在这里,插入排序法已经显现出了较大的优势,但是还有没有比插入排序更高效的排序方法呢?当然有
一、希尔排序
希尔排序本质上是对插入排序的优化。我们来看这么一个例子:
在这里,前面的数字都已经排好序了,但是最后有一个1,我们都知道,把1插入到2前方就可以解决了。但是计算机会一眼看出来吗?当然不会。我们知道插入排序是从左到右开始判断,那这样最后的1要运算到最后了才可以进行插入,这样就消耗了很多不必要的时间。
我们怎么进行优化呢?
在排序之初,我们可以将较小的数尽量地提到数组的左边,这样就可以减少很多运算。在这里我们使用分组的方法,逐步对数组中较小的数字逐步插入,把较小的数字先移到前边,再进行排序,这样就可以减少很多运算时间了。
在这里,我们使用了长度为8的数组,我们首先令数组分为length/2 (4)组,将第0个和第4个看作一组,第1个和第5个看作一组,利用插入排序将这些分组的数字进行排序。同理,排序完成之后,我们又令整个数组分为length/2²(2)组,利用插入排序讲分组之后的数字进行排序。这样我们就将小数字都尽量的移到了整个数组的前边,最后我们再整体利用插入排序,就可以成功地进行排序了。完整代码:
public static void ShellSort(int a[]) {
for (int i = a.length/2; i > 0; i/=2) {
for (int j = i; j < a.length; j++) {
int temp = a[j];
int index = j - i;
while (index >= 0 && temp < a[index]) {
a[index+i] = a[index];
index -= i;
}
a[index+i] = temp;
}
}
}
二、快速排序
快速排序主要利用了递归,主要是先选一个中间值,选择之后将数组中比中间值小的放在中间值的左边,大的放在中间值的右边。完成之后,进行递归,将数组又重新分为两部分,重复操作,直至排序完成
public static void quickSort(int a[] , int left , int right) {
int l = left;
int r = right;
int mid = (left+right)/2;
int midValue = a[mid];
while (l<r) {
while (a[l] < midValue) {
l++;
}
while (a[r] > midValue) {
r--;
}
if (l>=r) {
break;
}
int n;
n = a[r];
a[r] = a[l];
a[l] = n;
if (a[r] == midValue) {
r--;
}
if (a[l] == midValue) {
l++;
}
}
if (l == r) {
l++;
r--;
}
if (left < l) {
quickSort(a , left , r);
}
if (right > r) {
quickSort(a , l , right);
}
}
三、归并排序
归并排序的主要思想是将数组进行分组,分到最后之后最后合并在一起,利用一个中间数组做中转,最后就可以达到效果了。
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
if(left < right) {
int mid = (left + right) / 2; //中间索引
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右递归进行分解
mergeSort(arr, mid + 1, right, temp);
//合并
merge(arr, left, mid, right, temp);
}
}
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid + 1;
int t = 0;
while (i <= mid && j <= right) {
if(arr[i] <= arr[j]) {
temp[t] = arr[i];
t += 1;
i += 1;
} else {
temp[t] = arr[j];
t += 1;
j += 1;
}
}
while( i <= mid) {
temp[t] = arr[i];
t += 1;
i += 1;
}
while( j <= right) {
temp[t] = arr[j];
t += 1;
j += 1;
}
t = 0;
int tempLeft = left;
while(tempLeft <= right) {
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
总结
最后,我们创建了一个长度为1000w的数组,进行速度测试,看看最终的运行时间是多少:
可以看到速度非常快,下次使用排序的时候,就可以用这些比较高效的排序方法了。