【问题标题】:Trouble Using Template Bubblesort with Array of Structs使用带有结构数组的模板冒泡排序时遇到问题
【发布时间】:2016-11-30 03:28:54
【问题描述】:

所以我的目标是读入一些数据并按人口对其进行排序,但我必须使用可以接受多种数据类型的排序。我被指示使用模板来执行此操作,但每次我将数组“results[i].pop”传递给我的冒泡排序函数时,我都会收到错误

没有匹配的函数调用'bubblesort(std::string&)' 冒泡排序(结果[i].pop);” 注:候选人是: 选举.cpp:32:3:注意:模板 T 冒泡排序(T*) T 冒泡排序(T ar[]) ^ 选举.cpp:32:3:注意:模板参数推导/替换失败:

election.cpp:106:34:注意:无法将 'results[i].election::pop'(类型 'std::string {aka std::basic_string}')转换为类型 'std::basic_string* ' 冒泡排序(结果[i].pop);

代码如下:

#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <fstream>
#include <stdlib.h>
using namespace std; 

struct election {

string party;
string state;
string pop;
string reps;
int ratio;
};


template <typename T>
void bubblesort(T ar[])
{

//Bubblesort
int n = 51;
int swaps = 1;
    while(swaps)
    {
    swaps = 0;
            for (int i = 0; i < n - 1; i++)
            {
                    if (ar[i] > ar[i + 1])
                    {
                            swap(ar[i],ar[i+1]);
                            swaps = 1;
                    }
            }
    }
//End Bubblesort

}


void delete_chars(string & st, string ch)
{
    int i = st.find(ch);
    while (i > -1)
    {
            st.replace(i,1,"");
            i = st.find(ch);
    }
}



int main()
{
int i = 0;
int n = 51;
election results[n];

int population[n];
int electoralVotes[n];
int ratio[n];
string st;
fstream inData;

//Read in Data from Text File
inData.open("electionresults.txt");



//Print Array as is
cout << "Array Printed As is" << endl;
cout << left << setw(10) << "Party" << setw(20) << "State" << setw(20) <<     "Population" << setw(15) << "Representatives" << endl;
for (int i = 0; i < n; i++)
{
    getline(inData,st);
    results[i].party = st.substr(0,1);
    results[i].state = st.substr(8,14);
    results[i].pop = st.substr(24,10);
    results[i].reps = st.substr(40,2);
    cout << left << setw(10) << results[i].party << setw(20) <<     results[i].state << setw(20) << results[i].pop << setw(15) << results[i].reps << endl;
}

 //Array Sorted by Population
cout << "Array Sorted By Population" << endl;
cout << endl;
cout << endl;
cout << left << setw(10) << "Party" << setw(20) << "State" << setw(20) <<              "Population" << setw(15) << "Representatives" << endl;



for(int i = 0; i < n; i++){
bubblesort<string>(results[i].pop);
}

【问题讨论】:

  • 您的模板函数声明为返回T。返回T 的模板函数中没有return 语句。此外,无论如何,冒泡排序函数都没有理由返回任何内容。此外,您的冒泡排序函数将数组作为参数。当您的 main() 调用它时,main() 不会将数组作为参数传递,而是传递其他内容。整个代码完全错误。您需要花更多时间研究模板。这里的问题太多了。
  • 嗯,这是我第一次使用模板,是的。我将函数更改为 void 而不是 T 但我仍然得到同样的错误。
  • 这只是众多问题中的一个。
  • 您的模板函数需要T 的数组。您正在传递pop,这不是一个数组。如果你想看看如何组合一个排序模板函数,为什么不通过查看std::sort 接口来看看它实际上是如何完成的呢?您忘记将排序 criteria 模板化 - 相反,您将比较硬编码,没有自定义空间。

标签: c++ arrays templates struct


【解决方案1】:

要使冒泡排序正常工作,您需要为选举结构实现大于运算符(>):

struct election 
{

    string party;
    string state;
    string pop;
    string reps;
    int ratio;
    bool operator>( election a)
    {
        return pop > a.pop;
    }
};

现在通过传递结果数组来调用冒泡排序:

bubblesort<election>(results);

附注你的函数应该传递大小而不是在函数中硬编码大小(void bubblesort(T ar[], int size))。这为您的函数提供了更多的功能和适应性。

【讨论】:

  • 感谢您的帮助!得到实际帮助而不是被嘲笑是令人耳目一新的,因为我还是个新手。
  • @Nar1y 你为什么提到被嘲笑?另外,如果您需要对任何其他字段进行排序怎么办?你不能这样做,因为多个operator &gt; 是不可能的。我在线程主要部分的评论解决了这个问题。
  • @Nar1y -- 我花时间提供了一个答案,并希望能解释如何以更通用的方式解决问题。请检查一下,因为它给出了详细的解释。
【解决方案2】:

如果您只想对pop 进行排序,则另一个答案解决了该问题。但是,它是一个有限的解决方案,并且不会解决对任何字段进行排序的真正问题(今天它是“流行”,但如果明天不是这种情况,您想在哪里按“比率”排序?) .问题是您不能提供多个operator &gt; 来执行此操作,并且您基本上只能在pop 上进行排序。

另一种解决方案是为bubblesort 函数提供一个额外的模板参数,该参数定义在给定两个T 时要做什么,在排序数组中是否应将一个T 放在另一个T 之前.

#include <functional>
#include <algorithm>
//...
template <typename T, typename cmp>
void bubblesort(T ar[], int n, cmp compare_fn)
{
    int swaps = 1;
    while (swaps)
    {
        swaps = 0;
        for (int i = 0; i < n - 1; i++)
        {
            if (!compare_fn(ar[i], ar[i + 1]))
            {
                std::swap(ar[i], ar[i + 1]);
                swaps = 1;
            }
        }
    }
}

// keep our original 2 param bubble sort, but let it call the one above
template <typename T>
void bubblesort(T ar[], int n)
{
    // call general version using <
    bubblesort(ar, n, std::less<T>());
}

我们基本上有两个函数,其中两个参数冒泡排序函数调用通用的3参数bubblesort版本,它接受第三个参数,描述比较。

bubblesort 的两个参数版本用于当您想在“简单”情况下调用bubblesort 时,您的项目是

  1. 在数组中和
  2. 您可以使用 &lt;
  3. 比较 T
  4. 您希望按升序排序(这就是为什么我们在一般情况下使用&lt; 而不是&gt;)。

例如需要对int的数组进行排序,而你只是想按升序排序:

int someArray[10];
//...
bubblesort<int>(someArray, 10);  // sort ascending

但是,我们不想对 int 甚至 std::string 进行“简单”排序。我们想对election进行排序,不仅如此,在election.pop上。

如果您查看上面的第一个 bubblesort 函数,请注意我们将使用 &gt; 的比较替换为对函数 compare_fn 的调用。请注意,该参数默认为std::less 函数对象。这就是为什么第二个bubblesort 函数适用于简单类型的原因,因为std::less 使用&lt; 进行比较。

但是,如果您尝试使用election 仅使用两个参数调用bubblesort,您会遇到另一个编译器错误,基本上说明election 没有operator &lt; 可比较。解决方案是

1) 为election 结构或提供这样的运算符

2) 编写自定义比较函数。

让我们逐一介绍这些解决方案。


解决方案 1:

如果我们使用 1),election 结构将如下所示:

struct election
{
    std::string party;
    std::string state;
    std::string pop;
    std::string reps;
    int ratio;
    bool operator <(const election& e) const { return pop < e.pop; }
};

int main()
{
   //...
   bubblesort<election>(results, n);
}

由于std::less&lt;&gt; 正在使用election 中定义的operator &lt;,因此现在将使用pop 作为要排序的项目对results 进行排序。

Here is an example using overloaded < in election

但是,此解决方案与其他答案存在相同的问题,因为您只能定义一个将 const election&amp; 作为参数的 operator &lt;。例如,如果您想对ratio 进行排序,那么您就不走运了,或者如果您想按降序对pop 进行排序,那么您就不走运了。这是将使用上述选项 2) 的地方。


解决方案 2:

我们可以通过提供自定义比较函数、函数对象或lambda function来定义我们想要排序的内容、排序顺序等,如果第一个T应该在第二个@之前,则返回true 987654373@ 传入比较函数,false 否则。

让我们尝试一个函数:

bool compare_pop(const election& e1, const election& e2)
{
   return e1.pop < e2.pop;  // if e1.pop comes before e2.pop, return true, else false
}

int main()
{
   //...
   bubblesort<election>(results, n, compare_pop);
}

现在会发生的是,这将调用bubblesort 的第一个版本,它将比较函数作为参数。 bubblesort 模板函数现在将调用compare_pop 来确定项目是否出现故障。如果compare_pop 返回falsebubblesort 函数将交换项目,否则将不理会它们。

Here is a live example with an array of 3 elections, sorted on pop

如果您想使用 lambda 函数而不是编写另一个比较函数,那也可以:

int main()
{
   //...
   bubblesort<election>(results, n, [&](const element& e1, const element& e2) { return e1.pop < e2.pop; });
}

上面将做与函数示例相同的事情,只是您不再需要编写单独的函数,因为使用 lambda 语法作为函数。

Example using lambda syntax


那么现在,如果我们想对pop 进行排序,但要降序而不是升序呢?很简单——使用不同的函数或 lambda 调用 bubblesort

bool compare_pop_up(const election& e1, const election& e2)
{
   return e1.pop > e2.pop;  // if e1.pop comes after e2.pop, return true, else false
}

int main()
{
   //...
   bubblesort<election>(results, n, compare_pop_up);
}

或使用 lambda:

int main()
{
   //...
   bubblesort<election>(results, n, 
                 [&](const element&e1, const element& e2) 
                 { return e1.pop > e2.pop;});
}

神奇的是,bubblesort 完成了这项工作,按降序对pop 进行排序。

Here is a live example with an array of 3 elections, sorted on pop, descending

如果您想对ratio 进行排序怎么办?同样的事情——提供不同的函数或 lambda:

bool compare_ratio(const election& e1, const election& e2)
{
   return e1.ratio < e2.ratio;  
}

int main()
{
   //...
   bubblesort<election>(results, n, compare_ratio);
}

或使用 lambda:

int main()
{
   //...
   bubblesort<election>(results, n, 
                 [&](const element&e1, const element& e2) 
                 { return e1.ratio < e2.ratio;});
}

这将按ratio 的升序对ratio 进行排序。


您的代码的另一个问题是您在定义数组时使用了非标准 C++ 语法。你正在这样做:

election results[n];

这不是标准的 C++ 语法,因为 C++ 只允许使用编译时表达式创建数组来表示项目的数量。您正在使用名为Variable Length Arrays 的东西,这是标准。

相反,您可以使用std::vector,这是标准 C++。

#include <vector>
//...
std::vector<election> results(n);
//...
bubblesort<election>(results.data(), results.size(), compare_pop)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 1970-01-01
    • 2017-01-24
    相关资源
    最近更新 更多