update sort

This commit is contained in:
ranwenjie
2021-09-13 14:43:50 +08:00
parent d1ad2f3dbb
commit f72365e833
8 changed files with 169 additions and 65 deletions
+29 -15
View File
@@ -18,7 +18,7 @@
* 桶排序
## 交换排序算法
# 交换排序算法
排序算法的复杂度由 `比较的次数` 和 `交换的次数` 一起决定。
@@ -77,14 +77,18 @@
递归一次,pivot 左边都比它小,右边都比它大。这是递归,分治的思想。
> 快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历
对 A[p...r] :
1. 分解:A[p..q-1] A[q+1..r],使得 A[p...q-1]<A[q]<A[q+1..r]
0. 选择最后一个元素作为 pivot (基准)
1. 分解:A[p..q-1] A[q+1..r],使得 A[p...q-1]< A[q] <A[q+1..r]
2. 解决:递归调用 快排,,对子数组A[p..q-1],A[q+1..r]排序
3. 合并(子问题相互独立的,因此用分治算法就可以了)
具体步骤:
1. 从数列中选择一个元素,作为基准 pivot。通常取分区的第一个或最后一个
1. 从数列中选择一个元素,作为基准 pivot。通常取分区的最后一个
2. 重排数列,比 pivot 小得排左边,比pivot大的排右边,相等的随便。 一句话就是`挖坑填数`
3. 递归的,使用相同的方式,重排左右两边的子序列
@@ -107,14 +111,16 @@
int i=start,j=end;
int tmp = a[i]; // 这里要做越界检查
while(i<j){
// 从后向前扫描,找到第一个小于tmp的值,来填a[i]
while(i<j && a[j]>=tmp){
while(i<j && a[j]>=tmp){
j--;
}
if (i<j)//找到了,这时候a[j]为坑
{
a[i++] = a[j];
}
// 从左向右扫描,找一个大于 tmp的 数, 去填坑a[j]
while(i<j && a[i]<tmp){
i++;
@@ -124,6 +130,7 @@
a[j++]=a[i];
}
}
//扫描完成后,i==j
a[i]=tmp;
return i;
@@ -133,10 +140,9 @@
平均复杂度 O(n*logn)
最坏O(n^2)
平均复杂度 O(n * logn)
最坏 O(n^2)
空间复杂度
快速排序是对冒泡排序的改进,划分交换排序。
@@ -154,13 +160,21 @@
2. 解决。 将各个子数组都排好序,然后 merge 2个有序数组
3. 合并
if (length>1)
{
merge_sort(a,length/2);
merge_sort(a+length/2,length-length/2);
merge_array(a,length/2,a+length/2,length-length/2);
}
归并排序的代码框架如下:
```
void sort(int[] nums, int lo, int hi) {
int mid = (lo + hi) / 2;
sort(nums, lo, mid);
sort(nums, mid + 1, hi);
/****** 后序遍历位置 ******/
// 合并两个排好序的子数组
merge(nums, lo, mid, hi);
/************************/
}
```
@@ -239,7 +253,7 @@
国外也有人通过舞蹈的方式编排了几种基本的排序算法,非常有趣。[点这里去看看](http://v.youku.com/v_show/id_XMzMyODk4NTQ4.html?from=s1.8-1-1.2)
## 线性排序算法
# 线性排序算法
上面的算法都是基于比较的排序,时间复杂度最好也是 NlogN.而非基于比较的排序,可以突破NlogN的时间下限。当然,非比较的排序,也是需要有一些限定条件的。
@@ -252,7 +266,7 @@
### 小结
# 小结
常见的排序算法都是比较排序,比较排序的时间复杂度通常为 O(n^2) 或 O(nlogn)
但是如果带排序的数字有一些特俗性时,我们可以根据这来设计更加优化的排序算法。