数据结构学习笔记1(算法分析)
2014-02-13 15:05
176 查看
一 最大子序列和问题
本来眼高手低想着书上的例子都给了伪代码并且自己理解了准备直接翻过例程,后来想着这么简单不如试试,咳咳,试了将近两个小时....《数据结构与算法分析》P20,P21的算法实现
#include "stdio.h" int Maxsum(const int a[],int N); int MaxSUM(const int a[],int Left,int Right); int Max3(int,int,int); int main(void) { int a[8]={4,-3,5,-2,-1,2,6,-2}; int n=sizeof(a)/sizeof(int); int Max=Maxsum(a,n); int Max2=MaxSUM(a,0,n-1);//这里边界是n-1 printf("%d\n",Max); printf("%d\n",Max2); return 0; } int Maxsum(const int a[],int N) { int Max=0,ThisMax=0; for (int i=0;i<N;i++) { ThisMax+=a[i]; if (ThisMax>Max) { Max=ThisMax; } } return Max; } MaxSUM(const int a[],int Left,int Right) { int Maxleft,Maxright; int Borderleft,Borderright,ThisMax; int n,i; if (Left==Right) { if(a[Left]>0) return(a[Left]); else return 0; } n=(Left+Right)/2; Maxleft=MaxSUM(a,Left,n); Maxright=MaxSUM(a,n+1,Right); ThisMax=Borderleft=0; //for (i=Left;i<=n;i++)//这里出错 for(i=n;i>=Left;i--) { Borderleft+=a[i]; if (Borderleft>ThisMax) { ThisMax=Borderleft; } } Borderleft=ThisMax; ThisMax=Borderright=0; for (i=n+1;i<=Right;i++)//出错 { Borderright+=a[i]; if (Borderright>ThisMax) { ThisMax=Borderright; } } Borderright=ThisMax; //return Max3(Borderleft,Borderright,Maxleft+Maxright); return Max3(Borderleft+Borderright,Maxleft,Maxright); } int Max3(int a,int b,int c) { int temp; temp=(a>b?a:b); temp=(temp>c?temp:c); return temp; }
调试过程中出错如下:
1MaxSUM计算边界(a,0,n-1)习惯性写为n,这里是对a数组进行访问,下标界限为n-1
2计算Borderleft这里是先二分计算左边四个数的最大和Maxleft和右边的Maxright,Border是一定要有a
这个数,所以应该从n开始自减
3计算Borderright的i应该从n+1开始
算法分析:
第一种方法是联机算法,只对数据进行一次扫描,一旦a[i]被读入并被处理就不再需要被记忆。若数组在磁盘或磁带上,就可以顺序读入,主存中不必存储数组的任何部分。这里其实作者思维比较好理解:通过Max只记录某个区段的最大和
第二种方法时间复杂度为O(NlogN),有点二分的意思,比较好理解。但是如果深思,发现
Maxleft=MaxSUM(a,Left,n);
Maxright=MaxSUM(a,n+1,Right);
这里的递归调用,如果把整个程序的时间复杂度表示为T(N),这里就是T(N/2)。若a数组有32个元素,则要计算左边16个的Maxleft和右边16个Maxright、以及分别包含第16、17元素的Borderleft和Borderright。以计算Maxleft为例,调用MaxSUM(a[32],0,15),需要再分别计算16个元素的Maxleft、Maxright、Borderleft+Borderright;这里面又包含了左8个右8个元素的递归....以此类推。
所以书上也说对于递归调用不必一步一步分析清楚每一步的具体计算,只需要满足四条基本法则即可。易知,上述递归调用中没有做重复性工作。
二 时间复杂度分析中的对数问题
法则:如果一个算法用常数时间O(1)将问题大小削减为其中一部分(常为1/2),则该算法就是O(logN)常包含在对分查找、欧几里得算法、幂运算中
对分查找代码:
int Low=0,High=n-1; if(Low==High) return A[Low]; while(Low<High) { Mid=(Low+High)/2; if (A[Mid]>X) High=Mid; else if (A[Mid]<X) Low=Mid; else return Mid; }
对分查找一次比较(调试没问题,不知道原理正确不)
#include "stdio.h" int main(void) { int a[]={2,4,5,7,8,9,11}; int b[]={2,4}; int n1=sizeof(a)/sizeof(int); int n2=sizeof(b)/sizeof(int); int low=0,high=n1-1,mid,x=4; while (low<=high) { mid=(low+high)/2; if (x<=b[mid]) { high=mid; } else low=mid+1; if (high==low) { break; } } if (a[high]==x) { printf("%d\n",high); } else printf("0\n"); return 0; }
欧几里得算法(用于求最大公约数)
unsigned int tmp; while(N>0) { tmp=M%N; M=N; N=tmp; } return M;
幂运算 就是计算X的N次方,利用递归每次计算X的N/2次方
3
埃拉托斯特尼筛法
(这个gif的图片不能在csdn上显示?)
eratosthenes筛是一种用于计算小于N的所有素数的方法,如图的表中,先找出最小的整数i,打印出来,删除i,2i,3i,...直到N;然后i递增至i>N^(1/2)结束,将剩下的没有删除的数打印出来,算法终止。算法实现起来很简单,具体原理可参见http://zh.wikipedia.org/zh-cn/%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89%B9%E5%B0%BC%E7%AD%9B%E6%B3%95
该算法时间复杂度为O(N*loglogN),问题是:怎么算的?
三 课后习题选解
2.19算法的基本思想是基于以下基础:如果N是偶数,那么只有元素a的个数大于N/2+1才能成为主要元素,即不可能a?a?……这么重复下去出现a是主要元素的结果,算法思想也就有了基础;如果N是奇数,那么必然主要元素个数>=(N/2+1),这种情况下首先对前N-1个数进行处理,如果B中有candidate,那么A中最后一个元素不影响B的结果,如果B中没有candidate那么可以把第N个元素放入数组B中。
在递归过程中,B里面只有2个或者少于2个的元素时递归结束。这是为了避免出现两个元素个数相等的情况,但是也只能出现这种特殊情况。否则,B中有一个元素,只需进行遍历比较;B中没有元素则返回。
易知每次递归循环数组长度减半,则T(N)=T(N/2)+O(N)所以递归的时间复杂度是O(N*logN)。后面的遍历比较时间复杂度为O(N),又因为是顺序执行,所以程序在不考虑输入情况下时间复杂度为O(N*logN)。
程序如下:
问题list:
1 int *A1后即使A1=(int *)malloc(sizeof(A)); A1还是一个指针,只不过能当做数组来用。但是在调试过程中单看A1,值就是A1[0];但是A1[3]也有意义。
2 sizeof(A1)就是A1的大小,A1是指针,大小就是其指针类型所占字节数
3 memcpy()第三个参数大小应该是复制的字节数,不是int型的个数(在这里栽了大跟头!!!)。详细内容参考/article/1441612.html
#include "stdio.h" #include "string.h" #include "stdlib.h" int MajorEle(int A[],int n); int main(void) { int A[]={3,3,4,2,4,4,2,4,4,5}; int *A1; int m,n,j,k,i,a,b; n=sizeof(A)/sizeof(int); A1=(int*)calloc(n,sizeof(int)); memcpy(A1,A,n*sizeof(int)); m=MajorEle(A,n); if (m==0) printf("There is no major element.\n"); else if (m==1) { j=A[0]; k=0; for (i=0;i<n;i++) { if(j==A1[i]) k++; } if(k>=n/2+1) printf("The major element is %d.\n",j); else printf("There is no major element.\n"); } else if(m==2) { a=b=0; j=A[0]; k=A[1]; for (i=0;i<n;i++) { if(j==A1[i]) a++; if(k==A1[i]) b++; } if(a>=n/2+1) printf("The major element is %d.\n",j); else if(b>=n/2+1) printf("The major element is %d.\n",k); else printf("There is no major element.\n"); } free(A1); return 0; } int MajorEle(int A[],int n) { int i,m=0; bool flag=false; int *B; if (n%2==0) { B=(int *)malloc(n/2*sizeof(int)); for (i=0;i<n;i=i+2) if (A[i]==A[i+1]) { B[m]=A[i]; m++; } } else { B=(int *)calloc((n/2+1),sizeof(int)); printf("B_space=%d\n",sizeof(B)); for (i=0;i<n;i=i+2) { if (A[i]==A[i+1]) { B[m]=A[i]; m++; flag=true; } } if (flag==false) { B[m]=A[n-1]; m++;//这里如果没有m++则下面赋值不成功 } } memcpy(A,B,m*sizeof(int));//这里应该是字节数 for (i=0;i<m;i++) { printf("%d\n",A[i]); } if (m<=1) { free (B); return m; } else { n=m; MajorEle(A,n); } }话说这么简单的程序我竟然写了将近两个半小时!!!太水,基础概念掌握不牢固。平时贪玩,有些基础知识应该回顾的。
2.7.3 http://dl.acm.org/citation.cfm?id=315746&bnc=1页面的pdf文件可以作为参考
相关文章推荐
- 数据结构与算法学习笔记之 复杂度分析
- 数据结构和算法分析学习笔记(三)--二叉查找树的懒惰删除(lazy deletion)
- 数据结构学习笔记0——算法分析
- 算法设计和数据结构学习_3(《数据结构和问题求解》part2笔记)
- C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】
- TensorFlow学习笔记之源码分析(1)----最近算法nearest_neighbor
- 一步步学习数据结构和算法之堆排序效率分析及java实现
- [置顶] TensorFlow学习笔记之五——源码分析之最近算法
- C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】
- C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法
- 算法分析学习笔记(一) - 动态连通性问题的并查集算法(上)
- 数据结构与算法学习笔记之高效、简洁的编码技巧“递归”
- 算法导论17:摊还分析学习笔记(KMP复杂度证明)
- 机器学习笔记五 - 生成学习算法、高斯判别分析、朴素贝叶斯、拉普拉斯平滑
- 一步步学习数据结构和算法之快速排序效率分析及java实现
- 数据结构与算法学习笔记——数组
- 算法设计技巧和分析学习笔记1 (归纳法、分治和动态规划)
- opencv学习笔记2——surf算法demo中find_obj分析
- TensorFlow学习笔记 - TensorFlow数据结构分析
- 算法学习笔记一---如何进行算法分析&渐近符号介绍