文章目录
- 1.冒泡排序
- 1.1代码实现
- 1.2复杂度
- 2.快速排序
- 2.1人物及思想介绍【源于百度】
- 2.2hoare【霍尔】版本
- 1.初识代码
- 2.代码分析
- 3.思其因果
- 2.3挖坑版本
- 1.初始代码
- 2.代码分析
- 3.思想比较
- 2.4指针版本
- 1.初识代码
- 2.代码分析
- 3.问题探讨
- 2.5集体优化
- 2.6极致优化
- 2.7非递归版本
- 1.初识代码
- 2.代码分析
- 2.8相关博客及完整代码
1.冒泡排序
1.1代码实现
//插入排序 O(N)~O(N^2)
//冒泡排序 O(N)~O(N^2)
//当数据有序 二者均为O(N)
//当数据接近有序或局部有序 插排更优
void BubbleSort(int* a, int n)
{
assert(a);
int flag = 1;
for (int i = 0; flag && i < n - 1; ++i)
{
flag = 0;
for (int j = 0; j < n - 1 - i; ++j)
{
if (a[j] > a[j + 1])
{
Swap(&a[j - 1], &a[j]);
flag = 1;
}
}
}
}
1.2复杂度
- 最坏:
比较n-1轮
每一轮比较次数:n n-1 n-2 n-3 … 1 ≈ N^2 - 最优:
比较n-1轮
数据有序–每一轮只判断不比较 – N
2.快速排序
2.1人物及思想介绍【源于百度】
2.2hoare【霍尔】版本
1.初识代码
//霍尔版本
int PartSort1(int* a, int begin, int end)
{
int left = begin, right = end, x = left;
while (left < right)
{
//右找小
while (left < right && a[right] >= a[x])
--right;
//左找大
while (left < right && a[left] <= a[x])
++left;
Swap(&a[left], &a[right]);
}
Swap(&a[x], &a[left]);
x = left;
return x;
}
void QuickSort(int* a, int begin, int end)
{
//begin:左区间左边界下标
//end :右区间右边界下标
//begin==end:数据量=1 无需排序 直接返回
//begin>end :无效区间 无需排序 直接返回
if (begin >= end)
return;
int x = PartSort1(a, begin, end);
// [begin, x - 1] x [x + 1, end]
QuickSort(a, begin, x - 1);
QuickSort(a, x+1, end);
}
2.代码分析
3.思其因果
Q:为什么a[x]【作为基准值key】置于左侧 – 右边先移动?
A:目的是为了保证相遇位置的值<=key 从而把key与相遇值交换 不打乱“左放小,右放大”的思想
2.3挖坑版本
1.初始代码
//挖坑版本
int PartSort2(int* a, int begin, int end)
{
int x = begin, key = a[begin];
while (begin < end)
{
while (begin < end && a[end] >= key)
--end;
a[x] = a[end];
x = end;
while (begin < end && a[begin] <= key)
++begin;
a[x] = a[begin];
x = begin;
}
a[x] = key;
return x;
}
void QuickSort(int* a, int begin, int end)
{
//begin:左区间左边界下标
//end :右区间右边界下标
//begin==end:数据量=1 无需排序 直接返回
//begin>end :无效区间 无需排序 直接返回
if (begin >= end)
return;
int x = PartSort1(a, begin, end);
// [begin, x - 1] x [x + 1, end]
QuickSort(a, begin, x - 1);
QuickSort(a, x+1, end);
}
2.代码分析
3.思想比较
霍尔版本:右找小 左找打 大小交换 依次递归
挖坑版本:记录key值 x位–置空 右找小入坑 坑位更新 左找大入坑 坑位更新 依次递归
2.4指针版本
1.初识代码
int PartSort3(int* a, int begin, int end)
{ //prv:previous cp:current pointer
int prv = begin, cp = begin + 1, x = begin;
while (cp <= end)
{
if (a[cp] < a[x] && ++prv != cp)
Swap(&a[prv], &a[cp]);
++cp;
}
Swap(&a[prv], &a[x]);
x = prv;
return x;
}
void QuickSort(int* a, int begin, int end)
{
//begin:左区间左边界下标
//end :右区间右边界下标
//begin==end:数据量=1 无需排序 直接返回
//begin>end :无效区间 无需排序 直接返回
if (begin >= end)
return;
int x = PartSort3(a, begin, end);
// [begin, x - 1] x [x + 1, end]
QuickSort(a, begin, x - 1);
QuickSort(a, x+1, end);
}
2.代码分析
3.问题探讨
2.5集体优化
//快速排序 O(N * logN)
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{
int mid = (begin + end) / 2;
if (a[begin] < a[mid])
{
if (a[mid] < a[end])
return mid;
else if (a[begin] < a[end])
return end;
else
return begin;
}
else //a[begin] >= a[mid]
{
if (a[mid] > a[end])
return mid;
else if (a[begin] < a[end])
return begin;
else
return end;
}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{
int left = begin, right = end, x = left;
//确定更合适的key
int mid_x = GetMid_X(a, begin, end);
Swap(&a[x], &a[mid_x]);
while (left < right)
{
//右找小
while (left < right && a[right] >= a[x])
--right;
//左找大
while (left < right && a[left] <= a[x])
++left;
Swap(&a[left], &a[right]);
}
Swap(&a[x], &a[left]);
x = left;
return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{
int x = begin;
//确定更合适的key
int mid_x = GetMid_X(a, begin, end);
Swap(&a[x], &a[mid_x]);
int key = a[x];
while (begin < end)
{
while (begin < end && a[end] >= key)
--end;
a[x] = a[end];
x = end;
while (begin < end && a[begin] <= key)
++begin;
a[x] = a[begin];
x = begin;
}
a[x] = key;
return x;
}
//指针版本
int PartSort3(int* a, int begin, int end)
{ //prv:previous cp:current pointer
int prv = begin, cp = begin + 1, x = begin;
//确定更合适的key
int mid_x = GetMid_X(a, begin, end);
Swap(&a[x], &a[mid_x]);
while (cp <= end)
{
if (a[cp] < a[x] && ++prv != cp)
Swap(&a[prv], &a[cp]);
++cp;
}
Swap(&a[prv], &a[x]);
x = prv;
return x;
}
void QuickSort(int* a, int begin, int end)
{
//begin:左区间左边界下标
//end :右区间右边界下标
//begin==end:数据量=1 无需排序 直接返回
//begin>end :无效区间 无需排序 直接返回
if (begin >= end)
return;
int x = PartSort2(a, begin, end);
// [begin, x - 1] x [x + 1, end]
QuickSort(a, begin, x - 1);
QuickSort(a, x+1, end);
}
2.6极致优化
2.7非递归版本
递归版本存在的问题:若递归层次太深 导致栈溢出问题
递归改非递归的方法:
- 直接改循环 – 斐波那契数列、归并排序等
- 数据结构的栈(Stack)模拟递归【Stack的空间是从堆申请的 堆内存比栈内存大】
1.初识代码
int PartSort3(int* a, int begin, int end)
{ //prv:previous cp:current pointer
int prv = begin, cp = begin + 1, x = begin;
//确定更合适的key
int mid_x = GetMid_X(a, begin, end);
Swap(&a[x], &a[mid_x]);
while (cp <= end)
{
if (a[cp] < a[x] && ++prv != cp)
Swap(&a[prv], &a[cp]);
++cp;
}
Swap(&a[prv], &a[x]);
x = prv;
return x;
}
void QuickSort_NonRecursion(int* a, int begin, int end)
{
ST st;
StackInit(&st);
StackPush(&st, begin);
StackPush(&st, end);
while (!StackEmpty(&st))
{
int right = StackTop(&st);
StackPop(&st);
int left = StackTop(&st);
StackPop(&st);
int x = PartSort3(a, left, right);
if (x + 1 < right)
{
StackPush(&st, x + 1);
StackPush(&st, right);
}
// [left, x-1] x [x+1, right]
if (left < x - 1)
{
StackPush(&st, left);
StackPush(&st, x - 1);
}
}
StackDestroy(&st);
}
2.代码分析
2.8相关博客及完整代码
点击 [qsort与bubble之间不为人知的关系](htt p://t.csdn.cn/filuW) 查看博主之前关于分析这两个排序的博客。
//快速排序 O(N * logN)
int count = 0; //测试递归次数
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{
int mid = (begin + end) / 2;
if (a[begin] < a[mid])
{
if (a[mid] < a[end])
return mid;
else if (a[begin] < a[end])
return end;
else
return begin;
}
else //a[begin] >= a[mid]
{
if (a[mid] > a[end])
return mid;
else if (a[begin] < a[end])
return begin;
else
return end;
}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{
int left = begin, right = end, x = left;
//确定更合适的key
int mid_x = GetMid_X(a, begin, end);
Swap(&a[x], &a[mid_x]);
while (left < right)
{
//右找小
while (left < right && a[right] >= a[x])
--right;
//左找大
while (left < right && a[left] <= a[x])
++left;
Swap(&a[left], &a[right]);
}
Swap(&a[x], &a[left]);
x = left;
return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{
int x = begin;
//确定更合适的key
int mid_x = GetMid_X(a, begin, end);
Swap(&a[x], &a[mid_x]);
int key = a[x];
while (begin < end)
{
while (begin < end && a[end] >= key)
--end;
a[x] = a[end];
x = end;
while (begin < end && a[begin] <= key)
++begin;
a[x] = a[begin];
x = begin;
}
a[x] = key;
return x;
}
//指针版本
int PartSort3(int* a, int begin, int end)
{ //prv:previous cp:current pointer
int prv = begin, cp = begin + 1, x = begin;
//确定更合适的key
int mid_x = GetMid_X(a, begin, end);
Swap(&a[x], &a[mid_x]);
while (cp <= end)
{
if (a[cp] < a[x] && ++prv != cp)
Swap(&a[prv], &a[cp]);
++cp;
}
Swap(&a[prv], &a[x]);
x = prv;
return x;
}
void QuickSort(int* a, int begin, int end)
{
count++;
//begin:左区间左边界下标
//end :右区间右边界下标
//begin==end:数据量=1 无需排序 直接返回
//begin>end :无效区间 无需排序 直接返回
if (begin >= end)
return;
int x = PartSort3(a, begin, end);
// [begin, x - 1] x [x + 1, end]
QuickSort(a, begin, x - 1);
QuickSort(a, x+1, end);
}
/*
void QuickSort(int* a, int begin, int end)
{
count++;
if (begin >= end)
return;
if (end - begin > 10)
{
int x = PartSort3(a, begin, end);
// [begin, x-1] x [x+1, end]
QuickSort(a, begin, x - 1);
QuickSort(a, x + 1, end);
}
else
InsertSort(a + begin, end - begin + 1);
}
*/
//非递归版本
void QuickSort_NonRecursion(int* a, int begin, int end)
{
ST st;
StackInit(&st);
StackPush(&st, begin);
StackPush(&st, end);
while (!StackEmpty(&st))
{
int end = StackTop(&st);
StackPop(&st);
int begin = StackTop(&st);
StackPop(&st);
int x = PartSort3(a, begin, end);
if (x + 1 < end)
{
StackPush(&st, x + 1);
StackPush(&st, end);
}
// [begin, x-1] x [x+1, end]
if (begin < x - 1)
{
StackPush(&st, begin);
StackPush(&st, x - 1);
}
}
StackDestroy(&st);
}