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

时间:2015-11-12 17:23:42

标签: c++ algorithm list vector stl

我注意到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;
}

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

为什么他们会选择为列表实现此功能,而不是为矢量实现?

实施不仅简单,而且还可以使标准模板类更加一致......在开发界面时,一致性 非常 很重要这将被数百万程序员学习并得到广泛使用!

3 个答案:

答案 0 :(得分:17)

  

实施不仅简单,而且还可以使标准模板类更加一致......

不,它不会。

了解支持STL的设计和理念,然后再提出更加一致的说法。它可能更符合您的期望,或者与您使用的其他类库一致,但它与STL设计的其余部分不一致。

Stepanov的天才,以及Generic Programming的原则之一,在lifting常见的抽象中,将算法与容器分开,因此std::sort()函数对于任何随机函数同样有效 - 访问容器,无需在每个容器上一次又一次地重新实现。

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

  

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

有关在容器上定义成员函数的原则的进一步讨论,只有当它们的行为与通用算法不同时,请参阅Effective STL Item 44

答案 1 :(得分:8)

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

当您以这种方式查看问题时,很明显std::find是规则的例外,实现了自己的成员排序功能,因为具体来说,列表可以更有效地实现。

这与std::map::findmap完全相似,其中row_number()提供了更有效的查找功能。

答案 2 :(得分:1)

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;
}