【问题标题】:Why does vector not have sort() method as a member function of vector, while list does?为什么vector没有sort()方法作为vector的成员函数,而list有?
【发布时间】:2011-05-19 13:58:09
【问题描述】:

STL 中有一个用于列表的 sort() 方法。这很荒谬,因为我更倾向于对数组/向量进行排序。 为什么不为向量提供 sort()?向量容器的创建或使用背后是否有一些基本哲学,没有为它提供排序?

【问题讨论】:

  • 这并不完全是重复的,但 AndreyT 对why there is no find for vector in C++ 的回答是相关的。
  • 实际上更好的问题是:“为什么listsort() 方法?为什么不能像vectors 和数组一样使用std::sort()?”也不知道为什么你认为想要对列表进行排序是“荒谬的”。
  • @j_random_hacker:在我看来,这很荒谬可能是因为我看待使用列表的原因。我将其视为连接在一起的链环,在重新排列之前必须断开连接,与矢量相比,我认为矢量就像一副可以轻松洗牌的纸牌。我的看法......当我熟悉使用列表进行编程时,它会变得更加清晰。
  • 有趣的是,如果单个对象足够大,对它们的列表进行排序比对向量进行排序会更快,因为您只需要更改链接(每个都是 1 或 2 个指针)而不是复制围绕整个对象。
  • @j_random_hacker:我同意。这也是值得注意的一点..

标签: c++ sorting stl vector


【解决方案1】:

可以轻松地对vector 进行排序:

sort(v.begin(), v.end());

更新:(对评论的回答):嗯,他们当然提供了它默认。不同之处在于它不是vector 的成员函数。 std::sort 是一种通用算法,应该适用于提供迭代器的任何东西。但是,它确实希望随机访问迭代器能够有效地排序。 std::list,作为一个链表,不能有效地提供对其元素的随机访问。这就是为什么它提供了自己专门的排序算法。

【讨论】:

  • 我在问为什么他们默认不为矢量提供它,就像他们为列表所做的那样。显然是有原因的。
  • 而原因正是@Mehrdad 所说的。它是在课外提供的。你应该问的问题是为什么他们没有对list 做同样的事情;)
  • vector<MyClass*> vec; 如何使用std::sort(vec.begin(), vec.end()) 对其进行排序?覆盖小于运算符也不起作用:S bool operator < (const MyClass& obj) const { return (x < obj.x); }
【解决方案2】:

<algorithm> 中的std::sort() 对具有随机访问迭代器(如std::vector)的容器进行排序。

还有std::stable_sort()

编辑 - 为什么std::list 有自己的sort() 函数而不是std::vector

std::list 的实现方式与std::vectorstd::deque(都是随机访问可迭代)不同,因此它包含自己的sort 算法,专门用于其实现。

【讨论】:

  • 我在问为什么他们默认不提供排序,就像他们为列表所做的那样
  • @Nav - std::liststd::vectorstd::deque(都是随机访问可迭代)的实现方式不同,因此它包含自己的 sort 算法,专门针对其实施。
【解决方案3】:

向量特定的排序不会比<algorithm> 中的std::sort 提供任何优势。但是,std::list 提供了自己的sort,因为它可以使用list 实现方式的特殊知识,通过操作链接而不是复制对象来对项目进行排序。

【讨论】:

  • +1,但肯定更好的解决方案是让std::sort() 移交给以迭代器容器类型为模板的类中的静态函数。基类模板将默认提供sort() 的需要随机访问的版本,但(作为类模板)它可以部分专用于list<T>。这个框架将允许任何设计容器的人也提供一个可以通过std::sort()访问的函数来对其进行排序。
【解决方案4】:

正如已经说过的,标准库提供了一个非成员函数模板,它可以在给定一对随机访问迭代器的情况下对任何范围进行排序。

使用成员函数对向量进行排序是完全多余的。以下将具有相同的含义:

std::sort(v.begin(), v.end());
v.sort();

STL 的首要原则之一是算法不与容器耦合。数据的存储方式和数据的操作方式应尽可能松散耦合。

迭代器用作容器(存储数据)和算法(对数据进行操作)之间的接口。这样,你可以编写一次算法,它可以对各种类型的容器进行操作,如果你编写一个新的容器,就可以使用现有的通用算法来操作它的内容。

std::list提供自己的sort函数作为成员函数的原因是它不是一个随机可访问的容器;它只提供双向迭代器(因为它旨在表示一个双向链表,这是有道理的)。通用的std::sort 函数需要随机访问迭代器,因此您不能将它与std::list 一起使用。 std::list 提供了自己的 sort 函数,以便对其进行排序。

一般来说,容器应该实现算法有两种情况:

  • 如果通用算法无法在容器上运行,但有一个不同的、特定于容器的算法可以提供相同的功能,例如 std::list::sort

  • 如果容器可以提供比通用算法更有效的算法的特定实现,例如std::map::find,它允许在对数时间内在映射中找到元素(通用std::find 算法执行线性搜索,因为它不能假定范围已排序)。

【讨论】:

  • [实现容器特定算法可能还有其他原因;这些只是查看 STL 容器时想到的两个大问题]
  • +1,但肯定更好的解决方案是让std::sort() 移交给以迭代器的容器类型为模板的类中的静态函数。基类模板将默认提供需要随机访问的实现,但(作为类模板)它可以部分专门用于list<T>。该框架将允许任何设计容器的人也提供可通过std::sort() 访问的对其进行排序的函数,因此无需混淆地将sort() 作为方法添加到某些类而不是其他类。
  • @j_random_hacker:我不相信这种方法足够通用以支持所有可能的容器。考虑一个容器,其中迭代器不足以执行排序,并且您需要访问容器本身(我认为这对于典型的 list 实现来说不是问题,但您绝对可以在其中实现一个序列容器案例)。
  • @j_random_hacker:完全同意,find也是如此。
  • 在这种情况下,也许您需要一种不同的 sort(...) 算法,它可以采用整个容器并且可以专门针对它们。
【解决方案5】:

回答“为什么?”的问题

std::vector 的排序算法与对原生数组的排序相同,并且(可能)与对自定义向量类的排序相同。

STL 旨在分离容器和算法,并具有将算法应用于具有正确特征的数据的有效机制。

这使您可以编写一个可能具有特定特征的容器,并免费使用算法。只有当数据的某些特殊特征意味着标准算法不合适时,才会提供自定义实现,例如 std::list。

【讨论】:

    【解决方案6】:

    答案已经有了有趣的元素,但实际上关于这个问题还有更多要说的:虽然“为什么std::vector 没有sort 成员函数?”的答案?确实是“因为标准库只有在提供比通用算法更多的时候才提供成员函数”,真正有趣的问题是“为什么std::list 有一个sort 成员函数?”,还有一些事情没有解释然而:是的std::sort 仅适用于随机访问迭代器,std::list 仅提供双向迭代器,但即使 std::sort 使用双向迭代器,std::list::sort 仍会提供更多。原因如下:

    • 首先,std::list::sort 是稳定的,而std::sort 则不是。当然还有std::stable_sort,但它也不适用于双向迭代器。

    • std::list::sort 一般实现了归并排序,但它知道它是对列表进行排序,并且可以重新链接节点而不是复制东西。支持列表的归并排序可以在 O(n log n) 时间内对列表进行排序,仅需要 O(log n) 额外内存,而典型的归并排序(例如 std::stable_sort)使用 O(n) 额外内存或 O( n log² n) 复杂度。

    • std::list::sort 不会使迭代器无效。如果迭代器指向列表中的特定对象,那么它在排序后仍将指向同一个对象,即使它在列表中的位置与排序前不同。

    • 最后但同样重要的是,std::list::sort 不会移动或交换对象,因为它只会重新链接节点。这意味着当您需要对移动/交换昂贵的对象进行排序时,它可能会更高效,而且它可以对甚至不可移动的对象列表进行排序,这对于std::sort!

    基本上,即使 std::sortstd::stable_sort 与双向或前向迭代器一起使用(这完全有可能,我们知道可以使用它们的排序算法),它们仍然无法提供 std::list::sort 必须提供的所有功能提供,并且他们也无法重新链接节点,因为标准库算法不允许修改容器,只能修改指向的值(重新链接节点算作修改容器)。另一方面,专用的std::vector::sort 方法不会提供任何有趣的东西,因此标准库没有提供。

    请注意,关于std::list::sort 的所有内容也适用于std::forward_list::sort

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-23
      • 1970-01-01
      • 2012-01-23
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      • 2018-02-17
      • 1970-01-01
      相关资源
      最近更新 更多