排序
快排是不稳定的,归并是稳定的
快速排序 主要思想:分治(分界点从数组里随机取一个点
主要流程
-
确定分界点
- 第一种方法:取左边界 q[ I ]
- 第二种方式:取中间值 q[ ( 1 + r) / 2]
- 第三种方式 取右边界 q[ r ]
-
调整区间
使第一个区间里的数都 小于等于 x (左半边
第二个区间里的数都 大于等于 x (右半边
-
递归处理左右两端
左边排好序,右边排好序
第二步中两个小方法
方法一:
-
设两个数组 a[ ] b[ ]
-
检查q[ l~r ]的数值
- 小于等于X的插到a[ ]里
- 大于等于X的插到b[ ]里
-
分别将a[ ]、b[ ]插到q[ ]的第一区间和第二区间
方法二:
- 设置两个指针low和high,他们的初值分别为s和t。首先将X移至临时变量,之后检测指针high所指记录,若q[ high ] 大于 X,则high减1,否则将q[ high ] 移至指针low所指向的位置;之后检查指针low所指记录,若q[ low ] 小于 X ,则 low 增 1,否则将q[ low ] 移至指针high所指位置;重复上述两个方向的检测,直到high和low指针指向同一位置
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
归并排序 主要思想:分治(以中间点为分解点) (分治方法和快排不同
主要流程
- 确定分界点 : mid = (1 + r) / 2 (左右两边的平均值,就是最中间的位置
- 递归排序 left(第一个序列) 和 right (第二个序列)
- 归并 --》 把两个有序的数组合二为一 此步骤的时间复杂度是O(n)
如何归并
首先通过递归排序保证两个序列都是有序的,设置一个新的数组res[ ] ,和两个指针分别指向两个序列的最小值。比较两个指针指向的数值,把较小的指针指向的数值保存到res[ ] 中,然后把这个指针后移一位(再次指向此序列中最小值),继续比较两指针指向的数值,然后放到数组res[ ] 中。循环往复重复此操作,直至排序成功。
(如果两个指针指向的数值相等,优先把第一个序列中的数值存到res中,这样能保证排序是稳定的
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
else tmp[k ++ ] = q[j ++ ];
while (i <= mid) tmp[k ++ ] = q[i ++ ];
while (j <= r) tmp[k ++ ] = q[j ++ ];
for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
时间复杂度
平均的快排 和 归并排序 的时间复杂度都是 nlog2n