【问题标题】:C++: Time complexity of using STL's sort in order to sort a 2d array of integers on different columnsC++:使用 STL 的排序来对不同列上的二维整数数组进行排序的时间复杂度
【发布时间】:2013-03-16 13:59:51
【问题描述】:

假设我们有以下二维整数数组:

1 3 3 1
1 0 2 2
2 0 3 1
1 1 1 0
2 1 1 3

我试图创建一个实现,用户可以将数组本身和字符串作为输入。上例中的字符串示例为03,这意味着用户希望根据第一列和第四列对数组进行排序。

所以在这种情况下,排序的结果如下:

1 1 1 0
1 3 3 1
1 0 2 2
2 0 3 1
2 1 1 3

我对 STL 的 sort 函数中使用的比较函数了解不多,但是搜索后我创建了以下简单实现:

我创建了一个名为Comparator.h的类

   class Comparator{

     private:
      std::string attr;

     public:
      Comparator(std::string attr) { this->attr = attr; }

      bool operator()(const int* first, const int* second){
       std::vector<int> left;
       std::vector<int> right;
       size_t i;
       for(i=0;i<attr.size();i++){
                left.push_back(first[attr.at(i) - '0']);
                right.push_back(second[attr.at(i) - '0']);
        }
        for(i=0;i<left.size();i++){
                if(left[i] < right[i]) return true;
                else if(left[i] > right[i]) return false;
        }
        return false;
      }

     };

我需要知道字符串中的信息,所以我需要一个类,其中这个字符串是一个私有变量。在operator 中,我将有两个参数firstsecond,每个参数都指向一行。现在有了这些信息,我创建了一个left 和一个right 向量,其中在left 向量中我只有first 行的编号,这些编号对排序很重要并且由字符串变量和在right 向量我只有second 行的编号,这些编号对排序很重要并且由字符串变量指定。

然后我进行所需的比较并返回真或假。用户可以通过在Sorting.cpp类中调用这个函数来使用这个类:

void Sorting::applySort(int **data, std::string attr, int amountOfRows){

  std::sort(data, data+amountOfRows, Comparator(attr));

 }

这是一个使用示例:

int main(void){
    //create a data[][] variable and fill it with integers
    Sorting sort;

sort.applySort(data, "03", number_of_rows);
}

我有两个问题:

第一个问题

我的实现可以变得更好吗?我使用了额外的变量,例如 leftright 向量,然后我有一些 for 循环,这给排序操作带来了一些额外的成本。

第二个问题

由于额外的成本,排序的时间复杂度会变差多少?我知道 STL 的 sortO(n*logn) 其中 n 是您要排序的整数数。这里n 有不同的含义,n 是行数,每行最多可以有m 整数,而这些整数又可以在Comparator 类中找到,方法是覆盖operator 函数并使用额外的变量(向量)和 for 循环。

因为我不确定 STL 的sort 是如何实现的,所以我只能做出一些估计。 我最初的估计是O(n*m*log(n)),其中m 是对排序很重要的列数,但我不能100% 确定。

提前谢谢你

【问题讨论】:

  • 您可能希望使用元组而不是字符串来决定使用哪些列?
  • 没有必要复制我可以看到的每个键的数据。您是否打算只支持数组中的十个不同的排序列? IE。该字符串支持 0-9 的单个数字字符来标识排序列。如果您需要超出此范围的列支持,则此算法是有限的。
  • Alex,我不知道元组,我会去找他们。 WhozCraig,我只对正确排序的数字感兴趣,我不确定严格的排序,例如你能想到结果错误的一些情况吗?我还没有在很多情况下尝试过我的实现,所以可能有些我没有想到。谢谢!
  • @AlexChamberlain:由于元组的大小是类型的一部分,我认为它们在这里没有多大帮助。据我了解,参与比较的列数直到运行时才确定。
  • @ksm001 查看您的循环,您实际上是正确的。你继续平等,所以我的立场得到纠正。其余的仍然适用,但这看起来是正确的(决定不平等,否则继续,如果我没看错的话)。只要它在到达结束时返回 false 并且仍然没有检测到决策不等式,就应该没问题。在比较器的构建时丢失复制并翻译索引,我认为您的性能会好多更好。

标签: c++ performance stl sorting time-complexity


【解决方案1】:

您当然可以改进比较器。无需复制列然后进行比较。而不是两个 push_back 调用,只需比较值,然后根据它们是小于、大于还是等于返回 true、返回 false 或继续循环。

sort 的复杂性的相关部分是 O(n * log n) 比较(在 C++11 中。C++03 并没有提供这么好的保证),其中 n 是元素的数量排序。因此,如果您的比较器是 O(m),您的估计可以对 n 行进行排序。因为attr.size() &lt;= m,你是对的。

【讨论】:

    【解决方案2】:

    第一个问题:您不需要 left 和 rigth - 您一个接一个地添加元素,然后以相同的顺序迭代向量。因此,与其将值推送到向量然后对其进行迭代,不如简单地使用在第一个周期中生成它们的值,如下所示:

        for(i=0;i<attr.size();i++){
                int left = first[attr.at(i) - '0'];
                int right = second[attr.at(i) - '0'];
                if(left < right) return true;
                else if(left > right) return false;
        }
    

    第二个问题:时间复杂度可以提高吗?不适用于使用直接比较的排序算法。另一方面,你在这里解决的问题有点类似于radix sort。所以我相信你应该能够在 O(n*m) 中进行排序,其中 m 是排序标准的数量。

    【讨论】:

      【解决方案3】:

      1) 首先,您应该在构造函数中将字符串转换为整数数组。验证值小于列数。

      (你也可以有另一个将整数数组作为参数的构造函数。 一个轻微的改进是允许负值表示该列的排序顺序是相反的。在这种情况下,值将是 -N..-1 , 1..N)

      2) 不需要中间的左右数组。

      【讨论】:

        猜你喜欢
        • 2013-10-07
        • 2017-03-31
        • 1970-01-01
        • 2020-04-05
        • 2013-12-16
        • 1970-01-01
        • 2019-12-10
        • 2021-02-03
        • 1970-01-01
        相关资源
        最近更新 更多