【问题标题】:c++ sort and quick sort algorithm and for loop questionc++排序和快速排序算法和for循环问题
【发布时间】:2021-10-22 02:52:50
【问题描述】:

请你帮我从一本书中理解下面的代码吗?

我想知道为什么“swap(words, start, current);”不是下面代码中 for 循环的一部分?

“for 循环 - 检查单词与所选单词”的最终效果应该是将所有小于所选单词的单词放在所有大于或等于它的单词之前。

但是,在每次 I++ 迭代后不交换“开始”和“当前”,我不明白比较是如何完成的,因为 IF 语句中的“*words[i]”将始终与“* words[start]" 总是等于 index = 0 (条件在循环中迭代,意味着总是针对 0 索引进行比较)

// 指“*words[i]

附:我最初的假设是交换线 “交换(单词,开始,当前);”应该是 for 循环的一部分,如下所示,它不是循环的一部分,而是在 for 循环之外。

void sort(Words& words, size_t start, size_t end)
{
  // start index must be less than end index for 2 or more elements

  if (!(start < end))
    return;

  // Choose middle address to partition set

  swap(words, start, (start + end) / 2);

// Check words against chosen word

size_t current {start};
for (size_t i {start + 1}; i <= end; i++) 
  {
    if (*words[i] < *words[start])
      swap(words, ++current, i);
  }
  swap(words, start, current);

  if (current > start) sort(words, start, current - 1);
  if (end > current + 1) sort(words, current + 1, end);
}

下面还添加为交换函数定义的代码(以防你认为它是相关的)

#include <iostream>
#include <iomanip>
#include <memory>
#include <string>
#include <string_view>
#include <vector>

using Words = std::vector<std::shared_ptr<std::string>>;
void swap(Words& words, size_t first, size_t second);
void sort(Words& words);
void sort(Words& words, size_t start, size_t end);
void extract_words(Words& words, std::string_view text, std::string_view separators); void show_words(const Words& words);
size_t max_word_length(const Words& words);

int main() 
{
  Words words;
  std::string text;       
  const auto separators{" ,.!?\"\n"}; 

std::cout << "Enter a string terminated by *:" << std::endl;    getline(std::cin, text, '*');

extract_words(words, text, separators); 
if (words.empty())
 {
std::cout << "No words in text." << std::endl;
return 0;
 }
sort(words);
show_words(words);
}

void extract_words(Words& words, std::string_view text, std::string_view separators) 
{
size_t start {text.find_first_not_of(separators)};
size_t end {};

while (start != std::string_view::npos) 
 {
 end = text.find_first_of(separators, start + 1); 
 if (end ==    std::string_view::npos)
 end = text.length();
words.push_back(std::make_shared<std::string>(text.substr(start, end - start)));
 }
}


void swap(Words& words, size_t first, size_t second)
{
  auto temp{words[first]};
  words[first] = words[second];
  words[second] = temp; 
}

This just swaps the addresses in words at indexes first and second.

【问题讨论】:

  • std::swap 只接受两个参数。我们对您使用的swap 一无所知。
  • 这本书和作者是什么?此代码来自哪个页面?
  • @Eljay 从新手到专业 APRESS 第五版从 c++17 开始
  • 在本书第 7 章中,步骤 3 段落解释了 for 循环的作用,以及为什么在 for 循环之后有一个交换。
  • @Eljay 不确定你在哪里看练习是在第 8 章,第 311 页。我理解为什么需要它,我不明白为什么它被放置在它放置的位置(循环外)没有'没道理

标签: c++


【解决方案1】:

发生的事情是数组的中间值被选为枢轴值并将“不碍事”移动到数组的开头:

swap(words, start, (start + end) / 2);

然后循环处理从start+1end(含)的所有值,以便一旦完成,从startcurrent(含)的所有值都小于枢轴值。请注意,循环来自start+1,因此我们永远不会更改枢轴值。

size_t current {start};
for (size_t i {start + 1}; i <= end; i++) 
  {
    if (*words[i] < *words[start])
      swap(words, ++current, i);
  }

但是,此时枢轴位于错误的位置。要使递归调用起作用,words[current] 处的值必须包含枢轴值。 所以它需要从我们放置它的地方(words[start])交换到current

swap(words, start, current);

考虑一下如果你对一个简单的小数组进行排序会发生什么可能会很有用

[3,2,1]

您选择中间值并将其移至开头...

[2,3,1]

您移动所有小于枢轴的值...

[2,1,3]
   ^
   |
current

您将枢轴移回原位

[1,2,3]

您对当前 [1] 之前和当前 [3] 之后的部分进行排序,这不涉及任何更改,因为它们是单个元素。

请注意,如果您没有将枢轴移动到正确的位置,则对子数组进行排序不会产生正确的答案。

【讨论】:

  • 谢谢你很好地解释了@idz,我想我仍然缺少抓住这个概念的原因只是为什么循环总是将它与“*words[start]”进行比较,因为这个值总是相同的...如果向量中有很多单词多次比较将导致错误并且不会发生交换(循环内交换)
  • 这就是快速排序的基本思想。您通过数组,仅移动小于某个枢轴的值......然后您在枢轴两侧的新的较小子数组上执行相同的过程。维基百科页面解释得很好en.wikipedia.org/wiki/Quicksort
  • 值得用铅笔和纸计算出几个小阵列,让您了解它是如何工作的 ;-)
  • 非常感谢!!!
  • 整数除法会截断结果,因此假设这是第一轮,start = 0end = 3(start + end) / 2 == (0 + 3) / 2 == 3 / 2 == 1,因此将选择值 2(索引为 1)[3, 2, 1, 4].
猜你喜欢
  • 2017-01-14
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 2023-01-31
  • 1970-01-01
  • 2018-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多