前言
排序算法事很重要的算法之一,几乎是Java的面试必问题了,在此通过几篇博文,总结一下几种常见的排序算法。当然这只是其中的几个。
排序算法可以分为内部排序和外部排序。
- 外部排序通常是读数据量很大的数据进行排序,且因为需要排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
- 内部排序需要排序的数据量相对较小。是将需要排序的数据记录在内存中进行排序。
博文链接:(点击排序名称可看到不同排序的博文。不断更新中…)
常见的内部排序算法有:冒泡排序、选择排序、插入排序、希尔排序、快速排序等。
几种排序的比较:
排序算法 | 时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|
冒泡排序 | O(n2) | O(1) | 稳定 |
选择排序 | O(n2) | O(1) | 不稳定 |
插入排序 | O(n2) | O(1) | 稳定 |
快速排序 | O(n logn) | O(log n) | 不稳定 |
归并排序 | O(n logn) | O(n) | 稳定 |
希尔排序 | O(n logn) | O(1) | 稳定 |
快速排序
- 排序讲解
1 默认第一位数字为基准值
2 将剩下的数字看为有两个指针的队列,其中高位指针为最后一次数字,低位指针为第一个数字
3 向左移动高位指针,如果该位置的数字大于基准值,继续向左移动,如果小于基准值,则将该数字赋值到低指针的位置,开始移动低指针
4 向右移动低位指针,如果该位置的数字小于基准值,继续向左移动,如果大于基准值,则将该数字赋值到高指针的位置,开始移动高指针
5 重复3 4 步,如果低位指针和高位指针重合,退出本次循环。
6 将中间值左右两边分别看成两个队列,进行快速排序 - 代码实现
/**
* 快速排序
* @param arr 需要排序的数组
* @param low 低位指针位置,默认从第一个数字开始,为0
* @param high 高位指针位置,默认从最后一个数字开始,为数组长度减1
*/
public static void quickSort(int[] arr, int low, int high) {
//如果指针在同一位置(只有一个数据时),退出
if (high - low < 1) {
return;
}
//作为数据的起始标记,flag为true:从高指针开始,flag为false:从低指针开始
boolean flag = true;
//初始化指针的开始位置
int start = low;
int end = high;
//取第一个值为基准值
int midValue = arr[low];
while (true) {
//高指针移动
if (flag) {
//如果列表右方的数据大于基准值,将指针向左移动一位继续比较
if (arr[high] > midValue) {
high--;
} else if (arr[high] < midValue) {
//如果小于基准值,将低位指针的值置为当前位置的值,将低位指针向前移动一位,标志位改成从低指针开始移动
arr[low] = arr[high];
low++;
flag = false;
}
} else {
//如果低指针执指向的数据小于中间值,则低指针向右移动一位
if (arr[low] < midValue) {
low++;
} else if (arr[low] > midValue) {
//如果低指针的值大于中间值,则将高位指针的值置为当前位置的值,并向左移动高指针。切换为高指针移动
arr[high] = arr[low];
high--;
flag = true;
}
}
//当高位指针和低位指针重合的时候,说明找到了中间位置,退出当前循环。
if (low == high) {
arr[low] = midValue;
break;
}
}
//-- 循环结束后,中间值左边的数字小于中间数字,中间值右边的数字大于中间值。
//-- 分别对中间值左边的子列和中间值右边的子列进行快速排序
quickSort(arr, start, low -1);
quickSort(arr, low + 1, end);
}