Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ n_元素是如何实现的?_C++_Algorithm_Stl_Selection_Nth Element - Fatal编程技术网

C++ n_元素是如何实现的?

C++ n_元素是如何实现的?,c++,algorithm,stl,selection,nth-element,C++,Algorithm,Stl,Selection,Nth Element,有很多关于StackOverflow和其他地方的声明称,n\u元素为O(n),并且通常使用Introselect实现: 我想知道如何才能做到这一点。我看着他,这让我更加困惑。算法如何在QSort和中值之间切换 我在这里找到了介绍文件,上面写着: 在本文中,我们集中讨论排序问题,并在后面的部分中简要地回到选择问题 我试图通读STL本身,以了解第n个元素是如何实现的,但这很快就会变得棘手 有人能给我看一下如何实现Introselect的伪代码吗?或者更好的是,除了STL以外的实际C++代码当然是:免

有很多关于StackOverflow和其他地方的声明称,
n\u元素
为O(n),并且通常使用Introselect实现:

我想知道如何才能做到这一点。我看着他,这让我更加困惑。算法如何在QSort和中值之间切换

我在这里找到了介绍文件,上面写着:

在本文中,我们集中讨论排序问题,并在后面的部分中简要地回到选择问题

我试图通读STL本身,以了解第n个元素是如何实现的,但这很快就会变得棘手


有人能给我看一下如何实现Introselect的伪代码吗?或者更好的是,除了STL以外的实际C++代码当然是:

免责声明:我不知道如何<代码> STD::NthyEngult<代码>在任何标准库中实现。 如果您知道快速排序的工作原理,您可以轻松地对其进行修改,以执行此算法所需的操作。快速排序的基本思想是,在每个步骤中,将数组划分为两部分,使小于轴的所有元素都位于左侧子数组中,而等于或大于轴的所有元素都位于右侧子数组中。(对称为“三元快速排序”的快速排序的修改会创建第三个子数组,其中所有元素都等于轴。然后,右侧子数组只包含严格大于轴的条目。)然后,快速排序通过递归排序左侧和右侧子数组来进行

如果您只想将第n个元素移动到位,而不是递归到两个子数组中,那么您可以在每一步中判断是否需要下降到左或右子数组中。(之所以知道这一点,是因为排序数组中的第n个元素有索引n,所以这就成了比较索引的问题。)因此,除非快速排序遇到最坏情况下的退化,否则在每一步中,您都会将剩余数组的大小大约减半。(您永远不会再看另一个子数组。)因此,平均而言,您在每个步骤中处理的数组长度如下:

  • Θ(N)
  • Θ(N/2)
  • Θ(N/4)
  • 每一步在它所处理的数组长度上都是线性的。(循环一次,并根据每个元素与轴的比较情况决定每个元素应进入哪个子数组。)

    您可以看到,在Θ(log(N))步骤之后,我们最终将到达一个单例数组并完成。如果你把N加起来(1+1/2+1/4+…),你会得到2n。或者,在平均情况下,因为我们不能希望轴心总是精确地成为中位数,大约是Θ(N)。

    来自(3.3版,我想)的代码是:

    模板
    void第n个元素(\u RandomAccessIter第1个元素,\u RandomAccessIter第n个元素,
    _随机存取器uuu last,u Tp*){
    而(\uuuu last-\uuuu first>3){
    _随机存取器=
    __无防护分区(uuu第一,最后,
    _Tp(uuu中值(*uuuu优先,
    *(uu first+(u last-u first)/2),
    *(uu last-1));
    
    如果你问了两个问题,那就是名义上的问题

    n_元素是如何实现的

    你已经回答了:

    有很多关于StackOverflow和其他地方的声明称,n_元素是O(n),并且它通常是用Introselect实现的

    我也可以通过查看我的stdlib实现来确认这一点

    还有一个你不明白答案的地方:

    算法如何在QSort和中值之间切换

    让我们看看我从stdlib中提取的伪代码:

    nth_element(first, nth, last)
    { 
      if (first == last || nth == last)
        return;
    
      introselect(first, nth, last, log2(last - first) * 2);
    }
    
    introselect(first, nth, last, depth_limit)
    {
      while (last - first > 3)
      {
          if (depth_limit == 0)
          {
              // [NOTE by editor] This should be median-of-medians instead.
              // [NOTE by editor] See Azmisov's comment below
              heap_select(first, nth + 1, last);
              // Place the nth largest element in its final position.
              iter_swap(first, nth);
              return;
          }
          --depth_limit;
          cut = unguarded_partition_pivot(first, last);
          if (cut <= nth)
            first = cut;
          else
            last = cut;
      }
      insertion_sort(first, last);
    }
    
    第n个元素(第一个、第n个、最后一个) { if(first==last | | n==last) 返回; 插入选择(第一、第n、最后、log2(最后-第一)*2); } 插入选择(第一个、第n个、最后一个、深度限制) { 而(最后一个-第一个>3个) { 如果(深度限制==0) { //[编者注]这应该是中位数的中间值。 //[编辑注]见下面阿兹米索夫的评论 堆_选择(第一个,第n+1个,最后一个); //将第n个最大图元放置在其最终位置。 国际热核实验堆交换(第一次,第n次); 返回; } --深度限制; 切割=无防护分区轴(第一个、最后一个);
    如果切切请注意这似乎是一个纯粹的快速排序实现,没有算法切换,所以它不是内省。我不明白你想说什么,@ NoBODY。你回答标题,而不是问题>代码>有人能告诉我如何执行内省选择的伪代码吗?或者更好的是,除了T之外的实际C++代码。他当然会说:)
    。除此之外,我认为目前还不清楚每个分区的大小是否为原来的一半。我不确定
    无防护分区的大小,但选定的轴只是当前范围的第一个、中间和最后一个元素的中间值,它只能保证轴的每一侧至少有一个元素,因此需要在许多分区步骤中线性循环。关于最后一部分,我刚刚注意到您(和标准)正在讨论平均情况,所以这是可以的,但最好补充一点,最坏的情况可能(也将)会更糟。我的主要观点(从第一条评论)OP似乎对在introselect中切换算法比对
    nth\u元素的实际实现更感兴趣。我也通过从已安装的stdlib实现中创建伪代码进行了欺骗,但我试图解决这些问题。您是否注意到该算法应仅为
    O(n)
    根据cppreference的平均情况。它没有说明最坏的情况。这意味着quickselect将是可行的,因为它的平均情况是
    O(n)
    。@cppreference中没有人还声明可以使用除Introselect之外的其他内容
    template <class Iter, class T>
    void nth_element(Iter first, Iter nth, Iter last) {
      while (last - first > 3) {
        Iter cut =
          unguarded_partition(first, last,
                              T(median(*first,
                                       *(first + (last - first)/2),
                                       *(last - 1))));
        if (cut <= nth)
          first = cut;
        else 
          last = cut;
      }
      insertion_sort(first, last);
    }
    
    nth_element(first, nth, last)
    { 
      if (first == last || nth == last)
        return;
    
      introselect(first, nth, last, log2(last - first) * 2);
    }
    
    introselect(first, nth, last, depth_limit)
    {
      while (last - first > 3)
      {
          if (depth_limit == 0)
          {
              // [NOTE by editor] This should be median-of-medians instead.
              // [NOTE by editor] See Azmisov's comment below
              heap_select(first, nth + 1, last);
              // Place the nth largest element in its final position.
              iter_swap(first, nth);
              return;
          }
          --depth_limit;
          cut = unguarded_partition_pivot(first, last);
          if (cut <= nth)
            first = cut;
          else
            last = cut;
      }
      insertion_sort(first, last);
    }