这本身是一个简单的 绝对值排序 问题,但是使用 选择排序 和 冒泡排序 均出现了超时问题,这是由于数的数量最大达到10^5这时候经过学习,了解了常见排序算法的 时间复杂度 ,这时候初始了都够更快解决问题的 快速排序 法。
快速排序是一种基于分治的快速排序,是对冒泡排序的一种改进,是非常重要且应用比较广泛的一种高效率排序算法。
//一种快速排序方式
void quickSort(int* arr, int low, int high) {
int i = low; //由i从左向右判断
int j = high; //由j从右向左判断
int temp = arr[low]; //记录第一个基准值。(可以不为第一个)
if (i >= j) //判断边界条件。(判断结束排序递归)
return;
while (i != j) { //判断每一次分块是否完成
while (i < j && arr[j]>=temp) //从右向左找到小于基准值的数后停止
j--;
while (i < j && arr[i] <= temp) //从左向右找到大于基准值的数后停止
i++;
if (i < j)
swap(&arr[i], &arr[j]); //交换两个被找到的数,使大于基准值的都在右边,小于的在左
}
//**关于循环中的( itemp )
quickSort(arr, i + 1, high); //递归完成两块的后续分块
quickSort(arr, low, i - 1);
}
完成完全分块 (
//** 关于循环中加入的( i
//** 先判断从右向左的原因 :若从左向右判断,最后一趟交换会从 i++ 到达 i=j。而此时的j是刚交换完的大于基准值的值。导致最终完成完全分块发生问题。(交换数为大值)
//**若基准值选择的是最后一个数,则最后需要交换的为大于基准值的值,所以需要从左向右
在再探快速排序部分将深入解决这一问题。
//不同于前一种快排的优化版
# include
# include
int a[100005], n;
void Quicksort(int a[], int l, int r)
{
//1. check boundary.
if (l >= r)
return;
//2. partition
int mid = l + (r - l) / 2, i = l - 1, j = r + 1, x = abs(a[mid]);
while (i < j)
{
do i++; while (abs(a[i]) < x);
do j--; while (abs(a[j]) > x);
if (i < j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}//每次partition会执行多次while, 但一旦一次while结束, 就完成了一次划分. 左边所有数小于基准数 右边所有数大于基准数.
//3. recurrence.
Quicksort(a, l, j);
Quicksort(a, j + 1, r);
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
Quicksort(a, 0, n - 1);
for (int i = 0; i < n; ++i)
printf("%d ", a[i]);
printf("\n");
return 0;
}
仔细观察问题解决的快速排序,与之前初识快排部分有较大的不同。它去除了最后的交换步骤。
没有完成完全分块。我们来深入看看优化版的代码。
以上版本为 快速排序 的 hoare版本 和 其优化版。还有别的版本和优化后续将会更新;希望大家指出代码和注释的问题(我自己绕的也很晕……