前面已经实现了单趟排序,下面将通过递归进行第二趟、第三趟排序…来让数组有序
一、基本思路
测试数组是我们上次单趟排序的结果
在单趟排序之后,会分为左右两个区间,左右两个区间再分别进行单趟排序
直到分解只剩两个数
二、递归排序代码实现
1、单趟排序代码
下面贴上前面写的单趟排序的代码
需要注意的是,由于要根据分界点划分区间,每次单趟排序过后,要保留分界点的坐标
所以下面单趟排序的返回值 从void 改为 int
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
//单趟排序的范围是 [left , right]
int SingleSort(int* a,int left,int right)
{
int prev, cur, key;
prev = left;
cur = left + 1;
key = a[left]; //将最左边的值作为key值
while (cur<=right)
{
//若找到比key小的数,则交换
if (a[cur] < key)
{
//prev++;
//Swap(a[cur], a[prev]);
Swap(a[cur], a[++prev]);
}
cur++;
}
Swap(a[prev], a[left]); //将临时分界点替换为最终分界点
return prev;
}
2、递归排序代码
注意:结束条件是 left >= right
当left = keyi 的时候
下一次递归传入的参数是 left ,keyi-1
判断的时候 left > keyi ,即区间左边界下标比右边界的下标更大,无法排序
void RecurseSort(int* a,int left,int right)
{
//分解到最后的结束条件是left >= right
if (left >= right)
{
return;
}
//单趟排序,选定key值,比key小的放左边,比key大的放右边,返回分界点下标keyi
int keyi = SingleSort(a, left, right);
//单趟排完以后,开始向左递归分解,区间范围是 [left , keyi-1]
RecurseSort(a, left, keyi - 1);
RecurseSort(a, keyi + 1, right);
}
三、代码测试
int main() {
int arr[] = { 6,1,2,7,9,3,4,5,10,8 };
//SingleSort(arr, 0, sizeof(arr) / sizeof(arr[0]) - 1);
RecurseSort(arr, 0, sizeof(arr) / sizeof(arr[0]) - 1);
for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
四、时间复杂度
根据 “二、基本思路” 可以将流程图简单化
(1)
最理想的情况
每次单趟排序排完,key值都在数组的中间
这个时候的逻辑结构十分接近完全二叉树
—> 树的深度:log N
—> 每一层cur移动的
总次数
:N(每一层都是N个数不变)
所以
时间复杂度最好为:O(N*log N)
(2)最糟的情况
最糟的情况就是每一趟的分界点都在最左侧
此时 cur的移动次数 = N-1 + N-2 + … + 1 = N*(N-1)/2
所以
时间复杂度为:O(N^2)
为了尽量避免key出现在边界位置,下一次将对排序进行优化