基础算法
快速排序算法
-
算法思想
-
算法演示
--
一开始数组的顺序是乱序的,我们需要在数组中确定分界点,它可以是数组中的任何元素,我们一般选择中点作为分界点,我们将选中的元素记作pivot。
- -
接下来,我们将对数组中的元素进行一次划分,小于pivot的元素标记为蓝色。大于pivot的元素标记为红色。然后把蓝色元素挪到左面,红色元素挪到右面。此时,pivot左边的元素都小于等于他,privot右边的元素都大于等于他。
-
至于分割后的左边数组和右边数组的内部顺序,我们并不关心。
-
对于左边的数组和右边的数组递归调用以上方法即可。
-
1.785. 快速排序
-
题目描述
-
思路:
- 理解分治的思路 ---- 把问题大化小
- 代码细节一 : 以j为划分时,x不能选q[r] , 若以i为划分,则x不能选q[l]
- 这里我们举例子说明,x选q[r] 。 假设数组为 3 , 4 , 此时按照代码运行 ,i为 1 , j为1 。 [l,j]会造成无限划分 ,本质上是j的取值范围可能变为[l,r],所以可能造成无限划分
- 这里我们举例子说明,x选q[l] 。 假设数组为 3 , 4 , 此时按照代码运行 ,i为 0 , j为0 。 [i,r]会造成无限划分
- 代码细节二:do i++; while(q[i] < x)和do j–; while(q[j] > x) 中不能用q[i] <= x 和 q[j] >= x
- 假设q[l…r]全相等,则执行完do i++; while(q[i] <= x);之后,i会自增到r+1,然后继续执行q[i] <= x 判断条件,造成数组下标越界,就会造成一直循环下去(亲身实验),造成内存超限(Memory Limit Exceeded)
- 代码细节三:while(i < j) 不能改为 while(i <= j)
- 这里我们举例子说明,x选q[l] 。 假设数组为 3 , 4 , 此时按照代码运行 ,i为 1 , j为-1 。 [j+1,r]会造成无限划分 ,本质上是当 i >= j 时就表明数组已经排序完成。
- 代码细节四:最后一句能不能用quick_sort(q, l, j-1), quick_sort(q, j, r)作为划分
- 这里我们举例子说明,x选q[l] 。 假设数组为 3 , 4 , 此时按照代码运行 ,i为 0 , j为0 。 [j,r]会造成无限划分,还是j的取值范围的问题。
-
代码
-
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; const int N = 1e6 + 10; int n ; int q[N]; void quick_sort(int q[] , int l , int r){ //证明子数组中至多只有一个元素,我们无需进行排序 if(l >= r) return ; int x = q[(l+r)/2]; /* 注意:由于使用do-while循环,所以i和j一定会自增,使得循环会继续下去,但是如果采用while循环(i和j的初始化做出对应的变 更),i和j在特殊情况下不自增的话,循环就会卡死. while(q[i] < x) i++; while(q[j] > x) j--; 当q[i]和q[j]都为 x 时, i 和 j 都不会更新,导致 while 陷入死循环 这里是理解的难点: 我们取个例子 1 2 3 3 5 ,如果不使用do while循环的话 i , j 指针会卡在 3 3 上 , 从而卡在while循环,无法出来 */ int i = l - 1 , j = r + 1; while(i < j){ do i++ ; while(q[i] < x); do j-- ; while(q[j] > x); if(i < j ){ swap(q[i],q[j]); } } quick_sort(q,l,j); quick_sort(q,j+1,r); } int main(){ scanf("%d",&n); //进行读入 for(int i = 0 ; i < n ; i++){ scanf("%d",&q[i]); } quick_sort(q,0,n - 1); //进行输出 for(int i = 0 ; i < n ; i++){ printf("%d ",q[i]); } }
-