高级SelectionSort-在一次迭代中搜索两个元素

时间:2018-10-13 13:07:34

标签: c++ algorithm selection-sort

我有一个作业,必须使用以下参数“改进” SelectionSort:

  • 使用“改进的” SelectionSort对给定列表进行排序
  • 在一次迭代中,找到最小和第二小的元素
  • 将最小和第二小的元素放在正确的位置。

好的,到目前为止,我已经编写了以下c ++代码:

    #include <iostream>
    #include <array>
    #include <string>

    using namespace std;

    int main()
    {
    int min, min2;

    // doesn't work
    array<int, 9> list = { 97,34,15,25,27,4,19,41,68 };

    /* this one works:
    array<int, 10> list = { 4,8,1,3,10,6,5,7,9,2 }; 
    */

    // First loop
    for (int i = 0; i < list.size(); i+=2) {
        min = i;
        min2 = i + 1;

        // 2nd Loop for searching the smallest elements
        for (int j = i + 2; j < list.size(); j++) {

            if (list.at(j) < list.at(min)) {
                min = j;
            }

            // outer if -> stop before out of array
            if (j+1 < list.size()) {
                if (list.at(j+1) < list.at(min2)) {
                    min2 = j+1;
                }
            }   
        }
        swap(list.at(i), list.at(min));
        // Prevent out of array error
        if (i + 1 < list.size()) {
            swap(list.at(i+1), list.at(min2));
        }
    }

    cout << '\n' << '\n';
    cout << "Sorted list: " << endl;
    for (int elem : list) {
        cout << elem << ", ";
    }
  }

当然是排序,这就是结果...但不是我希望的结果:

4、97、15、19、25、34、27、41、68,

我没主意了,唯一的提示是:“没有第三回合”。

我将不胜感激:-)

编辑:

由于要举行投票,我试图指出问题所在。 当我使用高int值(例如代码中的int值)时,排序算法无法正常工作

  • 列表:array<int, 9> list = { 97,34,15,25,27,4,19,41,68 };
  • 结果:4, 97, 15, 19, 25, 34, 27, 41, 68,

如您所见,第一个if语句中位置0、2、4、6、8的值已正确排序,而其他两个则未形成第二个if语句。

例如,当我将int值更改为1-10的值并将它们随机混合时,该算法似乎正常工作(感谢评论!):

  • 列表:array<int, 10> list = { 4,8,1,3,10,6,5,7,9,2 };
  • 结果:1, 2, 4, 3, 5, 6, 8, 7, 9, 10,

我没主意-是编程错误还是算法错误?

编辑3: 这是我的(最终工作的)更新代码:

//array<int, 10> list = { 4,8,1,3,10,6,5,7,9,2 };
//array<int, 4> list = { 97,15,25,18 };
//array<int, 2> list = { 97,18 };
array<int, 3> list = { 4,5,3 };

// First loop
for (int i = 0; i < list.size(); i+=2) {
    if (i == list.size() - 1) {
        break;
    }
    min = i;
    min2 = i + 1;

    // Enforce that list.at(min) <= list.at(min2) -> Sorting pivot (element) for the algorithm to smallest, 2nd smallest.
    if (list.at(min) > list.at(min2)) {
        swap(list.at(min), list.at(min2));
    }

    // Second Loop
    for (int j = i + 2; j < list.size(); ++j) {
        if (list.at(j) < list.at(min)) {
            min2 = min; // min2 points now on the 2nd smallest element
            min = j; // min points now on the smallest element
        }
        else if (list.at(j) < list.at(min2)) {
            min2 = j;
        }
    }

    // Swapping the elements in the right position.
    swap(list.at(i + 1), list.at(min2));
    swap(list.at(i), list.at(min));
}

结果:

{4,8,1,3,10,6,5,7,9,2}-> 1,2,3,4,5,6,7,8,9,10

{97,15,25,18}-> 15,18,25,97,

{97,18}-> 18,97,

{4,5,3}-> 3,4,5,

1 个答案:

答案 0 :(得分:0)

尝试使用数组[97,18]进行程序。我认为您会发现它不起作用,因为从未输入过第二个循环,并且第一个循环结尾的行也不会交换任何内容。

当我在评论中说min必须小于或等于min2时,我的意思是说您必须确保list.at(min) <= list.at(min2)。我上面的2个项目数组的示例说明了为什么这样做很重要。

实施该方法的方法是修改您的第一个循环:

// First loop
for (int i = 0; i < list.size(); i+=2) {
    if (i == list.size()-1) {
        // There is an odd number of items in the list.
        // At this point, we know that the last item is in place.
        // So just exit.
        break;
    }
    min = i;
    min2 = i + 1;

    // enforce list(min) <= list(min2)
    if (list.at(min) > list.at(min2)) {
        swap(list.at(min), list.at(min2));
    }

    // second loop

是的,必须在内部循环中保持该状态。如果尝试使用数组[4,5,3],结果将是[3,5,4]

这主要是因为在您的内部循环中,当您发现list.at(j) < list.at(min)时便交换了项目。但是当list.at(min2) > list.at(min)时,您要做的就是乱码交换。

您应该使用3元素列表在调试器中单步执行代码,以了解正在发生的事情。如果您不知道如何使用调试器,请立即停止学习。当您可以观看代码的逐行执行时,很容易发现这种类型的编程错误。另一种方法是手工完成:用一支纸笔和一支铅笔,一步一步地遍历代码,将更改记入每个变量。

内循环的另一个问题是您正在使用list.at(j+1)检查list.at(min2)。但是您每次仅将j递增1,因此最终需要做更多的工作。没有理由进行额外检查。下次将通过循环进行处理。

假设您在minmin2之间保持适当的关系,则内循环中的修复很容易。如果为list.at(j) < list.at(min),则设置min2=min(因为min现在指向第二小的项目),并设置min=j。如果为list.at(j) < list.at(min2),则只需设置min2=j。代码如下:

for (j = i+2; j < list.size(); ++j) {
    if (list.at(j) < list.at(min)) {
        min2 = min;
        min = j;
    } else if (list.at(j) < list.at(min2)) {
        min2 = j;
    }
}

现在,您的代码在外部循环的末尾可以正常工作。

调试

使用数组[4,5,3]在调试器中运行程序。在内部循环之后的行上放置一个断点,这里:

    swap(list.at(i), list.at(min));

如果检查数组,您会发现它仍然是[4,5,3]。但是请看minmin2。您会看到min=2min2=0i等于0。现在,当您在list[i]list[min]交换项目时会发生什么?您得到[3,5,4],并且min2不再指向第二小的项目。

在几种不同的情况下,可能会发生这种情况。您必须考虑这些条件并加以处理。我提供的代码可让您找到最小和第二小的项目。但是,找到它们后,您必须弄清楚如何将它们交换到正确的位置。