为什么C++标准模板库不包含矢量的"sort"成员函数?

Why doesn't the C++ Standard Template Library include a "sort" member function for vectors?

本文关键字:sort 成员 函数 C++ 标准模板库 包含矢 为什么      更新时间:2023-10-16

我注意到C++标准模板库包含用于列表对象的排序成员函数,但由于某些原因,它不包含用于向量的此成员函数。

这看起来很草率,前后矛盾。。。

下面是一个示例:

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;
// Template function to print the contents of a container
template <typename Container>
void PrintContainer(const Container& container)
{
    cout << "{ ";
    Container::const_iterator i;
    for (i = container.begin(); i != container.end(); i++)
    {
        cout << *i << ' ';
    }
    cout << "}" << endl;
}
// Main
int main()
{
    vector<int> v;
    list<int> l;
    // Initialize the vector and the list in descending order
    for (int i = 10; i > 0; i--)
    {
        v.push_back(i);
        l.push_back(i);
    }
    // Print the contents
    cout << "Vector = ";
    PrintContainer(v);
    cout << "List   = ";
    PrintContainer(l);
    cout << endl;
    // Sort the vector and the list...
    cout << "Sorting..." << endl << endl;
    // Doesn't work... no member function exists, but why??
    // v.sort();
    // I have to do this annoying garbage instead...
    sort(v.begin(), v.end());
    // Works fine
    l.sort();
    // Print the contents
    cout << "Vector = ";
    PrintContainer(v);
    cout << "List   = ";
    PrintContainer(l);
    cout << endl;
    return 0;
}

我在某个地方读到,排序和其他成员函数被添加到列表模板中,以确保指针在执行不同的操作后仍然有效,但这并不能解释为什么他们会选择不为向量实现这一点。

为什么他们会选择为列表而不是向量实现这一点

实现不仅简单,而且会使标准模板类更加一致。。。在开发一个将被数百万程序员学习并广泛使用的接口时,一致性非常重要!

实现不仅简单,而且会使标准模板类更加一致。。。

不,不会。

在提出更一致的主张之前,请阅读STL的设计和理念。它可能更符合您的期望,或者与您使用过的其他类库一致,但它与STL设计的其余部分不一致。

Stepanov的天才,也是泛型编程的原则之一,在于提升通用抽象,将算法与容器分离,这样std::sort()函数就可以有效地用于任何随机访问容器,而不需要在每个容器上一次又一次地重新实现。

STL的规则是,只有当操作执行通用非成员版本无法执行的时,才将其定义为成员函数。因此,list::sort()允许对不可交换对象的列表进行排序,而std::sort()不能对列表进行排序(因为它没有随机访问迭代器),并且要求元素是可交换的。list::sort()也是稳定的,并保持迭代器的有效性,参见STL文档中关于list:的注释6

排序算法仅适用于随机访问迭代器。然而,原则上,可以编写一个也接受双向迭代器的排序算法。即使有这样一个版本的排序,列表中有一个排序成员函数仍然很有用。也就是说,提供排序作为成员函数不仅是为了提高效率,还因为它保留了列表迭代器指向的值

有关仅当容器的行为与通用算法不同时才在容器上定义成员函数的原则的进一步讨论,请参见有效STL项44。

实际上真正的问题是"当有一个非常好的std::sort算法时,为什么std::list有一个sort成员?"。(注意:std::sort是对vector和大多数其他容器进行排序的方式)

当你以这种方式看待这个问题时,很明显list是规则的例外,它实现了自己的成员排序函数,因为对于列表来说,它可以更有效地实现。

这与std::findstd::map::find完全类似,其中map提供其自己的查找功能,该查找功能工作效率高得多。

std::sort和std::stable_sort可以处理数组、向量等对象,以及任何具有随机访问迭代器的对象。std::sort通常是quicksort/heapsort的混合,称为introsort。std::stable_sort通常是某种类型的合并排序。std::list:sort设计用于处理单链表。对于双链表,内部先前的节点指针由后排序处理

std::list::sort算法经过优化,可用于链表。示例代码与HP/Microsoft版本的std::list::sort中使用的代码类似。使用指向内部列表的第一个节点的指针数组,其中array[i]为NULL或指向具有pow(2,i)节点的列表(除了最后一个指针列表大小不受限制)。实际的排序是使用标准的合并列表函数完成的。节点一次取一个并合并到数组中,然后将数组合并到单个列表中。这与用于std::sort或std::stable_sort的算法有很大不同。

NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL;                      /* destination head ptr */
NODE **ppDst = &pDst;                   /* ptr to head or prev->next */
    if(pSrc1 == NULL)
        return pSrc2;
    if(pSrc2 == NULL)
        return pSrc1;
    while(1){
        if(pSrc2->data < pSrc1->data){  /* if src2 < src1 */
            *ppDst = pSrc2;
            pSrc2 = *(ppDst = &(pSrc2->next));
            if(pSrc2 == NULL){
                *ppDst = pSrc1;
                break;
            }
        } else {                        /* src1 <= src2 */
            *ppDst = pSrc1;
            pSrc1 = *(ppDst = &(pSrc1->next));
            if(pSrc1 == NULL){
                *ppDst = pSrc2;
                break;
            }
        }
    }
    return pDst;
}
#define NUMLISTS 32                     /* size of aList[] */
NODE * SortList(NODE *pList)
{
NODE * aList[NUMLISTS];                 /* array of lists */
NODE * pNode;
NODE * pNext;
int i;
    if(pList == NULL)                   /* check for empty list */
        return NULL;
    for(i = 0; i < NUMLISTS; i++)       /* zero array */
        aList[i] = NULL;
    pNode = pList;                      /* merge nodes into aList[] */
    while(pNode != NULL){
        pNext = pNode->next;
        pNode->next = NULL;
        for(i = 0; (i < NUMLISTS) && (aList[i] != NULL); i++){
            pNode = MergeLists(aList[i], pNode);
            aList[i] = NULL;
        }
        if(i == NUMLISTS)
            i--;
        aList[i] = pNode;
        pNode = pNext;
    }
    pNode = NULL;                       /* merge array into one list */
    for(i = 0; i < NUMLISTS; i++)
        pNode = MergeLists(aList[i], pNode);
    return pNode;
}