【问题标题】:Why am I getting segmentation fault and how to resolve it为什么我会遇到分段错误以及如何解决它
【发布时间】:2016-06-08 18:15:01
【问题描述】:
#include<iostream>
using namespace std;
int BSearch(int array[],int key,int left,int right)
{
    if(array[left+right/2]==key)
        cout<<left+right/2;
    else if(array[left+right/2]<key)
        BSearch(array,key,left,right/2-1);
    else 
        BSearch(array,key,right/2,right);

}

int main()
{
int list[]={1,2,3,4,5,6,7,8,9,11,15,21};
BSearch(list,5,0,sizeof(list)/sizeof(int)-1);
}

我编写了这个程序来执行二进制搜索。每次运行时都会遇到分段错误。

【问题讨论】:

  • 必须加括号:(left+right)/2
  • @HalilİbrahimOymacı 哦,您可能在我写答案时发表了评论。如果你愿意,我可以删除它,因为看起来你是第一个来的。
  • @gsamaras 没有必要。 :)
  • 请发布真实代码。这甚至无法编译。
  • 我的回答不完整。更新辛哈。

标签: c++ algorithm binary segmentation-fault binary-search


【解决方案1】:

在这里查看:

if(array[left+right/2]==key)

并专注于这个left+right/2。在这里,运算符的优先级开始发挥作用。您可能是指将左右相加,然后将总和除以二。

但是,它会先将右边除以 2,然后再将其加到左边。


所以改变:

left+right/2

到:

(left+right)/2

无处不在你需要。


此外,您的逻辑有缺陷。我已经在Binary Search (C++) 中写了一个示例,但即使Wikipedia 也可以在这里提供帮助。您的代码适用于此:

#include <iostream>
using namespace std;

void BSearch(int array[], int key, int left, int right) {
    if (array[(left + right) / 2] == key) {
        cout << "found at position " << (left + right) / 2;
        return;
    } else if (array[(left + right) / 2] > key) {
        BSearch(array, key, left, (left + right)/ 2 - 1);
    } else {
        BSearch(array, key,  (left + right)/ 2 + 1, right);
    }
}

int main() {
    int list[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15, 21};
    BSearch(list, 5, 0, sizeof(list) / sizeof(int) - 1);
}

输出:

found at position 4

【讨论】:

    【解决方案2】:

    其实这样做的正确方法不是

    (left+right)/2
    

    但是

    left + (right - left)/2
    

    不同之处在于,在处理大型列表时,第一个变体存在溢出问题(有符号整数的未定义行为,无符号整数无法按预期工作)。

    让我们来说明范围为 0..255 无符号和 -128..127 有符号的 char 类型(int 的范围更广,但问题仍然存在)。

    假设你想找到签名字符 40 和 100 的中间:

    • 第一个表达式 [(left+right)/2] 的结果是:(40+100)/2 = (-116)/2 = -58(技术上未定义,40+100 字符在标准二进制补码实现中仅为 -116,但 C/C++ 标准不强制要求)
    • 第二个[left + (right - left)/2]的结果是40 + (100-40)/2 = 40 + (60)/2 = 40 + 30 = 70

    使用无符号字符 100 和 250:

    • 第一:(100 + 250)/2 = (94)/2 = 47
    • 第二个:100 + (250 - 100)/2 = 100 + 150 / 2 = 175

    对于递归调用,您需要沿“中间”点提供范围(同样是L + (R-L)/2 而不是R/2)。

    特别是Wikipedia article中也提到:

    虽然二分查找的基本思想比较 直截了当,细节可能非常棘手……(Donald Knuth)

    【讨论】:

    • 我明白了,但我仍然遇到同样的错误,代码是否还有其他问题。
    • 这是因为提供给递归调用的子范围也是错误的,正如@gsamaras 在他的回答中指出的那样。
    【解决方案3】:

    您必须在第二个 if 语句中将小于更改为大于:else if(array[(left+right)/2]&gt;key),因为您搜索的是反面。

    并且您必须在第三个 if 语句中将 right/2 更改为 (left+right)/2,因为 left 可能不是 0 并且 right/2 不会正确。您必须从中间向右侧搜索。解决办法是

    #include <iostream>
    
    using namespace std;
    
    int BSearch(int array[],int key,int left,int right)
    {
        if(array[(left+right)/2]==key)
            cout<<(left+right)/2 << endl;
        else if(array[(left+right)/2]>key)
            BSearch(array,key,left,(left+right)/2-1);
        else 
            BSearch(array,key,(left+right)/2+1,right);
    }
    
    int main()
    {
        int list[]={1,2,3,4,5,6,7,8,9,11,15,21};
        BSearch(list,5,0,sizeof(list)/sizeof(int)-1);
    }
    

    【讨论】:

      【解决方案4】:

      其他答案中讨论的括号问题肯定是一个大问题,必须解决。但是,我认为这不会导致段错误。

      第一次调用BSearch()leftright分别是0和11。 5 是(错误地)计算的索引,指向值 6。因此,BSearch() 的最后一行被调​​用,将 5 和 11 传递给 leftright

      再次遍历该函数,再次调用最后一行,再次传递 5 和 11,ad infinitum

      您必须更正BSearch() 计算要传递给自身的索引的方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-16
        • 2021-10-19
        • 2016-05-03
        • 2020-08-03
        相关资源
        最近更新 更多