搜索排序数组的复杂性低于二进制搜索

时间:2014-10-27 10:52:58

标签: algorithm sorting search

为了搜索一个非常大的数组,我正在考虑一个复杂度小于log n的算法,意味着不是小于log n但是绝对小于log n的顺序。所以我所做的不是去中间而是向前移动1步并检查如果数字均匀分布我们必须进一步移动多少,移动到该位置,如果这是一个解决方案,则以其他方式计算我们必须进一步移动,迭代地执行直到找到解决方案 这是一个可用的Java代码: -

 public class Search {
        public static void main(String[] args) {
            int a[]={12,15,16,17,19,20,26,27};
            int required=27;
            int pointer=0;
            int n=1;
            int diff;
            int count=0;
            int length=a.length;
            while(a[pointer]!=required){
                count++;
                if ((pointer+n)>(length-1))
                    n=length-1-pointer;
                if(n==0)
                    n=-1;
                diff=a[pointer+n]-a[pointer];
                pointer=pointer+n;
                n=(required-a[pointer])*n/diff;


            }
            System.out.println(pointer);
            System.out.println(count);
        }

    }

P.S-我有一个接近均匀分布的阵列。

我想问的是它真的比二进制搜索更好吗?在哪些情况下它会失败?最好的,平均和最差的情况复杂度是什么?

1 个答案:

答案 0 :(得分:2)

您正在使用启发式方法来尝试加速排序。启发式就像一个猜测。它并不能保证是正确的 - 但如果启发式算法很好,可以在一般情况下加速算法。

启发式算法通常不会改善算法的最坏情况运行时间。也就是说 - 启发式的某些输入可能是错误的。

我可以看到你正在做的直觉吸引力 - 你是"搜索"离您认为目标可能的位置越近。

但是你正在做的事情有两个问题:

  1. 移动"拆分"在靠近目标的二进制搜索中,不会加快搜索速度。在二进制搜索中,您每次将搜索空间分成两半。当你将分割点移近目标时,你没有找到目标,并且你可以在两个不相等的空间中较大的一个中找到目标。
  2. 例如,假设您有以下数组。 y是你的目标,x是所有其他值:

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxYxx
    

    在二进制搜索中,您可以将空间分成两半,然后在前两个决策中将其分成两半:

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxYxx
                    ^        ^
    

    经过两次决策后,您的32值数组将下降到8个值的搜索空间。但是假设你的启发式,在第二个选择之后你把分裂放在y之后?

    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxYxx
                    ^             ^
    

    在您做出第二个决定之后,您只是略微减少了搜索空间。通过添加此启发式,您可以将最坏情况下的运行时间减少到N - 因为有可能构造输入来欺骗您的启发式,以便每次都做出最糟糕的猜测。

    1. 另一个问题是,加速搜索的启发式方法只有在您了解搜索内容时才有用。进行字典搜索。你知道z在字母表的末尾。因此,当你得到一个以z开头的单词时,你就可以很清楚z字的字典在哪里。你不必从词典中间开始。
    2. 这是因为你对字典中单词的分布有所了解。但是如果有人不保证列表中的单词 - 那么你就不能保证字典搜索更快 - 例如你可以收到所有z字的列表。

      在你的情况下,你的启发式并不是特别好。您猜测下一次拆分的位置取决于当前拆分与之前值之间的距离。唯一一次很好的猜测是列表中的元素是否均匀分布。如果它们间隔不均匀(几乎总是),那么一些猜测将总是超过分裂和其他下冲。

      在任何不均匀间隔数的排序数组中,必然会有间隔比平均值更紧密的间隔,间隔比平均值更稀疏。您的启发式猜测当前分裂到数组末尾的数字的平均稀疏度。这两件事之间没有关系。

      更新:

      你最好的情况时间:O(1) - 例如你猜对了指数。

      最坏情况:O(N) - 例如每一种选择都是最糟糕的。

      你补充说你的阵列几乎是均匀间隔而且非常大。我猜测实际上最快的是:查找数组中的第一个数字和最后一个数字,以及数组的长度。对目标的偏移做出有根据的猜测:

      offset = floor((( target - first ) / ( last - first )) * length );
      

      在目标周围选择合理的搜索空间:

      window_start = floor( offset * ( 1 - alpha ));
      window_end   = floor( offset * ( 1 + alpha ));
      

      对此窗口定义的子数组执行二进制搜索。

      您设置alpha的内容取决于您对阵列的看法。例如。你可以设置为0.05来搜索一个窗口,该窗口大约是估计目标周围总搜索空间的10%。

      如果您可以对输入的均匀性做出一些保证,那么您可以最佳地调整alpha。

相关问题