对于判断一段代码的数据规模很多时候是可以看到捷径的比如有两个n循环,其中后面一个循环和n是成正相关,此时前一个n和后一个n相互嵌套,所以此时的数量级上表示应该是O(n^2)级别。
但是会有的时候后还是有特例的 比如两个嵌套,中间嵌套层并没有出现n,只是一个常数,此时就不能一概而论的认为应该是O(n^2)级别复杂度的代码。
利用二分查找法寻找判断O(nlogn) 级别算法的数据规模,以下为例:
#include "binarySearch.h"
int binarySearch(int arr[],int n,int target){
int l = 0,r = n-1;
while(l<=r){
int mid = l + (r-l)/2;
if(arr[mid] == target ) return mid;
if(arr[mid] > target) r = mid;
else l = mid +1;
}
return -1;
}
每一次查找都是在寻找到的结果中的一半的结果中查找,如果能够找到结束,没有办法找到的话就是在1/2,1/4....中查找,这正好是对数的定义。所以这种层次就是对数级别的数量级函数查找。
对于Log10和Log2的数量级之间能够相差多少呢?其实在高中教材中关于对数的推导有着相关的公式,两者之间只是常数级别的差距。所以这个对数的底并不是很重要所以简单的忽略掉这个对数的底,就可以统一的成为O(nlogn)。
我们可以根据这个复杂度做出相关的实验:
我们会遇到这种情况:我们以为自己写出了一个O(Logn)级别的算法,但是,实际上却是O(n^2)级别的算法,很多时候在线判题的网站就会产生问题。
为了解决这个问题,这时就需要观察实验趋势,将数据规模提高两倍看时间的变化。
测试规模为O(logn)级别的测试使用代码:
namespace MyAlgorithmTester{
//O(logN)
int binarySearch(int arr[]){
int l = 0,r = n-1;
while( l<=r){
int mid = l + (r-l)/2;
if( arr[mid]==target) return mid;
if( arr[mid]>target) r = mid -1;
else l = mid+1;
}
return -1;
}
}
这是一个简单的O(Logn)级别的算法 对于基础的算法规模来说这是一个非常好理解的低数量级的代码;
int main(){
//数据规模倍乘测试findMax
//O(n)
for(int i = 10; i<= 26;i++){
int n = pow(2,i);
int *arr =MyUtil::generateRandomArray(n,0,1000000000);
clock_t startTime = clock();
MyAlgorithmTester::findMax(arr,n);
clock_t endTime = clock();
cout<<"data size 2^"<<i<<" = "<<n<<"t";
cout<<"Time cost:"<<double(endTime-startTime);
delete[] arr;
}
}
根据我们获得的信息将各种数据规模的算法依次进行排列 我们可以得到很多个结果:
获得的结论如下:
1)每一行的结果都比上一行的数据结果翻了两倍,也就是说数据规模每增加一个数量级就会在时间上增加一倍;
2)由此可以看出这个数据规模是O(n)级别;
然后我们看一个O(n^2)级别的算法:
int main(){
//数据规模备乘测试selectionSort
//O(n^2)
cout<<"Test for selectionSort:"<<endl;
for(int i = 10; i<=15; i++){
int n = pow(2,i);
int *arr = MyUtil::generateRandomArray(n,0,100000000);
clock_t startTime = clock();
MyAlgorithmTester::selectionSort(arr,n);
clock_t endTime = clock();
cout<<"data size 2^"<<i<<"="<<n<<"\t";
cout<<"Time out:"<<double(endTime-startTime)/CLOCKS_PER_SEC<<endl;
delete[] arr;
}
return 0;
}
由于O(N^2)这个数量级太高了所以我们只运行到15这个数;
得出的结果如下图所示:
因为我们所使用的是O(n^2)这个级别 所以我们获得的结果也应该是下面的结果是上面的4倍。
结论:将顺序查找问题转换为二分查找的问题使用效率会大大提升。