一、算法和算法分析
什么是算法:
对特定问题的求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或多个操作。
算法的五个重要特性:
- 有穷性:一个算法必须总是(对任何合法的输入值)在执行有穷步之后结束,且每一步都可在有穷时间完成。
- 确定性:每一条指令必须有确切的含义,不会产生二义性。在任何条件下,相同的输入只能得出相同的结果。
- 可行性:算法中描述 的操作都可以通过已经实现的基本运算执行有限次来实现。
- 输入:有零个或多个的输入
- 输出:有一个或多个输出
算法设计的要求:
- 正确性
- 可读性
- 健壮性:当输入数据非法时,算法也能适当的做出反应或进行处理,不会产生莫名其妙的输出结果
- 高效率与低存储
算法效率的度量:
算法的执行时间需要依据该算法所编制的程序在计算机上运行所消耗的时间来度量,一般有两种方法:
事后统计的方法:
很多计算机内部都有计时功能,不同的算法的程序可通过一组或若干相同的统计数据以分辨优劣,例如:time ./a.out,但这种方法有两个缺陷,一是必须先运行依据算法编程的程序,如果程序不满足要求编写程序所耗费的人力物力就浪费了,二是所得时间的统计量依赖于计算机的硬件、软件等环境因素,有时容易掩盖算法本身的优劣,因此人们常常采用另一种事前分析法。
事前分析估算的方法:
一个用户高级程序语言编写的程序在计算机上运行所消耗的时间取决于下列因素:
1、依据算法先用何种策略,比如循环操作,可使用函数递归或for、while、do while等循环语句。
2、问题的规模,少量数据的问题求解、大规模数量的问题求解、海量数据的问题求解。
3、书写程序的语言,对于同一种算法,实现的语言级别越高,执行效率就越低。
4、编译程序所产生的机器代码的质量。
5、机器执行指令的速度,相同的编程语言,使用的编译器不同,产生的机器指令就会不同,从而执行的速度就会不同。
总结:同一个算法用不同的语言实现,或者用不同的编译器进行编译,或者不同的计算机上运行,效率均不相同,这表明使用绝对的时间单位衡量算法的效率是不合适的,抛开这些与计算机硬件、软件有关因素,可以认为特定算法“运行工作量”的大小,只依赖于问题的规模,或者说,它是问题规模的函数。
一个算法是由控制结构(顺序、分支、循环等3种基本结构)和原操作(指固有数据类型类型的操作)构成的,则算法时间取决于两者的统合效果,为了便于比较同一问题的不同算法,同学做法是,从算法中选取一种对于 所研究的问题来说是基本操作的原操作,以该基本操作重复执行的次数作为算法的时间量度。
所以:算法中基本操作重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记叙T(n)=O(f(n)),它表示问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称做算法的渐近时间复杂度,简称时间复杂度。
常见的时间复杂度有:
- O(1)
- O(log2N)/O(logN)
- O(N)
- O(NlogN)
- O(N^2)
- O(2^N)
注意:一般时间复杂度取的是一种大约情况不会精确到特别详细,也就是不会百分百正确。
最差时间复杂度:
数据的极端排序顺序会让算法执行效率最差的一种情况。
最优时间复杂度:
数据的极端排序顺序会让算法执行效率最优的一种情况。
平均时间复杂度:
数据的排序顺序队伍事物发展规律,算法执行效率接近真实的一种情况。
空间复杂度:
它代表随着问题规模n的某个函数f(n),它表示问题规模n的增大,算法所需要的存储空间增长率,被称为算法的空间复杂度。
二、查找算法
什么是查找算法:
在一个数据序列中,查找某个数据是否存在或存在的位置,在实际开发过程中使用的频率非常高,例如对数据常见的操作有增、删、改、查,增加数据时需要查询新增加的数据是否重复,删除数据时需要先查询到数据所在位置再删除,修改数据时也需要先查询到被修改的数据在什么位置,查找算法在编程中重要性排列在第一位。
顺序查找:
顺序表的顺序查找:
// 在顺序表中按照从前到后的顺序查找数据,如果找到则返回合法的下标,找不到则返回 -1
int linear_search(int* arr,size_t len,int key)
{
for(int i=0; i<len; i++)
{
if(arr[i] == key)
return i;
}
return -1;
}
链表的顺序查找:
// 在顺序表中按照从前到后的顺序查找数据,如果找到则返回所在节点的地址,找不到则返回NULL
Node* linear_search(Node* head,int key)
{
for(Node* n=head; NULL!=n; n=n->next)
{
if(n->data == key)
return n;
}
return NULL;
}
顺序查找的优点:
对数据的有序性没有要求,无论数据是否有序都可以查找。
对数据结构没有要求,无论是顺序表还中链式表都可以查找。
顺序查找的缺点:
查找速度相比其它查找算法慢,最优时间复杂度:O(1),最差时间复试度:O(N),平均时间复杂度:O(N)
二分查找:
数据序列必须有序,然后关键字key与中间数据比较,如果相等则立即返回,如果key小于中间数据,则只需要在中间数据左边继续查找即可,如果key大于中间数据,则只需要在中间数据右边继续查找即可,重复该步骤,直到找到关键字,或中间数据左右两边为空,则查找失败。
// 循环语句实现
int binary_search(int* arr, size_t len