对一个类的向量进行排序

3
我有一个名为"UltrasoundTemplate"的类。这些UltrasoundTemplate对象包含一个int参数,显示它们何时被定义(类似于时间戳)。我还有一个名为"UltrasoundTarget"的类,其中包含一个UltrasoundTemplate向量。我使用push_back(ultrasoundTemplate)将UltrasoundTemplates添加到向量中。

现在我想按时间戳的顺序而不是它们加入向量的顺序对向量进行排序。

我在谷歌上找到了很多答案,它们都显示给我相同的解决方案,但显然我仍然做错了些什么。以下是我认为寻求解决方案所必需的代码片段:

ultrasoundTemplate.h

class UltrasoundTemplate
{
public:
 UltrasoundTemplate(/*...*/);
 int getVolumePos() { return volume_; }
private:
 int volume_;
};

ultrasoundTarget.h

//the sort algorithm
struct MyTemplateSort {
bool operator() ( UltrasoundTemplate t1, UltrasoundTemplate t2){
    int it1 = t1.getVolumePos();
    int it2 = t2.getVolumePos();

    if (it1 < it2)
        return true;
    return false;
}
};

class UltrasoundTarget
{
public:
 UltrasoundTarget(/*...*/);
 vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
private:
 vector<UltrasoundTemplate> USTemplateVector_;
};

FMainWindow.cpp

void FMainWindow::match_slot()
{
 int i;
 //here I get the name of the target I'm looking for
 QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
 int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
 QString itemToAppendName = item->text(0);
 for(i = 0; i < USTargetVector.size(); i++){
  if(USTargetVector.at(i).getName() == itemToAppendName) {
   //here I try to sort
   MyTemplateSort tmpltSrt;
   std::sort(USTargetVector.at(i).getTemplates().begin(),
              USTargetVector.at(i).getTemplates().end(), tmpltSrt);     
   break;
  }
 }

作为一个例子:我在卷(0)中定义了Template1,在卷(70)中定义了Template2,在卷(40)中定义了Template3。现在的顺序是(Template1,Template2,Template3),但我希望它变成(Template1,Template3,Template2)。但是这段代码没有实现这个目标。
如果有信息缺失,请告诉我,我会提供更多的代码。
非常感谢。

你是否忘记分配 volume_ 了? - Katniss
2个回答

5
你的getTemplates()方法返回值,导致这里出现了问题:
std::sort(USTargetVector.at(i).getTemplates().begin(),
          USTargetVector.at(i).getTemplates().end(), tmpltSrt);     

您正在对不兼容的迭代器范围进行排序。您可以通过返回一个引用来解决这个特定的问题:

vector<UltrasoundTemplate>& getTemplates() { return USTemplateVector_; }

通常需要为这样的方法添加一个const重载:

const vector<UltrasoundTemplate>& getTemplates() const { return USTemplateVector_; }

你还可以修改你的比较函数来避免不必要的拷贝(还有为了更好的可读性和const正确性):
struct MyTemplateSort {
  bool operator() const ( const UltrasoundTemplate& t1, const UltrasoundTemplate& t2)
  {
    return t1.getVolumePos() < t2.getVolumePos();
  }
};

这将需要您将getVolumePos()方法变为const方法,而这也是应该的:

class UltrasoundTemplate
{
public:
 ...
 int getVolumePos() const { return volume_; }
 ...
};

注意,在一般情况下,提供对类的私有数据的引用并不是一个好的做法。如果可能的话,应该找到一种方法将其从 UltraSoundTarget 接口中移除。例如,可以暴露一对迭代器和/或给类添加一个排序方法。

@IanMedeiros 他们可能不会使用 const 重载,但在需要的情况下拥有一个是很好的。 - juanchopanza
1
由于模板向量被封装在目标类中,因此将排序方法添加到目标类中而不是在类外部进行操作更有意义...这将避免返回值与引用的问题。 - Zac Howland
@ZacHowland 是的,我同意。我可以加一条注释关于那个。 - juanchopanza
@juanchopanza,我明白。但是如果他只实现了const&版本,他将会得到一个编译时错误,这可能会让他感到困惑。 - Ian Medeiros
1
@IanMedeiros 当然可以。而且他们可能会在这个过程中学到一些东西。但我建议添加两个重载。 - juanchopanza
显示剩余2条评论

0

juanchopanza的答案是正确的,问题在于您从UltrasoundTarget返回向量的方式。只是触及另一个话题,也许改变一下实现的设计会很好。由于UltrasoundTarget是超声波的容器,因此将排序实现为该类的方法是有意义的,这样您就可以直接访问USTemplateVector_并节省不必要的复制。像这样:

class UltrasoundTarget
{
public:
 UltrasoundTarget(/*...*/);
 vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }

 void sort();

private:
 vector<UltrasoundTemplate> USTemplateVector_;
};

void UltrasoundTarget::sort()
{
 std::sort(USTemplateVector_.begin(), USTemplateVector_.end(), tmpltSrt);  
}

void FMainWindow::match_slot()
{
 int i;
 //here I get the name of the target I'm looking for
 QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
 int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
 QString itemToAppendName = item->text(0);
 for(i = 0; i < USTargetVector.size(); i++){
 if(USTargetVector.at(i).getName() == itemToAppendName) 
 {
   //here I try to sort
   MyTemplateSort tmpltSrt;
   USTargetVector.at(i).sort(); 
   break;
 }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接