文章目录
- 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 pointerint 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;elsereturn begin;}else //a[begin] >= a[mid]{if (a[mid] > a[end])return mid;else if (a[begin] < a[end])return begin;elsereturn end;}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{int left = begin, right = end, x = left;//确定更合适的keyint 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;//确定更合适的keyint 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 pointerint prv = begin, cp = begin + 1, x = begin;//确定更合适的keyint 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 pointerint prv = begin, cp = begin + 1, x = begin;//确定更合适的keyint 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;elsereturn begin;}else //a[begin] >= a[mid]{if (a[mid] > a[end])return mid;else if (a[begin] < a[end])return begin;elsereturn end;}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{int left = begin, right = end, x = left;//确定更合适的keyint 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;//确定更合适的keyint 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 pointerint prv = begin, cp = begin + 1, x = begin;//确定更合适的keyint 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);
}