使用带有哨兵的线性搜索有什么意义?

时间:2015-10-25 11:50:29

标签: c linear-search

我的目标是了解为什么采用带有哨兵的线性搜索比使用标准线性搜索更受欢迎。

#include <stdio.h>

int linearSearch(int array[], int length) {
    int elementToSearch;
    printf("Insert the element to be searched: ");
    scanf("%d", &elementToSearch);

    for (int i = 0; i < length; i++) {
        if (array[i] == elementToSearch) {
            return i; // I found the position of the element requested
        }
    }
    return -1; // The element to be searched is not in the array
}

int main() {
    int myArray[] = {2, 4, 9, 2, 9, 10};
    int myArrayLength = 6;
    linearSearch(myArray, myArrayLength);
    return 0;
}

维基百科提到:

  

减少开销的另一种方法是消除循环索引的所有检查。这可以通过将所需项目本身作为列表远端的标记值插入来完成。

如果我使用sentinel实现线性搜索,我必须

array[length + 1] = elementToSearch;

但是,一旦找到要搜索的元素,循环就会停止检查数组的元素。使用带有标记的线性搜索有什么意义?

6 个答案:

答案 0 :(得分:5)

标准线性搜索将检查每次检查数组索引的所有元素,以检查它何时到达最后一个元素。就像你的代码一样。

for (int i = 0; i < length; i++) {
    if (array[i] == elementToSearch) {
        return i; // I found the position of the element requested
    }
}

但是,想法是哨兵搜索是为了最终保持要搜索的元素,并跳过数组索引搜索,这将减少每次迭代中的一次比较

while(a[i] != element)
    i++;

答案 1 :(得分:1)

如果在数组的末尾追加值来搜索,那么当您使用初始化,条件和增量的for循环时,可以使用更简单的循环,而不是

while (array[i++] != ementToSearch)
    ;

然后循环条件 检查您搜索的值,这意味着在循环内执行的代码更少。

答案 2 :(得分:1)

关键是你可以将for循环转换为while / repeat循环。注意你是如何检查i&lt;每次长度。如果你转变它,

do {
} while (array[i++] != elementToSearch);

然后你不必做额外的检查。 (在这种情况下,array.length现在更大)

答案 3 :(得分:1)

使用sentinel值可以删除变量i并相应地检查和增加变量。

在线性搜索中,循环看起来如下

for (int i = 0; i < length; i++) {
    if (array[i] == elementToSearch) {
        return i; // I found the position of the element requested
    }
}

所以变量i被引入,初始化,在循环的每次迭代中进行比较,增加并用于计算数组中的下一个元素。

如果要将搜索到的值传递给函数

,该函数实际上还有三个参数
int linearSearch(int array[], int length, int value) {
//...

使用sentinel值可以按以下方式重写函数

int * linearSearch( int array[], int value ) 
{
    while ( *array != value ) ++array;

    return array;
}

在调用者内部,您可以检查数组是否具有以下方式的值

int *target = linearSearch( array, value );

int index = target == array + size - 1 ? -1 : target - array; 

答案 4 :(得分:1)

如果添加要搜索的值,则可以在每个循环中减少一次比较,从而减少运行时间。 它可能看起来像(i = 0 ;; i ++)if(array [i] == elementToSearch)返回i;。

答案 5 :(得分:0)

首先,让您将示例转换为使用哨兵的解决方案。

#include <stdio.h>

int linearSearch(int array[], int length, int elementToSearch) {
    int i = 0;
    array[length] = elementToSearch;
    while (array[i] != elementToSearch) {
        i++;
    }
    return i;
}

int main() {
    int myArray[] = {2, 4, 9, 2, 9, 10, -1};
    int myArrayLength = 6;
    int mySearch = 9;
    printf("result is %d\n", linearSearch(myArray, myArrayLength, mySearch));
    return 0;
}

请注意,该数组现在在末尾有一个额外的插槽来保存前哨值。 (如果我们不这样做,则未指定写入array[length]的行为。)


哨兵方法的目的是减少每次循环迭代执行的测试数量。比较:

    // Original
    for (int i = 0; i < length; i++) {
        if (array[i] == elementToSearch) {
            return i; 
        }
    }
    return -1;

    // New 
    while (array[i] != elementToSearch) {
        i++;
    }
    return i;

在第一个版本中,代码针对每次循环迭代都测试iarray[i]。在第二个版本中,i未经过测试。

对于大型阵列,性能差异可能会很大。

但是缺点是什么?

  1. 找不到值的结果不同; -1length
  2. 我们必须使数组更大以容纳哨兵值。 (如果我们做对了,我们就有可能破坏堆栈或堆中的内容。哎呀!)
  3. 该数组不能为只读。我们必须能够对其进行更新。
  4. 如果多个线程正在同一数组中搜索不同的元素,则此方法将无效。