算法导论
本文中含有数学公式,若无法显示请刷新重试,谢谢~
Lesson 1
插入排序
1 插入排序的基本原理(递增排序)
取当前元素往前序寻找。依序比较,若前一元素比当前大,则被比较元素往后移动一位;以此类推,直至找到第一个比其小的元素,则停止寻找,这个位置的后一个就是应该放的位置。
2 插入排序的C++实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void insertionsort(vector<int>sorted){
int size = (int)sorted.size();
//从第2项开始取为目标元素
for(int j=1;j<size;j++){
int key = sorted[j];
//需要比较的是目标元素的前一项开始
int k = j-1;
//向后移动的必要条件
while(k>=0 && sorted[k]>key){
sorted[k+1] = sorted[k];
k--;
}
//跳出循环,找到了应该在的位置
sorted[k+1] = key;
}
}
3 插入排序算法的分析
- 时间复杂度上界 \[O(n^2)\]
几个标记符号的数学定义
- 几个注意点:
- 渐进符号只关心两个函数在极限位置的大小状况。
- 所有的渐进符号都代表着一种函数,为集合概念,『=』仅为方便记载,对应于集合论中『∈』符号,理论上前后不调换。
- 性质:传递,自反,对称,转置对称
- 若在等式或不等式中出现的时候,则表示这一类的匿名函数,若出现在等式右边,可以另设一个函数f(x)来替代这个符号所表示的位置。若出现在左边,则可用以下规则解释:
无论怎样选择等号左边的匿名函数,总有一种方法来选择等号右边的匿名函数使等号成立。
Ex. \[ 2n^2+3n+1=2n^2+\Theta(n)=\Theta(n^2) \]
第一个等式: [ 表明存在某个函数f(n) \in \Theta(n),使得对所有的n,有2n^2+3n+1=2n+f(n)。 ] 第二个等式: [ 表明对于任意函数g(n)\in\Theta(n),存在h(x)\in\Theta(n^2),使得对所有的n,有2n^2+g(n)=h(n)。 ] 整体也蕴含着前项直接可以属于最后项(这个法则仅对有限项有效)
- 渐进上界 \[ O(g(n)) = \{f(n) :\exists c>0,n_0>0 ;对于\forall n\ge n_0 都有0\le f(n) \le c·g(n) \} \]
- 渐进上界的计算方式:忽略所有低阶项和最高阶前之前的常数系数。
- 渐进下界 \[ \Omega (g(n)) = \{f(n) :\exists c>0,n_0>0 ;对于\forall n\ge n_0 都有0\le c·g(n) \le f(n) \} \]
- 渐进紧确界 \[ \Theta(g(n))=\{f(n):\exists 正常数 c_1,c_2,n_0;使得对\forall n\ge n_0,都有0\le c_1·g(n)\le f(n) \le c2·g(n) \} \]
- o记号 基本同O符号,但需要对所有c>0成立。
- ω记号 基本同Ω符号,但需要对所有c>0成立
归并排序
1 归并排序的基本思想:分治法(Divide and Conquer)
2 归并排序的C++实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
vector<int> sorted;
//归并操作
void merge(int left,int mid,int right){
//将左右两边分别放入新建的数组当中,方便进行归并操作
int n1 = mid-left+1;
int n2 = right-mid;
vector<int>L,R;
L.clear();
R.clear();
for(int i=1;i<=n1;i++){
L.push_back(sorted[left+i-1]);
}
for(int i=1;i<=n2;i++){
R.push_back(sorted[mid+i]);
}
//归并排序,利用子序列已经排完序的性质,只需要比较首元素即可
int i=0,j=0;
for(int k=left;k<=right;k++){
if(L[i]<=R[j]){
sorted[k] = L[i];
i++;
}else{
sorted[k] = R[j];
j++;
}
//不使用哨兵,利用下标到达界限判断
if(i==L.size()){
k++;
for(int u=j;u<R.size();u++){
sorted[k] = R[u];
k++;
}
break;
}
if(j==R.size()){
k++;
for(int u=i;u<L.size();u++){
sorted[k] = L[u];
k++;
}
break;
}
}
}
//执行归并函数所需要调用的入口
void mergesort(int leftlim,int rightlim){
//若大于等于则表示已经只有一个元素,不需要进行递归进入下一步
if(leftlim<rightlim){
int mid = (leftlim+rightlim)/2;
//左侧递归进行归并
mergesort(leftlim,mid);
//右侧递归进行归并
mergesort(mid+1,rightlim);
//合并
merge(leftlim,mid,rightlim);
}
}
3 归并排序的递归式 [ T(n) = 2T(n/2)+\Theta(n) (n > 1) ]
[ T(n) = \Theta(1) (n=1) ]
4 递归式的时间复杂度分析
这里利用递归树的方法。具体在L2中解释,利用这个方法可以得到归并排序的时间复杂度为 [ O(nlgn) ] 可知归并排序在更大规模时比插入排序更优。
This post is licensed under CC BY 4.0 by the author.