【问题标题】:nth_element implementation based on modified quick_sort, not working as expected基于修改后的 quick_sort 的 nth_element 实现,未按预期工作
【发布时间】:2020-08-29 10:53:45
【问题描述】:

为了理解 quick_sort,我正在尝试实现 nth_element
作为测试的基本事实,我使用std::nth_element
我的算法在许多输入上都失败了,例如 a = {6,1,7,5,3,8,2,4,9}
如何解决?

std::random_device dev;
std::mt19937 rng(dev());

int kth_element(vector<long long> a, int l, int r, int k) {
  if(l >= r) return a[l];
  int i = l, j = r;
  uniform_int_distribution<int> dist(l,r);
  int X = a[dist(rng)];
  while(i < j) {
    while(a[i] < X) ++i;
    while(a[j] > X) --j;
    if(i < j) {
      swap(a[i], a[j]);
      ++i;
      --j;
    }
  }
  if(k >= l && k < i)
    return kth_element(a, l,i-1,k);
  else if (j < k && k <= r)
    return kth_element(a,j+1,r,k);
  return X;
}

int kth_element(vector<long long> a, int k) {
  int n = a.size();
  return kth_element(a,0,n-1,k);
}

int main(int argc, char* argv[]) {
  vector<long long> a = {1,2,3,4,5,6,7,8,9};
  int n = a.size();
  for(int i = 0; i < n; ++i)
    cout << kth_element(a,i) << '\n';

  random_device rd;
  mt19937 rng(rd());
  shuffle(a.begin(), a.end(), rng);
  show_vars(a);
  for(int i = 0; i < n; ++i) {
    cout << i << ": " << kth_element(a,i);
    nth_element(a.begin(), a.begin()+i,a.end());
    cout << ", " << a[i] << '\n';
    assert(kth_element(a,i) == a[i]);
  }

  return 0;
}

如果我在循环中进行测试,则更新算法失败:

int main(int argc, char* argv[]) {
  vector<long long> a = {1,2,3,4,5,6,7,8,9};
  int n = a.size();
  // for(int i = 0; i < n; ++i)
  //   cout << kth_element(a,i) << '\n';

  random_device rd;
  mt19937 rng(rd());
  for(int t = 0; t < 1000; ++t) {
    shuffle(a.begin(), a.end(), rng);
    // show_vars(a);
    for(int i = 0; i < n; ++i) {
      // show_vars(i);
      long long kth = kth_element(a,i);
      cout << i << ": " << kth;
      nth_element(a.begin(), a.begin()+i,a.end());
      cout << ", " << a[i] << '\n';
      // show_vars(kth, a[i]);
      assert(kth == a[i]);
    }
  }

  return 0;
}

【问题讨论】:

  • @john 错过了 wrapper 函数,现在已修复,谢谢
  • 你在调用kth_element时忘记返回if和else if。
  • @lucieon 非常感谢!而已!添加了返回语句,但如果我在循环中随机播放它仍然会失败,我添加了代码
  • 请显示更新后的代码。
  • @n.'pronouns'm。我将它附加到问题的末尾,在“如果我在循环中进行测试时更新,算法失败:”

标签: c++ algorithm quicksort nth-element


【解决方案1】:

如果有人尝试基于 Hoar 分区实现 nth_element:

使用 2 个指针 i,j 并保持循环不变:
对于 k = 0..i-1 a[k] = X
在循环之后,数组可能会以 2 种方式进行分区:
...| j |我 |...
要么 ...| j | X |我|... [L,j] 中具有 idx 的所有元素(左侧) 在 [i,R] >= X
基于左/右部分的元素数量在所需路径上重复出现

std::random_device dev;
std::mt19937 rng(dev());
long long kth(vector<long long>& a, int L, int R, int k) {
  if(L>=R) return a[L];

  int i = L,j = R;

  std::uniform_int_distribution<std::mt19937::result_type> dist(L,R);
  long long X = a[dist(rng)];

  while(i <= j) {
    while(a[i] < X) ++i;
    while(a[j] > X) --j;
    if(i <= j) {
      swap(a[i], a[j]);
      ++i;
      --j;
    }
  }


  if(k <= j)
    return kth(a, L,j,k);
  if (k >=i)
    return kth(a,i,R,k);
  return X;
}

【讨论】:

  • 这看起来不像是我的答案。答案部分用于解答。
猜你喜欢
  • 1970-01-01
  • 2023-03-25
  • 2021-06-10
  • 2023-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多