【问题标题】:How to extract columns of a 2D array in c++?如何在 C++ 中提取二维数组的列?
【发布时间】:2019-08-03 10:45:31
【问题描述】:

我的任务是计算 C++ 中二维数组的每个元素在对应行 i 和列 j 中大于元素 aij 的元素数量。我的方法是提取 ith 行和 jth 列,对它们进行排序并使用计数器变量遍历排序后的数组,直到 aij 元素被发现。

但问题在于为每个此类元素提取整行 i 和整列 j。我知道可以使用 c++ 中的std::copy 函数轻松提取该行。

int **adj=new int *[n];

for(r=0;r<m;r++)
   for(c=0;c<n;c++)
       cin>>adj[r][c];

int buf[n];
std::copy(adj[i], adj[i] + n, buf);

但是如何提取对应的第jth列呢?

我可以很容易地用这样的循环结构来做到这一点:

int buf[m];
for(r=0;r<m;r++)
   buf[r]=adj[r][j];

但这会增加时间复杂度,请记住数组的每个元素都需要此操作。有更好的方法吗?

【问题讨论】:

  • 如果您的代码有效,您对特定代码相关问题没有任何疑问,并且想知道如何优化您的解决方案,CodeReview 适合您,而不是 StackOverflow。
  • @Fureeish 我不同意,这是一个很好的问题,因为它非常仅限于特定问题。这在 CodeReview 上没有位置。
  • @ruohola 我不同意这在 CodeReview 上没有位置。 OP 提出了一种算法,大概可以解决他们的问题,并想知道解决方案是否会变得更好。这似乎非常适合 CodeReview 和 StackOverflow 上的边界题外话。人们可能会提到缓存友好性、更高效的算法等等,但这通常是 CodeReview 的工作。
  • “我的任务是为二维数组的每个元素计算相应行 i 和列 j 中大于元素 aij 的元素数”所以你必须创建另一个矩阵 C,其中 Cij = (...) Aij 的计数。对吗?
  • @Bob__ 是的,你是对的。

标签: c++ arrays sorting pointers


【解决方案1】:

如果你决定用 C++ 编写程序,那么

  • 停止使用普通的 C 样式数组。 C 样式数组没有任何理由。永远不要再使用它们。只需停止。
  • 停止使用原始指针。现在和永远。不要使用原始指针
  • 不要使用新的。从不
  • 您要使用的语言 C++ 不支持 VLA(可变长度数组),首先不要使用 C 样式数组,而且根本不使用 VLA(如 int buf[m];
  • 尤其是,如果您不了解它们的工作原理,请不要使用此类构造

在你的第一行,你正在写

int **adj=new int *[n];

这样你就分配了一个指针数组。这些指针未初始化。它们指向内存中随机的某个地方。

还有

for(r=0;r<m;r++)
   for(c=0;c<n;c++)
       cin>>adj[r][c];

您正在获取用户输入并将它们写入随机内存,这是一些未定义的,破坏堆并导致崩溃。

int buf[n];
std::copy(adj[i], adj[i] + n, buf);

你将一些随机值复制到 buf 中。它看起来像它的作品。但这只是偶然。

以后请使用std::vectorstd array(如果您在编译时知道尺寸)。对于二维数组,使用向量的向量。

请看下面的例子:

int main()
{
    const size_t numberOfRows = 3;
    const size_t numberOfColumns = 4;

    std::vector<std::vector<int>> a2d(numberOfRows, std::vector<int>(numberOfColumns));

    // Fill a2d with data
    for (size_t row = 0; row < a2d.size(); ++row) {
        for (size_t col = 0; col < a2d.front().size(); ++col) {
            std::cin >> a2d[row][col];
        }
    }

    // Get 2nd row
    std::vector<int> row(numberOfColumns);
    std::copy(a2d[1].begin(), a2d[1].end(), row.begin());

    return 0;
}

【讨论】:

  • 非常感谢您的宝贵回答。它将帮助我理清我的概念。但是你能解决这个问题----(我可以提取/有什么方法可以提取)这个二维向量的列,而不需要一个一个地复制元素(正如我在问题中所展示的那样(但是用向量代替)?。如果可能请提供语法。
  • 如果要直接使用列,则需要使用std::valarray 和切片。或stackoverflow.com/questions/56816493/… 中描述的内容。没那么容易。甚至不在 C 语言中。或者使用许多可用的矩阵库之一,例如 eigen。
  • "对于二维数组,使用向量的向量。"对性能非常不利。此外,没有理由停止使用数组。原始指针是非拥有访问的正确工具。
【解决方案2】:

但问题在于为每个这样的元素提取整行 i 和整列 j。

您尝试实现的算法不需要每次都复制和排序行和列。您可以对每一行和每一列进行一次复制和排序,然后为每个元素重复使用这些内容。虽然耗时,但它应该比多次遍历行和列来计算更大的值要快得多。

参见例如以下实现(可测试HERE)。

#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<std::vector<int>> a {
        {3, 5, 1, 2},
        {8, 0, -2, 7},
        {1, -5, 3, 6},
    };

    // Make a transposed copy. That's really cache unfriendly
    auto a_t = std::vector<std::vector<int>>(a[0].size(), std::vector<int>(a.size()));
    for (size_t r = 0; r < a.size(); ++r)
    {
        for (size_t c = 0; c < a[r].size(); ++c)
        {
            a_t[c][r] = a[r][c];
        }
    }
    // Sort the rows of a_t (columns of a)
    for (auto & row : a_t)
    {
        std::sort(row.begin(), row.end());
    }   

    auto c = std::vector<std::vector<int>>(a.size(), std::vector<int>(a[0].size()));
    for (size_t i = 0; i < c.size(); ++i)
    {
        // Sort a (copied) row at a time.
        auto row_copy(a[i]);
        std::sort(row_copy.begin(), row_copy.end());

        // The columns have already been copied and sorted,
        // now it just takes a couple of binary searches.
        for (size_t j = 0; j < c[i].size(); ++j)
        {
            auto it_r = std::upper_bound(row_copy.cbegin(), row_copy.cend(), a[i][j]);
            auto it_c = std::upper_bound(a_t[j].cbegin(), a_t[j].cend(), a[i][j]);
            c[i][j] = std::distance(it_r, row_copy.cend())
                    + std::distance(it_c, a_t[j].cend());
        }
    }

    for (auto const & row : c)
    {
        for (auto i : row)
            std::cout << std::setw(3) << i;
        std::cout << '\n';
    }
}

【讨论】:

  • 请注意,矩阵需要非常大才能使 sort-then-N-searches 方法击败简单的方法。可以通过对 (value,index) 的元组进行排序并按置换顺序访问 c[i][j] 来消除搜索。
猜你喜欢
  • 2012-04-23
  • 2020-12-13
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-28
  • 2016-09-24
  • 2013-05-14
相关资源
最近更新 更多