使用 std::sort() 方法






4.52/5 (10投票s)
2000年4月28日

223154

767
STL 排序入门。
去年,我正在开发一个数据库程序,需要执行三个查询,每个查询都有一些公共字段和几个不同的字段。公共数据是开始和结束日期,自然地,数据行需要交错排列。
Purchase Jan 1, 1990
Installation Feb 2, 1990
Repair Sept 23, 1991
Installation Dec 10, 1993
Repair Jun 4, 1996
由于有三个不同的但相似的项目,我需要一个基类,我可以从中派生。基类包含我将用于排序的日期戳,并且为了这个例子,我添加了一个将文本输出到输出流的方法。
// Base class we're using to provide a function with a sortable value class CHistoryItem { public: CHistoryItem(DATE& rTimestamp) { m_Timestamp = rTimestamp; } DATE& GetTimestamp() { return m_Timestamp; } // Indicate the item type as a string virtual char* ItemName() = 0; // Output the item to a stream void OutputToStream(std::ostream& os) { os << ItemName() << "\t" << m_Timestamp << "\n"; } protected: DATE m_Timestamp; };
定义了基类后,我从中派生了三个历史项目。
// Repair history entry class CRepairItem : public CHistoryItem { public: CRepairItem(DATE rTimestamp) : CHistoryItem(rTimestamp) { } // Indicate that this is a repair char* ItemName() { return "Repair: "; } }; // Installtion history entry class CInstallItem : public CHistoryItem { public: CInstallItem(DATE& rTimestamp) : CHistoryItem(rTimestamp) { } // Indicate that this is a installation char* ItemName() { return "Install: "; } }; // Purchase history entry class CPurchaseItem : public CHistoryItem { public: CPurchaseItem(DATE& rTimestamp) : CHistoryItem(rTimestamp) { } // Indicate that this is a installation char* ItemName() { return "Purchase: "; } };
好的...所以我们有了类定义,现在是时候创建一个包含我们对象的向量了。由于我不知道在执行查询之前会期望什么,我们必须动态分配对象。由于我有点懒而且健忘,我倾向于在向量析构函数中释放我分配的向量中的对象。
// A vector based class to contain our history items class CHistoryVector : public std::vector<CHistoryItem*> { public: // Make sure that the history items are de-allocated so we don't leak ~CHistoryVector() { for (iterator pItem=begin(); pItem != end(); ++pItem) delete *pItem; } };
现在我们已经设置好了一切,我们需要提供一种指定如何排序数据的方法。通常我只需要以一种方式排序我的数据,但是为了展示排序的工作原理,我创建了两种排序方法。同样,我本可以在 CHistoryItem 类中做更多的工作,并为其提供一个 operator < 方法,但那样我所做的事情可能就不那么明显了。基本上,排序类必须有一个 operator () 方法,该方法返回一个布尔值,并由 sort() 算法传递两个向量元素。你的任务是在第一个项目应该放在排序输出中第二个项目之前返回 true,否则返回 false。
// Ascending date sorting function struct SAscendingDateSort { bool operator()(CHistoryItem*& rpStart, CHistoryItem*& rpEnd) { return rpStart->GetTimestamp() < rpEnd->GetTimestamp(); } }; // Descending date sorting function struct SDescendingDateSort { bool operator()(CHistoryItem*& rpStart, CHistoryItem*& rpEnd) { return rpStart->GetTimestamp() > rpEnd->GetTimestamp(); } };
现在我们只需要一些东西来创建我们的向量,对其进行排序,然后做一些可以指示我们输出内容的事情。这是一个简单的控制台应用程序,可以用来测试我们的示例。
// Stuff a vector with data & then sort int main(int argc, char* argv[]) { CHistoryVector HistoryVector; // Put two repair items in the vector HistoryVector.push_back(new CRepairItem(2*365.0)); HistoryVector.push_back(new CRepairItem(5*365.0)); // Now stick three installations items in the vector HistoryVector.push_back(new CInstallItem(3*365.0)); HistoryVector.push_back(new CInstallItem (6*365.0)); HistoryVector.push_back(new CInstallItem (4*365.0)); // Finally we need to add a purchase item to the vector HistoryVector.push_back(new CPurchaseItem (1*365.0)); //================================== // Sort the items in ascending order std::sort(HistoryVector.begin(), HistoryVector.end(), SAscendingDateSort()); // Now show the results! std::cout << "Ascending Sort\n"; for (long lEle=0; lEle < HistoryVector.size(); ++lEle) HistoryVector[lEle]->OutputToStream(std::cout); //================================== // Sort the items in descending order std::sort(HistoryVector.begin(), HistoryVector.end(), SDescendingDateSort()); // Now show the new results! std::cout << "\nDescending Sort\n"; for (lEle=0; lEle < HistoryVector.size(); ++lEle) HistoryVector[lEle]->OutputToStream(std::cout); getchar(); // Pause for a response return 0; }
那么运行后它看起来怎么样?这里是输出:
Ascending Sort
Purchase: 365
Repair: 730
Install: 1095
Install: 1460
Repair: 1825
Install: 2190
Descending Sort
Install: 2190
Repair: 1825
Install: 1460
Install: 1095
Repair: 730
Purchase: 365
显然,日期没有转换为漂亮的字符串,但如果需要,我们可以添加这个...主要一点是注意第一组数据按升序排序,而第二组数据按降序排序。
Paul 的公司是 ADOPro.com。