一、折半查找的定义
折半查找(二分查找)是一种常用的查找算法,它要求待查找的数据结构必须是有序的。
其实现过程如下:
int binary_search(int arr[], int left, int right, int target) { while(left <= right) { int mid = (left + right) / 2; if(arr[mid] == target) return mid; if(arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; }
二、折半查找的时间复杂度与时间复杂度分析
常见的算法时间复杂度分别有O(1), O(logn), O(n), O(nlogn), O(n²), O(n³)等。
而折半查找的时间复杂度为O(logn),也就是说它属于时间复杂度比较小的算法,适用于大数据量的快速查找。
下面从多个方面来详细阐述折半查找的时间复杂度。
三、折半查找的时间复杂度与数据规模
折半查找的时间复杂度与数据规模有关,具体表现为:
当数据规模n增大时,时间复杂度O(logn)的速度要比O(n)快,因为O(logn)的增长速度是比O(n)慢的。
如下面的示例所示,随着数据规模的增大,折半查找算法与普通查找算法的时间复杂度对比:
#include <stdio.h> #include <stdlib.h> #include <time.h> int search(int arr[], int len, int target) { for(int i = 0; i < len; i++) { if(arr[i] == target) return i; } return -1; } int binary_search(int arr[], int left, int right, int target) { while(left <= right) { int mid = (left + right) / 2; if(arr[mid] == target) return mid; if(arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; } int main() { int len = 100000000; int* arr = (int*)malloc(len * sizeof(int)); for(int i = 0; i < len; i++) arr[i] = i; int target = len - 1; clock_t start, end; int ret; start = clock(); ret = binary_search(arr, 0, len - 1, target); end = clock(); printf("binary_search: %d, time: %fs\n", ret, (double)(end - start) / CLOCKS_PER_SEC); start = clock(); ret = search(arr, len, target); end = clock(); printf("search: %d, time: %fs\n", ret, (double)(end - start) / CLOCKS_PER_SEC); free(arr); return 0; }
当数据规模为100000000时,折半查找算法的耗时只有0.001秒,而普通查找算法的耗时却为4.737秒。
四、折半查找的时间复杂度与查找时间
在平均时间复杂度为O(logn)的前提下,折半查找算法的查找时间比较快,因为它每次可以将查找范围缩小为原来的一半。
而在最坏情况下,折半查找的时间复杂度O(logn)也会失效,比如当查找的关键字不在序列中时,折半查找会一直循环到我查找范围为空,这时它的时间复杂度将达到O(n)。
下面的示例程序中,为了让折半查找失效,我将查找目标设置为0xFFFFFFF(因为序列中最大的数为0x7FFFFFFF,所以它不可能在序列中):
int binary_search(int arr[], int left, int right, int target) { while(left <= right) { int mid = (left + right) / 2; if(arr[mid] == target) return mid; if(arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; } int main() { int arr[] = {1,2,3,4,5,6,7,8,9,10}; int ret; ret = binary_search(arr, 0, 9, 0xFFFFFFF); printf("%d\n", ret); return 0; }
程序会输出-1,表示查找目标不在序列中。由于这个查找目标不在序列中,折半查找算法的每次循环都会扫描整个序列,这时时间复杂度会退化为O(n)。
总结
综上所述,折半查找算法是一种时间复杂度为O(logn)的快速查找算法。在数据规模较大的情况下,折半查找算法明显比普通查找算法快许多。但在最坏情况下,它的时间复杂度会失效,这时需要考虑到其他查找算法。