【问题标题】:Is there a C++ function to sort a std::stack?是否有 C++ 函数对 std::stack 进行排序?
【发布时间】:2020-08-23 23:58:39
【问题描述】:

我的代码中有一个std::stack,我需要对其进行排序。是否有任何内置功能可以做到这一点?因为std::stack 没有std::end。我可以使用std::sort 还是必须采用相同的旧方法,即使用辅助堆栈对原始堆栈进行排序?

【问题讨论】:

  • 堆栈应该是一个后进先出容器。对其进行排序会破坏该不变量。如果不需要不变量,只需使用std::vector
  • 底层容器是受保护的成员,因此,您应该能够从std::stack 继承并在内部提供其排序。但我需要承认,我不知道这种方法是否会违反一些标准规则。
  • 您将与 std::stack 一起使用的底层容器是什么?你关心排序的性能吗?
  • 我的代码中有一个 std::stack,我需要对其进行排序 -- 听起来像 XY Problem
  • 只使用std::vectorpush_back/pop_back 元素并使用std::sort 排序会不会更好?

标签: c++ sorting stl stack


【解决方案1】:

可能有一个 std::stack::sort 模板使用两个辅助堆栈和多相归并排序(时间复杂度 O(n log(n)),见下文),或者该模板可以基于底层容器类型:std::deque、std::list 或 std::vector,因为可以为 std::stack 指定容器类型,例如:

    std::stack <int, std::vector<int>> mystack;

std::sort 可用于std::deque 或std::vector(两者都有随机访问迭代器),std::list::sort 可用于std::list。我不知道 std::stack 是否允许其他容器类型或自定义容器类型;如果允许,这将导致尝试基于容器类型创建 std::stack::sort 的问题。

使用辅助堆栈对原始堆栈进行排序

具有一个辅助堆栈的堆栈排序具有 O(n^2) 时间复杂度。具有两个辅助堆栈的堆栈排序,基于多相归并排序,时间复杂度为 O(n log(n)),但代码复杂。将堆栈移动到数组或向量,对数组或向量进行排序,然后创建一个新的排序堆栈会更快。

如果您对 3 个堆栈(原始堆栈和 2 个辅助堆栈)的多相合并排序感到好奇,我编写了链接到下面的示例。这些使用基于数组的自定义堆栈容器,并且与数组上的标准合并排序一样快,但需要 2 个临时堆栈。

很久以前,多相合并排序用于磁带驱动器。一些磁带驱动器可以向后读取,以避免倒带时间,本质上使它们像容器一样堆叠(向前写入,向后读取)。对于磁带驱动器,可以使用不同大小的文件标记或记录来指示运行结束,从而无需跟踪代码的运行边界。许多商业多相归并排序程序的高级版本是专有的,随着磁带排序逐渐消失在历史中,这些知识基本上随着时间的推移而丢失。

https://stackoverflow.com/a/38419908/3282056

【讨论】:

    【解决方案2】:
    template <class T, class U, class Compare>
    void sort_stack(std::stack<T,U> &stack, Compare comp)
    {
        std::vector<T> tmp_container;
        tmp_container.reserve(stack.size());
        while(!stack.empty())
        {
            tmp_container.push_back(std::move(stack.top()));
            stack.pop();
        }
        std::sort(tmp_container.begin(), tmp_container.end(), comp);
        for(auto it:tmp_container)
        {
            stack.push(std::move(it));
        }
    }
    template <class T, class U>
    void sort_stack(std::stack<T,U> &stack)
    {
        sort_stack(stack, std::less<T>());
    }
    

    据我所知,没有办法对堆栈进行就地排序。但一种解决方法是使用额外的空间。

    【讨论】:

      【解决方案3】:

      std::stack 不是容器,而是容器适配器。

      因此,考虑到它的预期语义--

      充当底层容器的包装器 - 仅提供一组特定的函数。

      --这是一个不能排序的特征。

      由于constructor 将任何给定容器复制到堆栈中,直接对堆栈对象进行排序的唯一方法是对底层容器成员对象进行排序:

      成员对象

      Container c底层容器(受保护的成员对象)

      为此,您需要从堆栈派生一个新的自定义类型,其中涉及派生自 std 容器类的所有 headaches

      【讨论】:

      • 对不起,我不同意那些“头痛”。继承不仅仅适用于多态类。
      • @DanielLangr - 我没有特别说“不要”。我说头疼。 the whole discussion 有什么不让人头疼的?
      • 我相信经验法则非常简单(不会让人头疼)——如果你不以多态方式使用类,你就不需要虚拟析构函数。但是您可能是对的,对于标准容器,有很多要求,并且从它们继承是否不会违反其中一些规则可能不是很明显(需要仔细研究 Standrad 或在这里询问:)。跨度>
      猜你喜欢
      • 2019-10-05
      • 2020-06-30
      • 2018-11-20
      • 2011-06-05
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多