文章目录
参考:https://www.acwing.com/blog/content/277/
快速排序模板
void quick_sort(int q[], int l, int r)
{
if (l >= r)
return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
while(q[i] < x)
i++;
while(q[j] > x)
j--;
if (i < j)
swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
本模板实现的是升序排序,改降序的话直接修改while里面的符号,改成
while(q[i] > x) i++;
while(q[j] < x) j--;
即可。
模板思路:
- 这个函数接受三个参数:一个整数数组q,以及两个表示要排序部分的起始(l)和结束(r)的索引。
- 在函数的开头,我们首先检查数组的长度是否大于1。如果l >= r,那么数组的长度为0或1,我们可以直接返回,因为长度为0或1的数组已经是排序好的。
- 接下来,我们初始化两个指针i和j,分别指向数组的开始和结束,然后选择基准元素x。这里的基准元素是数组中间的元素(l + r >> 1表示(l + r) / 2,即数组的中点)。
- while循环开始了分区操作。在这个循环中,我们首先移动i直到找到一个大于等于基准的元素,然后移动j直到找到一个小于等于基准的元素,然后交换这两个元素。当i < j不再满足,循环结束,此时所有小于基准的元素都在j的左边,所有大于基准的元素都在j的右边。
- 最后,我们对基准左侧和右侧的两个子数组递归调用quick_sort函数。
两个while的解释:
while(q[i] < x) i++;和while(q[j] > x) j–;这两行代码的作用是找到需要交换的元素。
-
while(q[i] < x) i++;这一行是在找数组中第一个大于等于基准元素x的元素。从左边(即较小的索引)开始遍历,只要遇到的元素小于基准元素,就将索引i向右移动一位,即i++。一旦找到一个大于等于基准元素的元素,就跳出循环。
-
同样,while(q[j] > x) j–;这一行是在找数组中第一个小于等于基准元素x的元素。这次从右边(即较大的索引)开始遍历,只要遇到的元素大于基准元素,就将索引j向左移动一位,即j–。一旦找到一个小于等于基准元素的元素,就跳出循环。
这两步操作的目标是找到数组中的一对元素,其中左边的元素大于基准元素,右边的元素小于基准元素,然后交换这对元素。这样,在每次循环结束时,都能保证基准元素左边的元素都小于或等于基准元素,右边的元素都大于或等于基准元素,从而完成了一轮的分区操作。
使用示例:
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + 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() {
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr) / sizeof(arr[0]);
quick_sort(arr, 0, n - 1);
for(int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
时间复杂度与空间复杂度
快速排序(QuickSort)的性能依赖于选择的“pivot”(基准)元素。如果恰好每次都能选择中间值,快速排序表现最好;如果每次选择的都是最小(或最大)的元素,快速排序表现最差。
-
时间复杂度
- 最好情况:如果每次我们都能选取到数组的中间值作为pivot,快速排序的性能最好。这种情况下,快速排序的时间复杂度为O(n log n)。
- 最坏情况:如果每次我们都选取到数组的最小值或最大值作为pivot,快速排序的性能最差。这种情况下,快速排序的时间复杂度为O(n^2)。
- 平均情况:在随机选择pivot的情况下,快速排序的平均时间复杂度为O(n log n)。
-
空间复杂度
- 快速排序是原地排序算法,不需要额外的存储空间,所以其空间复杂度为O(1)。但是,快速排序需要用到递归,递归需要堆栈空间。
- 递归的深度在最坏情况下为n,在最好情况下为log n。因此,快速排序的空间复杂度通常描述为递归堆栈的大小。
- 最好情况(平均情况):递归树的深度为log n,所以空间复杂度为O(log n)。
- 最坏情况:递归树的深度为n,所以空间复杂度为O(n)。
空间复杂度上,O(n)是快排最差的,O(logn)是一般情况或者平均。面试被问到直接两种都说出来更好。
空间复杂度的计算
空间复杂度计算的时候, 不算上结果数组 但是会算除了结果数组之外的部分,例如开的除了结果数组之外的额外空间,和有的stl算法本身消耗的空间