算法打基础——算法基本分析
因为基础实在太差,决定从看算法导论视频+书开始重新打打基础,希望能坚持下来!!
第一节 算法基本分析
个人认为 本节的主要知识点有:
1 插入排序及其分析 2 算法复杂度基本符号 3 merge sort及其分析
1 插入排序及其分析
插入排序伪代码:
INSERTION-SORT (A, n) ⊳A[1 . . n]
for j ←2 to n
do key ←A[ j]
i ←j –1
while i > 0 and A[i] > key
doA[i+1] ←A[i]
i ←i –1
A[i+1] = key
排序算法的关键就是那个key,过程是,从第二个开始往后,将key元素插到前面的元素中去(注意:前面的元素永远都是排序过的元素),
找到比这个key小的停下来就ok了
2 算法复杂度基本符号
我们先介绍复杂度基本符号,然后再分析插入排序。 算法基本符号: big O ;big omega; big theta
f = O(g) 是说存在一个N,当n>N的时候有 f(n) < c * g(n),说明增长趋势不会超过g(n)的趋势 上界!
f = Ω(g) 是说存在一个N,当n>N的时候有 f(n) > c * g(n),说明增长趋势至少会有g(n)的趋势 下界!
f = Θ(g) 是说存在一个N,当n>N的时候有 c1 * g(n) < f(n) < c2 * g(n),说明增长趋势和g(n)一样 准确界!
然后我们来分析插入排序的复杂度:
插入排序的最差情况是当序列是逆序的时候,每个元素都要和前面所有的元素交换位置,
复杂度:
平均情况是当前序列期望的交换次数是前面元素的一半的时候,
复杂度:
3. merge sort 及其相关分析
merge sort的主要思想是分治法,将一个序列分到只有一个元素,然后再按一定规则合并,自然就排序了。其主要过程就是两个:分! 合!
伪代码如下:
MERGE-SORT A[1 . . n]
1. If n= 1, done.
2. Recursively sort A[ 1 . . low(n/2)]
and A[ up(n/2)+1 . . n ] .
3. “Merge” the 2 sorted lists.
然后是非常重要的merge过程:
merge 过程的伪代码非常的复杂,但是其叙述过程很简单,就是两个(已!排!序!)的序列,合并时去每个的头部,谁小就将其插
到结果序列中,删去改头部,重复这个过程,知道所有元素处理完毕!(merge sort实现还是蛮难的,值得一试)
merge sort 有趣的一点就是其复杂度分析(涉及到递归树)
2T(n/2)严格来说 应该是 T(up(n/2))+T(down(n/2))
则 归并排序的复杂度为
这个复杂度是用递推公式来表达的,当然可以用数学方法来求,但是这里我们可以用递归树来求!
Solve T(n) = 2T(n/2) + cn, where c > 0 is constant.
归并排序的复杂度是nlogn 而插入排序的复杂度是n^2, 但是插入排序处理小规模数据的时候速度还是很快的。据说当数据<30时
插入快于归并(原因?应该可以推的)
最后附上写的插入 和 归并排序的代码:
1 /////////////////////////CLRS video lec1 选择排序/////////////////////////////////////////////////// 2 // 3 // 已插入排序为主,还涉及到产生随机某个范围的数(时间种子); 4 5 #include<iostream> 6 #include<cstdlib> 7 #include<ctime> 8 #define random(x)(rand()%x) 9 10 using namespace std; 11 12 int main() 13 { 14 int a[100]; 15 clock_t start,finish; 16 double funtime; 17 srand((int)time(0)); 18 for(int i=0;i<100;i++) 19 a[i] = random(200); 20 int key,j; 21 start = clock(); 22 for(int i=1;i<100;i++) 23 { 24 key = a[i]; 25 j=i-1; 26 while(j>=0&&a[j]>key) 27 { 28 a[j+1] = a[j]; 29 j--; 30 } 31 a[j+1] = key; 32 } 33 finish = clock(); 34 for(int i=0;i<100;i++) 35 { 36 cout<<a[i]<<" "; 37 } 38 cout<<endl; 39 funtime=(double)(finish-start); 40 cout<<funtime<<endl; 41 return 0; 42 } 43 44
1 /////////////////////////CLRS video lec1 归并排序/////////////////////////////////////////////////// 2 // 3 4 5 #include<iostream> 6 #include<cstdlib> 7 #include<ctime> 8 using namespace std; 9 10 #define random(x)(rand()%x) 11 #define INF 0x3f3f3f3f 12 13 void merge(int* arr, int begin, int end) 14 { 15 int middle; 16 middle = (end+begin)/2; 17 int numl = middle - begin +1; 18 int numr =end -( middle+1) +1; 19 int* arrl = new int[numl+1]; 20 int* arrr = new int[numr+1]; 21 for(int i=0;i<numl;i++) 22 { 23 arrl[i] = arr[begin+i]; 24 } 25 arrl[numl] = INF; 26 for(int i=0;i<numr;i++) 27 { 28 arrr[i] = arr[middle+1+i]; 29 } 30 arrr[numr] = INF; 31 int recl = 0; int recr = 0; 32 for(int i=0;i<(end-begin+1);i++) 33 { 34 if(arrl[recl]<arrr[recr]) 35 { 36 arr[begin+i] = arrl[recl++]; 37 } 38 else{ 39 arr[begin+i] = arrr[recr++]; 40 } 41 } 42 } 43 44 45 46 47 void merge_sort(int* arr, int begin, int end) 48 { 49 int middle; 50 if(begin<end) 51 { 52 middle = (end + begin)/2; // 计算分割后的下标! 53 merge_sort(arr,begin,middle); 54 merge_sort(arr,middle+1,end); 55 merge(arr,begin,end); 56 } 57 } 58 59 60 int main() 61 { 62 srand(time(0)); 63 int i,j,k; 64 int a[100]; 65 cout<<"origin array: "; 66 for(i=0;i<100;i++) 67 { 68 a[i]=random(500); 69 cout<<a[i]<<" "; 70 } 71 cout<<endl; 72 73 merge_sort(a,0,100-1); 74 for(i=0;i<100;i++) 75 cout<<a[i]<<" "; 76 return 0; 77 78 } 79