这里主要是参考网上的博客做的学习笔记,有不对之处请指正,其实本人现在对于快速排序还是不够清晰。
/** | |
* <p> | |
* <code>Test</code> | |
* </p> | |
* Description: | |
* | |
* @author Mcchu | |
* @date 2017/12/5 15:57 | |
*/ | |
public class Test { | |
/** | |
* 快速排序轮次计数器 1 | |
*/ | |
private static int quickSortCount1 = 0; | |
/** | |
* 快速排序轮次计数器 2 | |
*/ | |
private static int quickSortCount2 = 0; | |
/** | |
* 快速排序 | |
* 参考:百度百科 | |
* | |
* 快排简述 - 分治法 | |
* 1.先从数列中取出一个数作为基准数。 | |
* 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。 | |
* 3.再对左右区间重复第二步,直到各区间只有一个数。 | |
* | |
* 程序解释 | |
* 1. 设置两个变量 i、j,排序开始的时候:i=0,j=N-1; | |
* 2. 以第一个数组元素作为关键数据,赋值给 key,即 key=A [0]; | |
* 3. 从 j 开始向前搜索,即由后开始向前搜索 (j--),找到第一个小于 key 的值 A [j],将 A [j] 和 A [i] 互换; | |
* 4. 从 i 开始向后搜索,即由前开始向后搜索 (i++),找到第一个大于 key 的 A [i],将 A [i] 和 A [j] 互换; | |
* 5. 重复第 3、4 步,直到 i=j; | |
* (3,4 步中,没找到符合条件的值,即 3 中 A [j] 不小于 key,4 中 A [i] 不大于 key 的时候改变 j、i 的值,使得 j=j-1,i=i+1,直至找到为止。 | |
* 找到符合条件的值,进行交换的时候 i, j 指针位置不变。另外,i==j 这一过程一定正好是 i + 或 j - 完成的时候,此时令循环结束)。 | |
* | |
* 注意:快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。 | |
* 快速排序时间复杂度:O (nlogn) | |
* @param arr 排序数据 | |
* @param low 每次排序时第一个数字的下标 | |
* @param high 每次排序时最后一个数字的下标 | |
*/ | |
private static void quickSort1(int[] arr,int low,int high){ | |
if ( low < high ){ | |
int i = low; // 左指针(以下标为计数), 由右向左移动 | |
int j = high; // 右指针(以下标为计数), 由左向右移动 | |
int k = arr[low]; //k 为基准数 | |
quickSortCount1++; | |
System.out.println("第"+ quickSortCount1 +"轮次"); | |
System.out.println("指针i指向:arr["+i+"]"); | |
System.out.println("指针j指向:arr["+j+"]"); | |
System.out.println("基准数k值:"+k); | |
while( i < j ){ | |
// 从右向左找第一个小于基准数的数 | |
while ( i < j && k <= arr[j] ) | |
j--; | |
// 执行 i 和 j 交换 | |
if ( i < j ){ | |
int temp = arr[j]; | |
arr[j] = arr[i]; | |
arr[i] = temp; | |
i++; | |
} | |
// 从左向右找第一个大于基准数的数 | |
while ( i < j && k >= arr[i] ) | |
i++; | |
// 执行 i 和 j 交换 | |
if ( i < j ){ | |
int temp = arr[i]; | |
arr[i] = arr[j]; | |
arr[j] = temp; | |
j--; | |
} | |
} | |
System.out.print("排序后数组:"); | |
for ( int in: arr ){ | |
System.out.print(in); | |
System.out.print(","); | |
} | |
System.out.println(); | |
if(i>low) quickSort1(arr,low,i-1); | |
if(j<high) quickSort1(arr,j+1,high); | |
} | |
} | |
/** | |
* 快速排序 | |
* 挖坑填数 + 分治法 | |
* 参考:CSDN(http://blog.csdn.net/morewindows/article/details/6684558) | |
* | |
* 1. 以一个数组作为示例,取区间第一个数为基准数 | |
* 2. 初始时,i = 0; j = arr.length-1; k = a [0] (k 为基准数) | |
* 3. 可以理解为:首先在 a [0] 上挖了一个坑 | |
* 4. 从 j 开始向前搜索,即由后开始向前搜索 (j--),找到第一个小于 k 的值 a [j],将 a [j] 挖出填到 a [0], | |
* 第一个坑就被填上了,需再找一个数字填 a [j] 的坑,该轮到 i 找了(即 i++) | |
* 5. 从 i 开始向后搜索,即由前开始向后搜索 (i++),找到第一个大于 k 的值 a [i],将 a [i] 挖出填到刚刚的 a [j], | |
* 继续找 j(即 j--) | |
* | |
* @param arr 排序数据 | |
* @param low 每次排序时第一个数字的下标 | |
* @param high 每次排序时最后一个数字的下标 | |
*/ | |
private static void quickSort2( int[] arr, int low, int high ){ | |
if (low < high) { | |
int i = low; | |
int j = high; | |
int k = arr[low]; | |
quickSortCount2++; | |
System.out.println("第"+ quickSortCount2 +"轮次"); | |
System.out.println("指针i指向:arr["+i+"]"); | |
System.out.println("指针j指向:arr["+j+"]"); | |
System.out.println("基准数k值:"+k); | |
while (i < j) | |
{ | |
while(i < j && arr[j] >= k) // 从右向左找第一个小于 k 的数 | |
j--; | |
if(i < j) | |
arr[i++] = arr[j]; | |
while(i < j && arr[i] < k) // 从左向右找第一个大于等于 k 的数 | |
i++; | |
if(i < j) | |
arr[j--] = arr[i]; | |
} | |
arr[i] = k; | |
System.out.print("排序后数组:"); | |
for ( int in: arr ){ | |
System.out.print(in); | |
System.out.print(","); | |
} | |
System.out.println(); | |
quickSort2(arr, low, i - 1); // 递归调用 | |
quickSort2(arr, i + 1, high); | |
} | |
} | |
private static int[] arr = {8,2,5,4,6,9,1,3,7}; | |
/** | |
* 快速排序 | |
* 参考:《啊哈算法》 | |
* 参考:CSDN (http://blog.csdn.net/binyao02123202/article/details/20051391) | |
* | |
* 1. j 指针一步一步向左移动,找到一个小于 k 的值后,停下,此时 j 指向 a [j] | |
* 2. i 指针开始一步一步向右移动,找到一个大于 k 的值后,停下,此时 i 指向 a [i] | |
* 3. 交换 a [i] 和 a [j] 的值 | |
* 4. 再次轮到 j 行动,重复上面的步骤,直到 i 和 j 相遇 | |
* 5. i 和 j 相遇后的动作是: | |
* 第一个值(起始值)赋值为此时他们相遇指向的那个值; | |
* 而他们指向的那个值赋值为 k | |
* 6. 重复上面的步骤 | |
* | |
* @param low 每次排序时第一个数字的下标 | |
* @param high 每次排序时最后一个数字的下标 | |
*/ | |
private static void quickSort3( int low,int high ){ | |
if ( low<high ){ | |
int i = low; | |
int j = high; | |
int k = arr[low]; | |
while ( i!=j ){ | |
while ( arr[j]>=k && i<j ) | |
j--; | |
while ( arr[i]<=k && i<j ) | |
i++; | |
if ( i<j ){ | |
int temp = arr[i]; | |
arr[i] = arr[j]; | |
arr[j] = temp; | |
} | |
} | |
arr[low] = arr[i]; | |
arr[i] = k; | |
quickSort3(low,i-1); | |
quickSort3(i+1,high); | |
} | |
} | |
public static void main(String[] args) { | |
// 测试快速排序 1 | |
int[] arr1 = {8,2,5,4,6,9,1,3,7}; | |
int low1 = 0; | |
int high1 = arr1.length-1; | |
quickSort1(arr1,low1,high1); | |
System.out.println("\n\n---------我是分割线-----------\n\n"); | |
// 测试快速排序 2 | |
int[] arr2 = {8,2,5,4,6,9,1,3,7}; | |
int low2 = 0; | |
int high2 = arr2.length-1; | |
quickSort2(arr2,low2,high2); | |
System.out.println("\n\n---------我是分割线-----------\n\n"); | |
// 测试快速排序 3 | |
quickSort3(0,arr.length-1); | |
System.out.print("排序后数组:"); | |
for ( int in: arr ){ | |
System.out.print(in); | |
System.out.print(","); | |
} | |
System.out.println(); | |
} | |
} |
输出:
第1轮次
指针i指向:arr[0]
指针j指向:arr[8]
基准数k值:8
排序后数组:7,2,5,4,6,3,1,8,9,
第2轮次
指针i指向:arr[0]
指针j指向:arr[6]
基准数k值:7
排序后数组:1,2,5,4,6,3,7,8,9,
第3轮次
指针i指向:arr[0]
指针j指向:arr[5]
基准数k值:1
排序后数组:1,2,5,4,6,3,7,8,9,
第4轮次
指针i指向:arr[1]
指针j指向:arr[5]
基准数k值:2
排序后数组:1,2,5,4,6,3,7,8,9,
第5轮次
指针i指向:arr[2]
指针j指向:arr[5]
基准数k值:5
排序后数组:1,2,3,4,5,6,7,8,9,
第6轮次
指针i指向:arr[2]
指针j指向:arr[3]
基准数k值:3
排序后数组:1,2,3,4,5,6,7,8,9,
---------我是分割线-----------
第1轮次
指针i指向:arr[0]
指针j指向:arr[8]
基准数k值:8
排序后数组:7,2,5,4,6,3,1,8,9,
第2轮次
指针i指向:arr[0]
指针j指向:arr[6]
基准数k值:7
排序后数组:1,2,5,4,6,3,7,8,9,
第3轮次
指针i指向:arr[0]
指针j指向:arr[5]
基准数k值:1
排序后数组:1,2,5,4,6,3,7,8,9,
第4轮次
指针i指向:arr[1]
指针j指向:arr[5]
基准数k值:2
排序后数组:1,2,5,4,6,3,7,8,9,
第5轮次
指针i指向:arr[2]
指针j指向:arr[5]
基准数k值:5
排序后数组:1,2,3,4,5,6,7,8,9,
第6轮次
指针i指向:arr[2]
指针j指向:arr[3]
基准数k值:3
排序后数组:1,2,3,4,5,6,7,8,9,
---------我是分割线-----------
排序后数组:1,2,3,4,5,6,7,8,9,
附一个挖坑填数的草图(就是上面第二个测试的):