【问题标题】:Using JavaScript, how do I perform a binary search that will return multiple values?使用 JavaScript,如何执行将返回多个值的二进制搜索?
【发布时间】:2012-04-22 22:47:22
【问题描述】:

背景

我目前有一个这样的数组:

[1,1,2,3,4,5,5,5,6,7,8,8,8,8,9,10]

我一直在使用来自this website 的出色 JS 二进制搜索公式:

searchArray = function(needle, haystack, case_insensitive) {
    if (typeof(haystack) === 'undefined' || !haystack.length) return -1;
    
    var high = haystack.length - 1;
    var low = 0;
    case_insensitive = (typeof(case_insensitive) === 'undefined' || case_insensitive) ? true:false;
    needle = (case_insensitive) ? needle.toLowerCase():needle;
    
    while (low <= high) {
        mid = parseInt((low + high) / 2)
        element = (case_insensitive) ? haystack[mid].toLowerCase():haystack[mid];
        if (element > needle) {
            high = mid - 1;
        } else if (element < needle) {
            low = mid + 1;
        } else {
            return mid;
        }
    }
    
    return -1;
};

这适用于返回单个值。

问题

如何返回一个范围而不是单个值?例如,我将如何从数组中返回 8 的所有值,但仍然使用二进制搜索(我不想遍历所有内容!!)。

谢谢!

【问题讨论】:

  • @ManseUK--不用担心!有什么想法吗?
  • 正在努力!!!!输入总是一个数字吗? (单词范围让我很困惑)
  • @ManseUK--如果这让你感到困惑,请随时更改。我也在使用该特定脚本进行单词搜索,但请随意简化。到目前为止,我最好的想法是找到一个正匹配,然后向外递增和递减以收集所有匹配,但这似乎很慢而且很讨厌。
  • 正是我的想法 - 我的浏览器已经崩溃了几次测试!!!!
  • 我正在考虑在第一个肯定结果之后递归地运行二进制搜索以实现相同的结果,但没有迭代。仍然在弄清楚如何做到这一点。 . .

标签: javascript algorithm search nosql


【解决方案1】:

除非您只想计算给定数字的实例数,否则您需要返回数组中数字的上下索引。我们可以从 2 种方法中进行选择:

  1. 编写一个二进制搜索,将上下界的索引作为数组返回
  2. 坚持使用返回下限的标准二分搜索,然后简单地向上迭代直到运行结束。

采用方法 2 的性能稍差,但保留了通用算法。

【讨论】:

    【解决方案2】:

    这样的? http://jsfiddle.net/DCLey/3/

    var arr = ['1','1','2','3','4','5','5','5','6','7','8','8','8','8','9','10'];
            //  0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15            
    var searchArray = function(needle, haystack, case_insensitive) {
        if (typeof(haystack) === 'undefined' || !haystack.length) return -1;
    
        var high = haystack.length - 1;
        var low = 0;
        var vals = []; 
        var bUp = true; 
        var bDown = true;
        var i = 1; 
        case_insensitive = (typeof(case_insensitive) === 'undefined' || case_insensitive) ? true:false;
        needle = (case_insensitive) ? needle.toLowerCase():needle;
    
        while (low <= high) {
            mid = parseInt((low + high) / 2)
            element = (case_insensitive) ? haystack[mid].toLowerCase():haystack[mid];
            if (element > needle) {
                high = mid - 1;
            } else if (element < needle) {
                low = mid + 1;
            } else {
                vals.push(mid); 
                while(bUp || bDown){
                    if(bUp && haystack[mid] === haystack[mid + i]){
                        vals.push(mid + i); 
                    }else{
                        bUp = false;   
                    }
                    if(bDown && haystack[mid] === haystack[mid - i]){
                        vals.push(mid - i); 
                    }else{
                        bDown = false;   
                    }
                    i++;
                }
                return vals; 
            }
        }
    
        return -1;
    };
    
    alert(searchArray('8', arr, true)); 
    

    【讨论】:

    • @BrandonBoone--谢谢 Brandon,我认为这很有潜力。我正在查看是否可以在您的小提琴的基础上使用递归二进制搜索,而不是在数据集非常大的情况下使用递增循环。如果我能确定,我会将结果转发给您,以便您更新答案并获得信用。谢谢。
    • @MatthewPatrickCashatt - 不确定我是否遵循您的“递归”二进制搜索想法。您的输入数组必须按照二进制搜索的要求进行排序。由于是这种情况,因此可以保证其他匹配值依次高于或低于最初找到的值。因此,试图将值比较为 > 或 或
    • @BrandonBoone——我意识到这听起来可能很奇怪。我的想法是,与其向外迭代以找到边界,不如(在非常大的数据集上)运行递归二进制搜索以找到所述边界可能更快。因此,当找到第一个匹配的haystack[mid] 时,您使用该值作为high 递归搜索,并且低值保持不变。你这样做直到你再也找不到needle 值,然后你应该有你的第一个索引。然后,您使用原始中和高对needle 的最后一个索引重复该过程。希望这更有意义。
    猜你喜欢
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 2020-10-25
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多