数据结构与算法分析 第二章

数据结构与算法分析(C语言描述)是一本比较全面的算法书籍。我将对书中内容结合其他知识进行总结。

首先,算法(algorithm)是为求解一个问题需要遵循的,被清楚地指定的简单指令的集合。

切记,一个需要1G字节内存的算法是没用的(我做web开发时,自己写的算法总是导致页面崩溃,血的教训啊)。

贯穿全文的四个数学定义:

定义1:如果存在正常数cn0使得当N>=n0T(N)=<cf(N),则记为TN= OfN));(大O)即T(N)的增长率小于等于f(N)的增长率。

定义2:如果存在正常数cn0使得当N>=n0T(N)>=cg(N),则记为T(N)=Ω(g(N));T(N)的增长率大于等于gN)的增长率。

定义3TN=thetah(N))当且仅当T(N)=O(h(N))T(N)=(h(N));T(N)的增长率等于hN)的增长率。

定义4:如果对所有的常数c存在n0使得当N>n0TN<cp(N),则记为TN=oPN))(小o);TN)的增长率小于P(N)的增长率。

大O和小o区别在于大O包含增长率相同这种可能性。

更重要的是要记住下面的三个法则:

法则1:如果T1N=Of(N)),T2N=OgN)),那么

T1N+T2N= OfN+gN)),T1N*T2N=OfN*g(N)

法则2:如果T(N)是一个k次多项式,则T(N)和N的k次方增长率相等。

法则3:对于任意常数k,以2为底N的对数的k次方=O(N)。它告诉我们对数的增长的非常缓慢



运行时间计算的一般法则:

法则1for循环,一个for循环的运行时间至多是该for循环内语句(包括测试)的运行时间乘以迭代的次数。

法则2:嵌套循环,从里向外分析这种循环,在一组嵌套循环内部的一条语句总得运行时间为该语句的运行时间乘以该组所有循环的大小得乘积。

 for(int i =0; i < n; i++)

        for(int j = 0; j < n; j++)

             K++

该程序为O(N*N

法则3:顺序语句 将各个语句的运行时间求和。

forint i = 0; i < n; i++

      a [i] = 0;

for(i = 0; i < n; i++)

   for(int j = 0; j < n; j++)

              a [i] = a[i-1]+a[i-2];

总量为O(N*N);

法则4If/Else语句,对于程序片段

ifcondition

   S1

else

   S2

一个if/else 语句的运行时间从不超过判断再加上S1S2中运行时间较长者的总得运行时间。

分析的基本策略是从内部(或最深层部分)向外展开工作。

最大子程序和问题的解

算法1

int maxSubsum1(const vector<int>& a)

{

  int maxSum = 0;

  

  for(int i = 0; i < a.size(); i++)

      for(int j = i; j < a.size(); j++)

      {

      int thisSum = 0;

  for(int k = i; k <= j; k++)

     thisSum += a[k];

 

  if(thisSum > maxSum)

      maxSum = thisSum;

  }

    return maxSum;

}

分析算法一可以得到O(N*N*N

算法二

int maxSubsum1(const vector<int>& a)

{

  int maxSum = 0;

  

  for(int i = 0; i < a.size(); i++)

      for(int j = i; j < a.size(); j++)

      {

      int thisSum = 0;

  thisSum += a[j];

  

  if(thisSum > maxSum)

     maxSum = thisSum;

  }

    return maxSum;

}

T(N)=O(N*N

算法三

算法三采用一种递归和相对复杂的解法(NlogN),该方法采用分治(divide-and-conquer)策略。其想法是把问题分成两个大致相等的子问题,然后递归地对他们求解,这是“分”的部分,“治”阶段将两个子问题的解合并一起并可能再做少量的附加工作。最后得到整个问题的解。

int maxSumRect(const vector<int>& a, int left, int right)

{

     if(left == right)

    if(a[left] > 0)

   return a[left];

else

   return 0;

int center = (left + right) / 2;

int maxLeftSum = maxSumRect(a, left, center);

int maxRightSum = maxSumRect(a, center+1, right);

int maxLeftBorderSum = 0, leftBorderSum = 0;

for(int i = center; i >= left; i--)

{

   leftBorderSum += a[i];

   if(leftBorderSum > maxLeftBorderSum)

        maxLeftBorderSum = leftBorderSum;

}

int maxRightBorderSum = 0, rightBorderSum = 0;

for(int j = center + 1; j <= right; j++)

{

    rightBorderSum += a[j];

if(rightBorderSum > maxRightBorderSum)

     maxRightBorderSum = rightBorderSum;

}

return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);

}

有程序分析可以得到:T(N)=O(NlogN)

算法四

int maxSubSum4(const vector<int>& a)

{

    int maxSum = 0,thisSum = 0;

for(int j = 0; j < a.size(); j++)

{

     thisSum += a[j];

 if(thisSum > maxSum)

    maxSum = thisSum;

 else if(thisSum < 0)

    thisSum = 0;

}

return maxSum;

}

分析可以得到T(N)=O(N)

运行时间中得对数

对数最常出现的规律可概括为下列一般的法则

如果一个算法用常数时间ON)将问题的大小削减为某一部分(通常是1/2,那么该算法就是OlogN

如果使用常量时间只是把问题减少一个常数的数量(例如将问题减少1),那么这种算法就是ON

Example1:二分搜索(binary search

template <typename Comparable>

int binarySearch(const vector<Comparable>& a, const Comparable& x)

{

    int low = 0,high = a.size - 1;

while(low <=high)

{

     int mid = (low + high)/2;

 

 if(a[mid] < x)

    low = mid + 1

 else if(a[mid] > x)

    high = mid - 1;

else 

    return mid;

}

return -1;

}

Example 2  欧几里得算法 

计算最大公因数的欧几里得算法。

long gcb(long m, long n)

{

    while(n != 0)

{

    long rem = m%n;

m = n;

n = rem;

}

return m;

}

幂运算

long pow(long x, int n)

{

     if( n == 0)

 return 1;

 if( n== 1)

 return x;

 if(isEven(n))

    return pow(x*xn/2);

 else

     return pow(x*x, n/2)*x;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值