1 思想
快速排序(Quick Sort)使用分治法策略。
它的基本思想是:选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分;其中一部分的所有数据都比另外一部分的所有数据都要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序流程:
(1) 从数列中挑出一个基准值。
(2) 将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边);在这个分区退出之后,该基准就处于数列的中间位置。
(3) 递归地把"基准值前面的子数列"和"基准值后面的子数列"进行排序。
2 思路
- 选中第1个数6为基准,然后遍历后面的数,将比6大的数放到6的右边,比6小的数放到6的左边,分成2组
- 将上面6左边的数当成一个数组,在选出一个基数为3,将比3大的数放到3的右边,比3小的数放到3的左边,在分成2组
- 然后在选出一个基础 依次类推
快速排序动态演示
4 代码实现(通过递归实现)
//快速排序 public static void main(String[] args) { int[] arr = {6,2,1,7,9,3,4,5,10,8}; quickSort(arr, 0, arr.length-1); System.out.println(Arrays.toString(arr)); } /** * 数组排序方法 * @param arr 需要排序的方法 * @param left 需要排序的左起点 * @param right 需要排序的右起点 * void */ public static void quickSort(int[] arr, int left, int right) { if (left > right) { return; } // 定义两个指针 用于移动 int start = left;// 起点下表 int end = right;// 终点下标 int base = arr[left];// 把第一个点作为基准点 int temp;// 下面帮助切换的辅助节点 while (start < end) { while (start < end && arr[end] >= base) {// 右指针先走,找到小于基准数的停止 end--; } while (start < end && arr[start] <= base) {// 左指针后走,找到大于基准数的停止 start++; } //当上面的循环结束时,此时证明找到了start和end的值 这是交换即可 if (start < end) { temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; } } //如果上面循环结束,证明 start 和 end 已经碰到了一起 此时start = end //这时候将基准数和start和end碰到的位置交换 arr[left] = arr[start]; arr[start] = base; //使用递归 //对基准数左边的数进行排序 quickSort(arr, left, start - 1); //对基准数右边的数进行排序 quickSort(arr, start + 1, right); }
5 快速排序时间复杂度
时间复杂度
快速排序涉及到递归调用,所以该算法的时间复杂度还需要从递归算法的复杂度开始说起;
令:n = n/2 = 2 { 2 T[n/4] + (n/2) } + n ----------------第二次递归
= 2^2 T[ n/ (2^2) ] + 2n
令:n = n/(2^2) = 2^2 { 2 T[n/ (2^3) ] + n/(2^2)} + 2n ----------------第三次递归
= 2^3 T[ n/ (2^3) ] + 3n
......................................................................................
令:n = n/( 2^(m-1) ) = 2^m T[1] + mn ----------------第m次递归(m次后结束)
当最后平分的不能再平分时,也就是说把公式一直往下跌倒,到最后得到T[1]时,说明这个公式已经迭代完了(T[1]是常量了)。
得到:T[n/ (2^m) ] = T[1] ===>> n = 2^m ====>> m = logn;
T[n] = 2^m T[1] + mn ;其中m = logn;
T[n] = 2^(logn) T[1] + nlogn = n T[1] + nlogn = n + nlogn ;其中n为元素个数
又因为当n >= 2时:nlogn >= n (也就是logn > 1),所以取后面的 nlogn;
综上所述:快速排序最优的情况下时间复杂度为:O( nlogn )
最差情况下时间复杂度
最差的情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序)
这种情况时间复杂度就好计算了,就是冒泡排序的时间复杂度:T[n] = n * (n-1) = n^2 + n;
综上所述:快速排序最差的情况下时间复杂度为:O( n^2 )
平均时间复杂度
空间复杂度
6 快速排序速度测试
1 //快速排序 2 public static void main(String[] args) { 3 speedTest(80000); 4 } 5 /** 6 * 创建一个随机数组 然后调用排序方法 得到时间 7 * @param number 创建的随机数组个数 8 */ 9 public static void speedTest(int number) { 10 int[] arr = new int[number]; 11 for (int i = 0; i < arr.length; i++) { 12 arr[i] = (int) (Math.random() * 800000); 13 } 14 15 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 16 Date date1 = new Date(); 17 String time1 = simpleDateFormat.format(date1); 18 System.out.println("排序前的时间为:" + time1); 19 20 //调用上面的快速排序方法 21 quickSort(arr, 0, arr.length - 1); 22 23 Date date2 = new Date(); 24 String time2 = simpleDateFormat.format(date2); 25 System.out.println("排序后的时间为:" + time2); 26 }
速度测试结果
8万个数据通过插入排序大约需要不到1秒
80万个数据通过插入排序大约需要不到1秒
800万个数据通过插入排序大约需要1秒
8000万个数据通过插入排序大约需要13秒