快速排序是一种高效且使用广泛的排序算法,在很多语言的标准库中自带的排序都是快速排序,所以我们也有必要了解快排的原理以及其实现方法。
快排的大致思想
快速排序实现的重点在于数组的拆分,通常我们将数组的第一个元素定义为比较元素,然后将数组中小于比较元素的数放到左边,将大于比较元素的放到右边,
这样我们就将数组拆分成了左右两部分:小于比较元素的数组;大于比较元素的数组。我们再对这两个数组进行同样的拆分,直到拆分到不能再拆分,数组就自然而然地以升序排列了。
不难看出,拆分算法是整个快速排序中的核心,快速排序拥有非常多的拆分方式,在本篇文章中我们介绍其中的两种,我个人将它称作:单指针遍历法与双指针遍历法(在下文中用英文单词split和partition称呼)
split算法解析
split算法使用一个单向的指针来对数组进行遍历,首先将数组首元素设置为比较元素,然后将第二个开始的元素依次与比较元素比较,如果大于比较元素则跳过,如果小于比较元素,则将其与前面较大的元素进行交换,将数组中所有元素交换完毕后,再将比较元素放到中间位置。
split算法实现(c):
1 //划分数组的函数
2 int split(int a[], int low, inthigh)3 {4 int i = low; //i指向比较元素的期望位置
5 int x = a[i]; //将该数组第一个元素设置为比较元素6 //从数组的第二个元素起开始遍历,若找到的元素大于比较元素,则跳过
7 for(int j = low+1;j<=high;j++)8 //若找到了小于比较元素的数,则将其与前面较大的数进行交换
9 if (a[j] <=x)10 {11 i++;12 swap(a[i], a[j]);13 }14 swap(a[low], a[i]); //将比较元素交换到期望位置
15 returni;16 }
split算法实现(java):
1 //划分数组
2 public static int split(int a[], int low, inthigh)3 {4 int i = low; //i指向比较元素的期望位置
5 int x = a[low]; //将该组的第一个元素作为比较元素6 //从第二个元素开始,若当前元素大于比较元素,将其跳过
7 for(int j = low+1; j <= high; j++)8 //若找到了小于比较元素的元素,将其与前面较大的元素进行交换
9 if(a[j] <=x)10 {11 i++;12 if(i !=j)13 swap(a, i, j);14
15 }16 swap(a, i, low); //将比较元素交换到正确的位置上
17 return i; //返回比较元素的位置
18 }
partition算法解析
partition算法使用头尾两个方向相反的指针进行遍历,先将数组第一个元素设置为比较元素,头指针从左至右找到第一个大于比较元素的数,尾指针从右至左找到第一个小于比较元素的数,全部交换完毕后将比较元素放到中间位置。
partition算法实现(c):
1 int partition(int a[], int low, inthigh)2 {3 int x = a[low]; //将该数组第一个元素设置为比较元素
4 int i = low; //指向数组头的指针
5 int j = high; //指向数组尾的指针
6 while (i =x)9 j--; //从右至左找到第一个小于比较元素的数
10 while (i < j && a[i] <=x)11 i++; //从左至右找到第一个大于比较元素的数
12 /*需要注意的是,这里的j--与i++的顺序不可以调换!13 如果调换了顺序,i会走过头,以至于将后面较大的元素交换到数组开头*/
14
15 //将大数与小数交换
16 if (i !=j)17 swap(a[i], a[j]);18 }19 swap(a[low], a[i]); //将比较元素交换到期望位置
20 return i; //返回比较元素的位置
21 }
partition算法实现(java):
1 //划分数组
2 public static int partition(int a[], int low, inthigh)3 {4 int x = a[low]; //将该数组第一个元素设置为比较元素
5 int i=low;6 int j=high;7 while(i =x)12 j--;13
14
15 if(i!=j)16 swap(a, i, j);17 }18 swap(a, j, low);19 returnj;20 }
两种算法的完整代码和实际演示
split算法(c):
1 #include
2
3 void swap(int &a, int &b)4 {5 int t =a;6 a =b;7 b =t;8 }9
10 //划分数组的函数
11 int split(int a[], int low, inthigh)12 {13 int i = low; //i指向比较元素的期望位置
14 int x = a[i]; //将该数组第一个元素设置为比较元素15 //从数组的第二个元素起开始遍历,若找到的元素大于比较元素,则跳过
16 for(int j = low+1;j<=high;j++)17 //若找到了小于比较元素的数,则将其与前面较大的数进行交换
18 if (a[j] <=x)19 {20 i++;21 swap(a[i], a[j]);22 }23 swap(a[low], a[i]); //将比较元素交换到期望位置
24 returni;25 }26
27 //快速排序
28 void quicksort(int a[], int low, inthigh)29 {30 if (low
33 quicksort(a, low, i - 1); //对比较元素左边进行排序
34 quicksort(a, i + 1, high); //对比较元素右边进行排序
35 }36 }37
38 intmain()39 {40 int a[] = { 5,7,1,6,4,8,3,2};41 int length = sizeof(a) / sizeof(a[0]);42 quicksort(a, 0, length - 1);43 for (int i = 0; i < length; i++)44 printf("%d", a[i]);45 printf("\n");46 return 0;47 }
split算法(java):
1 //快速排序split实现方法
2 public classT1 {3 public static voidmain(String args[])4 {5 int a[] = {5,7,1,6,4,8,3,2};6 quickSort(a, 0, a.length-1);7 for(int i=0;i
12 //交换方法
13 public static void swap(int a[], int i, intj)14 {15 int t =a[i];16 a[i] =a[j];17 a[j] =t;18 }19
20 //划分数组
21 public static int split(int a[], int low, inthigh)22 {23 int i = low; //i指向比较元素的期望位置
24 int x = a[low]; //将该组的第一个元素作为比较元素25 //从第二个元素开始,若当前元素大于比较元素,将其跳过
26 for(int j = low+1; j <= high; j++)27 //若找到了小于比较元素的元素,将其与前面较大的元素进行交换
28 if(a[j] <=x)29 {30 i++;31 if(i !=j)32 swap(a, i, j);33
34 }35 swap(a, i, low); //将比较元素交换到正确的位置上
36 return i; //返回比较元素的位置
37 }38
39 public static void quickSort(int a[], int low, inthigh)40 {41 if(low
44 quickSort(a, low, i-1); //对比较元素左边的数组进行排序
45 quickSort(a, i+1, high); //对比较元素右边的数字进行排序
46 }47 }48 }
partition算法(c):
1 #include
2
3 //交换函数
4 void swap(int &a, int &b)5 {6 int t =a;7 a =b;8 b =t;9 }10
11 int partition(int a[], int low, inthigh)12 {13 int x = a[low]; //将该数组第一个元素设置为比较元素
14 int i = low; //指向数组头的指针
15 int j = high; //指向数组尾的指针
16 while (i =x)19 j--; //从右至左找到第一个小于比较元素的数
20 while (i < j && a[i] <=x)21 i++; //从左至右找到第一个大于比较元素的数
22 /*需要注意的是,这里的j--与i++的顺序不可以调换!23 如果调换了顺序,i会走过头,以至于将后面较大的元素交换到数组开头*/
24
25 //将大数与小数交换
26 if (i !=j)27 swap(a[i], a[j]);28 }29 swap(a[low], a[i]); //将比较元素交换到期望位置
30 return i; //返回比较元素的位置
31 }32
33 void quicksort(int a[], int low, inthigh)34 {35 if (low
38 quicksort(a, low, i - 1); //对比较元素左边进行排序
39 quicksort(a, i + 1, high); //对比较元素右边进行排序
40 }41 }42
43 intmain()44 {45 int a[] = { 5,7,1,6,4,8,3,2};46 int length = sizeof(a) / sizeof(a[0]);47 quicksort(a, 0, length - 1);48 for (int i = 0; i < length; i++)49 printf("%d", a[i]);50 printf("\n");51 return 0;52 }
partition算法(java):
1 //快速排序partition实现方法
2 public classT2 {3 public static voidmain(String args[])4 {5 int a[] = {5,7,1,6,4,8,3,2};6 quicksort(a, 0, a.length-1);7 for(int i=0;i
12 public static void swap(int a[], int i, intj)13 {14 int t =a[i];15 a[i] =a[j];16 a[j] =t;17 }18
19 //划分数组
20 public static int partition(int a[], int low, inthigh)21 {22 int x = a[low]; //将该数组第一个元素设置为比较元素
23 int i=low;24 int j=high;25 while(i =x)28 j--; //从右至左找到第一个小于比较元素的数
29 while(i
31 /*需要注意的是,这里的j--与i++的顺序不可以调换!32 *如果调换了顺序,i会走过头,以至于将后面较大的元素交换到数组开头*/
33
34 //将大数与小数交换
35 if(i!=j)36 swap(a, i, j);37 }38 swap(a, i, low); //将比较元素交换到期望位置
39 return i; //返回比较元素的位置
40 }41
42 public static void quicksort(int a[], int low, inthigh)43 {44 if(low
47 quicksort(a, low, i-1); //对比较元素左边进行排序
48 quicksort(a, i+1, high); //对比较元素右边进行排序
49 }50 }51 }