快速排序:
一、排序原理&逻辑
要想拿捏住快速排序算法,就要先将它的排序原理和逻辑给弄清楚。
| 原理&逻辑 |
| 图解 |
>> 单个数排序图解
!! 此时 3 的顺序已经定了下来,后续不再需要移动 !!
| 代码实现 |
#include<stdio.h>
void ArrPrint(const int* a, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
void QuickSort(int* a, int n)
{
int begin = 0;
int end = n - 1;
int pivot = begin;
int key = a[begin];
while (begin < end)
{
while (begin < end && a[end] >= key)
{
end--;
}
a[pivot] = a[end];
pivot = end;
while (begin < end && a[begin] <= key)
{
begin++;
}
a[pivot] = a[begin];
pivot = begin;
}
pivot = begin;
a[pivot] = key;
}
int main()
{
int arr[] = { 3,1,6,5,0,4,2 };
QuickSort(arr, sizeof(arr) / sizeof(arr[0]));
ArrPrint(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
>> 代码运行符合图解分析,达到了我们预期的结果
当 3 左右两边的 x 区域和 y 区域都有序时,整个数组就变得有序了。
而对 x 区域的各个数和 y 区域的各个数排序与本篇博客上面讲解的对一个数排序的过程说相类似的。这时我们要运用到分治策略的思想。
二、分治策略
在C语言里我们可以用函数的递归来实现分治策略。 用函数递归的形式不断的对 x 区域和 y 区域里的各个数进行排序,直到整个数组有序。
>> 进行完以上的优化分析后,我们的代码同样也需要进行调整
#include<stdio.h>
void ArrPrint(const int* a, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
void QuickSort(int* a, int left, int right) //讲解点1
{
if (left >= right) //讲解点3
{
return;
}
int begin = left;
int end = right;
int pivot = begin;
int key = a[begin];
while (begin < end)
{
while (begin < end && a[end] >= key)
{
end--;
}
a[pivot] = a[end];
pivot = end;
while (begin < end && a[begin] <= key)
{
begin++;
}
a[pivot] = a[begin];
pivot = begin;
}
pivot = begin;
a[pivot] = key;
QuickSort(a, left, pivot - 1); //讲解点2
QuickSort(a, pivot + 1, right); //讲解点2
}
int main()
{
int arr[] = { 3,1,6,5,0,4,2 };
QuickSort(arr, 0, (sizeof(arr) / sizeof(arr[0])) - 1); // 讲解点1
ArrPrint(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
| 讲解点1 |
| 讲解点2 |
| 讲解点3 |
三、“三数取中” ( 拓展 )
通常情况下我们取待排序区间的左边界的数据存放在 key 中,若该数组为有序数组 ( 以升序为例 ) 每次 end 都要从待排序区间的右边界遍历到左边界,这一操作会使得快速排序的时间复杂度变坏
| 图解 |
为解决这一情况我们要引入一个较为巧妙的方法 >> “三数取中”
| 逻辑 |
>> 清楚 “三数取中” 的逻辑后,要用函数来实现三个数的比较
#include<stdio.h>
void ArrPrint(const int* a, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int GetMid(int* a, int left, int right) //讲解点1
{
int mid = (left + right) / 2;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
{
return mid;
}
else if (a[left] > a[right])
{
return left;
}
else
{
return right;
}
}
else
{
if (a[mid] > a[right])
{
return mid;
}
else if (a[right] > a[left])
{
return left;
}
else
{
return right;
}
}
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
int index = GetMid(a, left, right); //讲解点2
Swap(&a[left], &a[index]);
int begin = left;
int end = right;
int pivot = begin;
int key = a[begin];
while (begin < end)
{
while (begin < end && a[end] >= key)
{
end--;
}
a[pivot] = a[end];
pivot = end;
while (begin < end && a[begin] <= key)
{
begin++;
}
a[pivot] = a[begin];
pivot = begin;
}
pivot = begin;
a[pivot] = key;
QuickSort(a, left, pivot - 1);
QuickSort(a, pivot + 1, right);
}
int main()
{
int arr[] = { 7,4,3,2,1,5,7,88,9,76,5 };
QuickSort(arr, 0, (sizeof(arr) / sizeof(arr[0]))-1);
ArrPrint(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
| 讲解点1 |
| 讲解点2 |
引入 “三数取中” 后有序数组的排序情况 >>
< 本次学习就到这里了,如有错误希望大家指正,感谢 ! >