常用算法设计技巧

来源:互联网 发布:php会员信息管理系统 编辑:程序博客网 时间:2024/05/04 14:39

1.贪心算法

实例:Dijkstra算法,Prim算法,Kruskal算法,调度(最小化平均完成时间),哈夫曼编码,装箱算法

哈夫曼编码采用最小堆实现时,运行时间为O(C log C),采用简单链表为O(C^2)。在ASCII字符集的情况下,C足够小,这使得二次时间可以接受,这样的应用中实际上所有的运行时间都将花费在读进输入文件和写出压缩文件所需要的磁盘I/O上。

2.分治算法

实例:最大子序列和,平面几何最近点,树递归遍历,归并排序,快速排序,快速选择

分治算法的运行时间方程可归结为 : T(N)=aT(N/b)+Θ(N^k)。

最近点问题可将点集按照x坐标和y坐标排序,将点集按x分为两半,PL和PR,分别计算dL、dR和dC,dC时间为O(N),因此总时间为O(NlogN)。

整数相乘(两个八位整数X,Y)常规是O(N^2)。


有4次相乘,将问题缩小为(N/2)。四次相乘可以减少为3次:


由此,T(N)=3T(N/2)+O(N)=O(N^1.59)。

矩阵乘法常规为Ω(N^3),代码如下。

matrix<int> operator*(const matrix<int>& a,const matrix<int>& b){    int n=a.numrows();    matrix<int> c(n,n);    int i;    for(i=0;i<n;i++)        for(int j=0;j<n;j++)            c[i][j]=0;    for(i=0;i<n;i++)        for(int j=0;j<n;j++)            for(int k=0;k<n;k++)                c[i][j]+=a[i][k]*b[k][j];    return c;}
可采用Strassen方法降阶。


3.动态规划

实例:用表代替递归,矩阵乘法的顺序安排,最优二叉查找树,有向图中所有点对最短路径(稠密图)

将递归算法重新写成非递归算法,可以把子问题的答案系统地记录在一个表中,利用这种方法的一种技巧称为动态规划。

计算fibonacci数列的递归和动态规划代码:

int fib(int n){    if(n<=1)        return 1;    else        return fib(n-1)+fib(n-2);}int fibonacci(int n){    if(n<=1)        return 1;    int last=1;    int nextToLast=1;    int answer=1;    for(int i=2;i<=n;i++)    {        answer=last+nextToLast;        nextToLast=last;        last=answer;    }    return answer;}
最优二叉查找树公式如下O(N^3),可优化为O(N^2):

所有点对最短路径(稠密图)公式O(N^3):

代码:

void allPairs(matrix<int>& a,matrix<int>& d,matrix<int>& path){    int n=a.numrows();    //initialize d and path    for(int i=0;i<n;i++)        for(int j=0;j<n;j++)        {            d[i][j]=a[i][j];            path[i][j]=-1;        }    for(int k=0;k<n;k++)        //consider each vertex as an intermediate        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                if(d[i][k]+d[k][j]<d[i][j])                {                    //update shortest path                    d[i][j]=d[i][k]+d[k][j];                    path[i][j]=k;                }}


4.随机化算法

实例:跳跃表,随机素性测试

生成随机数的代码:

static const int A=48271;static const int M=2147483647;//2^31-1static const int Q=M/A;static const int R=M%A;class Random{public:    explicit Random(int initialValue=1);    int randomInt();    double random0_1();    int randomInt(int low,int high);private:    int state;};//Construct with initialValue for stateRandom::Random(int initialValue){    if(initialValue<0)        initialValue+=M;    state=initialValue;    if(state==0)        state=1;}//period M-1int Random::randomInt(){    int tmpState=A*(state%Q)-R*(state/Q);    if(tmpState>=0)        state=tmpState;    else        state=tmpState+M;    return state;}double Random::random0_1(){    return (double)randomInt()/M;}int Random::randomInt(int low,int high){    if(low>high)        return -1;    return randomInt()%(high-low+1)+low;}
跳跃表:以O(logN)期望支持查找和插入。

素性测试:随机化方法极快,偶尔会出现错误的判断,但这种机会非常小,足可忽略。

5.回溯算法

实例:公路收费点重建问题(O(N^2 * logN)),博弈(极大极小策略,α-β裁剪)



原创粉丝点击