前言
在计算机科学中,查找问题是经常遇到的一个问题。顺序查找和折半查找是两种非常基础的查找算法,也是大多数其他高效查找算法的基础。了解它们的原理、优缺点及应用场景,对于我们深入理解各种排序和查找算法有很大帮助。
顺序表的储存结构
typedef struct {
int* array;//储存空间基地址
int lenght;//当前长度
}SQList;
顺序查找
顺序查找(Sequential Search)也被称为线性查找,它的基本思想是从数据结构的起点开始,循环遍历每个元素直到目标值或整个数据结构被遍历完毕。如果找到了目标值返回下标,否则返回不存在的标识(通常使用-1)。它既可以用于有序表中的无序查找,也可以用于无序表中的有序查找。
以下是算法实现:
int Sequential_Search(SQList* L, int e) {
for (int i = 0; i < L->lenght; i++) {
if (L->array[i] == e) {
return i;//找到目标值,返回下标
}
}
return -1;//没有找到目标值,返回-1
}
还有一种是设置监视哨,可以免去查找过程中每一步都有检测整个表是否查找完毕。以下是在表尾设置监视哨的算法:
int Sequential_Search(SQList* L, int e) {
int i;
L->array[L->lenght] = e;
for (i =0; L->array[i] != e; i++);
return i==L->lenght? -1:i;
}
顺序查找的时间复杂度为O(n),其中n为待查找元素的个数。由于需要遍历整个数据结构,它在大型数据集上的效率不高,但对于小型数据集或数据有序性较低的情况,它仍然是一个简单而有效的方法。
折半查找
折半查找(Binary Search)又称二分查找,它是针对有序数据结构的查找算法。它的基本思想是将待查区间的两端分别记录下来,然后计算出中点位置。与目标值进行比较大小,如果等于中点位置上的值,则查找结束;否则根据大小关系继续在左半部分或右半部分进行二分查找,直到最后找到目标值或确定该值不存在于待查区间。
在实现二分查找时,通常区间定义、循环结束条件和中值溢出是需要特别注意的,这里给出一些具体的解决方案:
1.区间定义:采用左闭右闭区间或者左闭右开区间。在左闭右闭区间中,数组索引的起始值和结束值都包含在搜索区间中;而在左闭右开区间中,开始值包含在搜索区间中,但结束值不在其中。
2.循环结束条件:当待搜索区间为空时,可以结束循环。具体判断方法如下:
- 在左闭右闭区间[left,right]中,判断left <= right是否成立。
- 在左闭右开区间中[left,right),判断left < right是否成立。
3.中值溢出:当left和right都是int,两个值的初始值都超过int限定大小的一半,那么left+right就会发生溢出,所以应该用left+(right-left)/2来防止求中值时候的溢出。
根据以上三点,可以在代码中清晰地定义搜索区间,并避免进入死循环。
int Binary_Search(SQList* L, int e) {
//查找目标值e
int left, right, mid;
left = 0;
right = L->lenght - 1;
while (left <= right) {
mid = (left + right) / 2;
if (L->array[mid] == e) {
return mid;//返回目标值所在数组下标
}
else if (L->array[mid] > e) {
right = mid - 1;//继续查找左半区
}
else {
left = mid + 1;//继续查找右半区
}
}
return -1;//没有找到目标值,返回-1
}
还可以通过递归实现:
int Binary_Search(SQList* L, int left, int right, int e) {
//查找目标值e
if (left > right) return -1;//没有找到目标值,返回-1
int mid = (left + right) / 2;
if (L->array[mid] == e) return mid;//返回目标值所在数组下标
//递归查找左半区或右半区
return L->array[mid] > e ? Binary_Search(L, left, mid - 1, e) : Binary_Search(L, mid + 1, right, e);
}
折半查找的时间复杂度为O(log n),其中n为待查元素的个数。由于是将待查区间不断对半划分直到找到目标元素或者区间为空,因此当数据集非常大时它是一种高效而实用的查找算法。
总结
顺序查找和折半查找作为查找问题中的基础算法,在各自适合的场景中具备着一定的优势和局限性。当数据规模较大时,折半查找的时间复杂度的表现更佳;而对于较小数据规模和无序数据,使用顺序查找可能是更好的选择。同时,我们还可以通过在二叉搜索树和哈希表等其他数据结构上应用查找技术来解决不同的查找问题。因此,我们在日常编程中,应该根据实际情况选择基于不同算法的查找策略,以获得更好的效率与体验。