快捷搜索:  汽车  科技

c语言的算法总结(算法基础C语言描述)

c语言的算法总结(算法基础C语言描述)void hello(int n){ int a b c; if(n>1){ hello(n-1); } printf("%d\n" n) } S(n) = O(n)每次递归调用,都会为方法开辟一块内存空间,虽然每块内存空间中都有a b c三个整数,但是他们与问题规模没有关系,所以空间复杂度为O(n) // n 占 4个字节 void hello(int n){ //flag占4n²个字节 int flag[n][n]; //temp占4n个字节 int temp[n]; //i占4个字节 int i; } S(n) = 4 4n² 4n 4 =

c语言的算法总结(算法基础C语言描述)(1)

什么是算法
  • 算法是为了解决问题需要遵守、被明确指定的指令的集合。
  • 很多人说程序的本质是算法,就是因为程序的本质也是为了解决问题而使用的需要遵守、被明确指定的指令的集合。
使用算法需要考虑的问题(时间&空间)
  • 如果一个算法是可行的,我们接下来要考虑的往往是算法的效率。比如说如果一个算法虽然可以解决问题,但是却要耗费很长的时间或不合理的内存空间,那这种算法其实也意义不大。
时间复杂度
  • 大O表示法

/* * 这是一个简单的单循环算法 * n 表示循环的规模 =〉问题规模 */ void hello(int n){ int i = 1; //用 i 表示其与 n 的关系为 i<=n while(i<=n){ printf("你叫什么名字?你玩过吃鸡吗?\n" i); i ; } printf("废话,I'm a box on the ground"); }

  • 假设 n 为 100,可以得到一个表达式为:T(100) = 1 101 2 * 100 1其中 T 表示单位时间成本 n 表示问题规模 T(n) = 时间复杂度第一个常数 1 表示 int i = 1;在程序中执行的次数。第二个常数 101 表示 while 判断执行的次数。后面依次类推.....最终得到一个详细的算法时间开销
  • 我想我已经可是使用上述方法去计算算法时间复杂度了,但是现在我遇到了一个问题:我可能需要写一段很长很长的代码,如果我还用这种逐行去数的方式去计算实在显得有点不切实际。所以现在我的脑袋里浮现出了两个问题。如果一个算法有上千行的代码,难不成我也要一行一行地去数?我是否可以忽略某些部分,只关注代码中影响时间复杂度的最重要部分?
  • 能!首先我们将 T(100) 中的 100 仍然使用代数 n(表示规模) ,可得 1 101 2 * 100 1 = 3n 3对于程序而言,运算阶数低的部分的时间开销往往可以忽略不计,只保留阶数最高的部分(好读书不求甚解,可以先这么理解),于是乎哈哈得到 3n,最后还是由于好读书不求甚解的原因,当 n 变得足够大时,常数项往往可以忽略不计,遂得到 3n = n最后用大O表示法得到当前算法的时间复杂度为 T(n) = O(n)
算法的时间复杂度

O(1) < O(log2n) < O(n) < O(nlog2n) < O(n²) < O(n³) < O(2ⁿ) < O(n!) < O(nⁿ)
常 < 对 < 幂 < 指 < 阶

示例
  • 嵌套循环

/* * 这是一个简单的嵌套循环算法 * n 表示循环的规模 =〉问题规模 */ void hello(int n){ int i = 1; //用 i 表示其与 n 的关系为 i<=n while(i<=n){ printf("你叫什么名字?你玩过吃鸡吗?\n" i); i ; //内层循环次数以及循环几轮取决于 n 的值,所以共执行n²次 for(int j = 0; j < n; j ){ printf("如果你玩吃鸡的话,我们可以组团吃鸡。\n"); } } printf("废话,I'm a box on the ground");

得到 T(n) = O(n) O(n²) 取最高阶的部分得出 T(n) = O(n²)

  • 单次循环、 i 倍次递增

/* * 这是一个简单的循环算法 * n 表示循环的规模 =〉问题规模 */ void hello(int n){ int i = 1; //用 i 表示其与 n 的关系为 i<=n while(i<=n){ printf("你叫什么名字?你玩过吃鸡吗?\n" i); i = i * 2; } printf("废话,I'm a box on the ground"); }

得到 T(n) = O(log2n)
log2n: 假设 n = 8 8的对数为3 ,2³ = 8。由于2³ 1 > 8,所以循环退出,最终循环一共执行了 3 次,3 = log2(8),结果 T(n) = log2n

  • 遍历查找算法

/* * 这是一个简单的遍历查询算法 * n 表示循环的规模 =〉问题规模 */ void hello(int flag[] int n){ int i = 0; printf('find n\n') //用 i 表示其与 n 的关系为 i<=n while(i<n){ if(flag[i]==n){ printf("find it,厉害,值:%d\n" flag[i]); break; } i ; } }

最好的情况:数组中第一个元素就是要查找的值 T(n) = O(1) 一般不采用
最坏的情况:数组中最后一个元素才是目标元素 T(n) = O(n)
平均情况:假设n在任意一个位置的概率相同 T(n) = O(n)
* 平均情况复杂度计算公式
* 循环次数x = (1 2 3 4 ... n) * 1/n = (n(1 n)/2)*1/n = 1 n/2
* T(n) = O(x) = O(n)

空间复杂度

空间与问题规模的关系

示例
  • 循环递增

void hello(int n){ int i = 1; while(i<=n){ printf("你见过凌晨4点的洛杉矶吗?%d\n" i); i ; } printf("我没见过,但是我见过凌晨4点网吧,凌晨4点烧烤摊,还有凌晨四点的召唤师峡谷\n"); }

i&n都是内存中固定的常量,所以无论程序执行时i怎样变化,原地工作,复杂度都为O(1)
S(n) = O(1)

  • 单个数组

// n 占 4个字节 void hello(int n){ //flag占4n个字节 int flag[n]; //i占4个字节 int i; }

变量占用的空间相加 S(n) = 4 4n 4 = 4n 8 = O(n)

  • 二维数组

// n 占 4个字节 void hello(int n){ //flag占4n²个字节 int flag[n][n]; //temp占4n个字节 int temp[n]; //i占4个字节 int i; }

S(n) = 4 4n² 4n 4 = 4n² 4n = O(n²)
取最高阶 4n²

  • 递归

void hello(int n){ int a b c; if(n>1){ hello(n-1); } printf("%d\n" n) }

S(n) = O(n)
每次递归调用,都会为方法开辟一块内存空间,虽然每块内存空间中都有a b c三个整数,但是他们与问题规模没有关系,所以空间复杂度为O(n)

  • 递归&数组

void hello(int n){ int flag[n]; if(n>1){ hello(n-1); } printf("%d\n" n) }

与上面相反,此处会有一个与问题规模关联的数组,所以代入一个等差数列 1 2 3 ... n = n(1 n)/2 = 1/2 * n² 1/2 * n
忽略常数项,取最高阶可得 T(n) = S(n²)

猜您喜欢: