本周知识要点:
3.1 C语言中的类型转换机制
3.2 整数次幂(高次数的快速计算)
3.3 筛选素数算法
1.C语言中的类型转换的简单介绍
1.1 (同为signed类型 或 unsigned类型)长整数转短整数
规则:丢掉高字节部分,只保留低位字节。长整数的值若在短整数的范围内,则转换结构保持不变。
1.2 短整数转长整数
规则:如果短整数带符号,则长整数高字节bit填充符号;否则填0
(unsigned的作用,仅在于赋更大的初值、转换时填充的符号位。)
1.3 小数转小数
规则:有效数字部分,保留高bit,丢掉低bit;指数部分,按整数形式转换。
1.4 整数转小数
规则:保留高位的bit作为有效数字,指数正常计算出多少位
1.5 小数转整数
规则:有效数字作为 long long型,按指数计算小数点位进行移动,这个过程会舍去小数或高位溢出部分(即:丢掉小数部分,对整数部分按整数转)
(最后其实都是看二进制的转换,以及这个类型给多少bit位置来进行保留)
2. 整数次幂问题 及其 算法设计与分析
问题描述:对于一个数进行n次方计算(不考虑数值溢出等问题),如果设计算法使得计算最快。
2.1 (最直观的算法)算法一:
思路:直接用n重循环进行 n次乘法可得
int way_one(int x, int n)
{
int a = x;
for (int i = 1;i < n;i++)a = a*x;
return a;
}
易得 时间复杂度。
2.2 (递归)算法二:
思路:每一次得到,假如n是偶数则直接由相乘可得,如果n是奇数则由 相乘 再乘x得。
最后递归的边界条件是 x一次方 返回自己。
int way_two(int a, int x, int n)
{
if(n == 1) return x;
else
{
if(n%2 ==0)return way_two(a,x,(n/2))*way_two(a,x,(n/2));
else return way_two(a,x,(n-1)/2)*way_two(a,x,(n-1)/2)*a;
}
}
因为每一次递归都大约是计算的一半 所以
2.3 (非递归)算法三:
思路:由递归算法可得到启发,把n次方写成二进制的形式就可以轻松得到是 一个简单的循环公式。如2的10次方可写成2的(2+8)次方,所以 我们只需要让 第1次循环 和第3次循环 相乘即可。
int way_three(int x,int n)
{
int result = 1;
for(int i = 0;n!=0; n = n/2)
{
// 判断是否现在的二进制是否是1
if(n%2 == 1) result *=x;
x =x*x;
}
return result;
}
n次循环大约被分成很多个2,是计算的很多个一半, 所以
2.4 (无法正确实现)算法四:
思路: 用尽量少的步骤得到目的数次方,得需要穷举搜索一遍得到路径 再由路径去得到次方数,穷举搜索就已经耗费很多计算量所以无法正确实现。(个人认为)
2.5 扩展,由乘法到加法,用最少的加法得到一个多项式的定值计算——秦九韶算法
秦九韶算法介绍:https://baike.baidu.com/item/%E7%A7%A6%E4%B9%9D%E9%9F%B6%E7%AE%97%E6%B3%95/449196?fr=aladdin
3. 筛素数问题 及其 算法设计与分析
问题描述:
问题一:判断一个数n是否是素数
问题二:筛选正整数n之前的素数,并输出出来
问题一就不再多说,可以遍历之前去整除,应该是目前常用的算法,现在就问题二进行算法设计
3.1 算法一:
思路:用前面的素数 去筛去后面他的整数倍,比如在n个之中,从2开始 往后删,每遇到一个没被删的由此开始又继续想后删除
算法设计,两重循环,第一重遍历整个n,第二重如果遍历n的同时遇到未删除的情况就开始由此往后删除。
#include<stdio.h>
int main()
{
int n = 1000; // 筛选n之前的素数
// 生成整数n之前的数组,作用是用来标记是否被筛走
int a[n+1];
for(int i = 1;i<=1000;i++)a[i] = i;
for(int i = 2; i <= n;i++)
{
if(a[i] != -1)
{
printf("%d\n",a[i]);
for(int k = 2;k*i <= n;k++)
{
a[k*i] = -1;
}
}
}
}
算法分析,利用欧拉级数定理可求得。,参考维基百科:https://en.wikipedia.org/wiki/Proof_of_the_Euler_product_formula_for_the_Riemann_zeta_function