【问题标题】:How to make index in an vector as a pair of (x,y) coordinates?如何将向量中的索引作为一对(x,y)坐标?
【发布时间】:2018-08-12 07:06:12
【问题描述】:
#include<bits/stdc++.h>
using namespace std;

int main() {

     int i,j;
     vector<int> v(100);   // defined a vector of size 100

     for(i=1;i<=50;i++) {
         v[i]=i;             // storing the values as we do in 1-d array
     }

    for(int i=1;i<=50;i++) {

         cout<<"index="<<i<<" "<<v[i]<<"\n";  // It will give output similar 
                                               //   to 1-d array
    }
    return 0;
}

所以这是一维向量的情况,其中向量的索引是整数,值也是整数。以上代码运行良好。

但我想将向量的索引作为对 (i,j) 并将值作为整数。

请参阅下面的代码以获得更多说明。

    #include<bits/stdc++.h>
    using namespace std;

    int main() {

         int i,j;

         vector<pair<int,int>> ve(make_pair(100,100));   
         //defined a vector of size of indices (100,100)

         for(i=1;i<=50;i++) {

               for(j=0;j<=50;j++) {

                  ve[make_pair(i,j)]=2; // Storing value of 2 in all the 
                                        // (i,j) indices
              }
         }

        for(int i=1;i<=50;i++) {

             for(j=0;j<=50;j++) {

                  cout<<ve[make_pair(i,j)]<<" "; 
                  // Output should be 2 in all the possible pairs of (i,j)
             }
        }
        return 0;
    }

但是上面的代码不起作用:(。 请告诉我如何解决这个问题。

【问题讨论】:

  • 您混淆了元素类型和索引类型。首先,两者都是整数类型。在第二个中,您将元素类型切换为一对,但索引类型保持不变。
  • 也许您想停止使用这种#include&lt;bits/stdc++.h&gt; 废话并了解每个单独的标准标头的作用。其中一个或多个可能会提供您想要的设施。 OTOH 向量的向量可能正是您所需要的(ve[i][j] 更容易理解并且看起来并不难看)。
  • @n.m.我对标题非常了解。因此,您只需专注于回答问题。
  • @Deepak 在固定范围内,顺序,您最好以二维形式使用 std::array。我在下面的答案中的示例。不是矢量,当然也不是地图。

标签: c++ c++11 vector stl


【解决方案1】:

向量和数组一样,只能使用整数索引。对于向量 vec,索引必须0 &lt;= index &lt; vec.size() 范围内,否则它要么无法编译(不能转换为unsigned int),要么行为未定义(超出范围)。

你写了

vector<pair<int,int>> ve

这意味着您创建了一个包含对的向量,而不是按对索引。

现在,如果你想要一个二维向量,即矩阵,你应该检查Boost matrix。您也可以自己实现它,但使其通用化需要一些努力。基本思想是将对转换为单个整数值。最简单的实现是:

template <class T>
void init_2d(std::vector<T> &vec, std::pair<unsigned, unsigned> coordinates)
{
    vec.resize(coordinates.first * coordinates.second);
}
inline unsigned flatten(std::pair<unsigned, unsigned> coordinates,
            unsigned num_columns)
{
    return coordinates.first * num_columns + coordinates.second;
}

template <class T>
T & get_2d(std::vector<T> & vec, 
       std::pair<unsigned, unsigned> coordinates,
       unsigned num_columns)
{
    return vec.at(flatten(coordinates, num_columns));
}
template <class T>
const T & get_2d(const std::vector<T> & vec, 
         std::pair<unsigned, unsigned> coordinates,
         unsigned num_columns)
{
    return vec.at(flatten(coordinates, num_columns));
}

然后在你的代码中使用它:

int main() {

    std::vector<int> ve;
    auto dimensions  = std::make_pair(100,100);
    init_2d(ve, dimensions);

    for(int i=1;i<=50;i++) {
       for(int j=0;j<=50;j++)
         get_2d(ve, {i,j}, dimensions.second) =j; 
    }

    for(int i=1;i<=50;i++) {
        for(int j=0;j<=50;j++)
            std::cout << get_2d(ve, {i,j}, dimensions.second) <<" "; 
        std::cout << '\n';
    }
    return 0;
}

但是,您应该更喜欢使用 boost 矩阵,而不是重新实现现有代码。如果您正在尝试学习如何实现矩阵(这是一个非常好的主意),那么继续尝试将上述函数+向量转换为一个类,并将dimensions 对放入该类。对于矩阵来说,拥有一个类比使用单独的函数要好。维护类的不变量比维护单独的函数更容易。

注意:您可以改用std::map&lt;std::pair&lt;int, int&gt;&gt;,但迭代它会更困难,而且速度会慢得多。如果它使您的代码更清晰,使用std::map 是一个好主意,但不清楚std::map&lt;pair&lt;...&gt;&gt; 是否比std::vector + _2d 函数更易于使用。

【讨论】:

  • 二维向量只需要一行 C++ 代码:std::vector&lt;std::vector&lt;int&gt;&gt; tdv(100, std::vector&lt;int&gt;(100, 0));
  • @AmitG。向量和地图的向量都不完全是二维数组,就像我的答案不是一样。除了 boost 矩阵(或自己实现的矩阵),它们都是近似值。向量的向量需要为所有数组单独分配(可能隐藏在一行上)。
  • OP 询问二维向量。
  • 我讨厌 bug,所以我宁愿使用或编写一个类来防止更大类的 bug。我宁愿使用 boost 矩阵,或者编写我自己的矩阵。它将消除与矢量大小不同步相关的所有错误。
  • 另外,你可以写auto matrix::operator[](std::pair&lt;size_type, size_type&gt;) -&gt; reference;
【解决方案2】:

我建议您改用map

Operator [] for mapkey_type 作为参数,这是一个容器,这意味着您可以使用pair 对象作为索引(在映射中称为键),但是Operator [] for vetorsize_type 作为参数,它是一个无符号整数。

您的代码可能如下所示:

map< pair<int, int>, int > notVector;

for(i=0;i<=50;i++) 
    for(j=0;j<=50;j++)
        notVector[make_pair(i,j)]=2; // Storing value of 2 in all the (i,j) indices


for(i=0;i<=50;i++) 
    for(j=0;j<=50;j++) 
        cout<<notVector[make_pair(i,j)]<<" ";

【讨论】:

  • 但是你能告诉我向量实现有什么问题吗?
  • 因为它是这样实现的,所以我编辑了我的答案,请再看看@Deepak
【解决方案3】:

另一种解决方案:通过聚合标准容器来创建自己的容器。

极其简化的例子:

#include <vector>
#include <iostream>

struct xy
{

    std::size_t x, y;
};

constexpr std::size_t linear_extent(xy _)
{
    return _.y * _.x;
}

constexpr std::size_t linear_position(xy _, xy extent)
{
    return _.y * extent.x + _.x;
}

template<class T>
struct vector_2d
{
    vector_2d(xy size, T x = T())
    : extent_(size)
    , storage_(linear_extent(extent_), x)
    {

    }

    T& operator[](xy const& _)
    {
        return storage_[linear_position(_, extent_)];
    }

    T const& operator[](xy const& _) const
    {
        return storage_[linear_position(_, extent_)];
    }

    constexpr auto extent() const { return extent_; }

    xy extent_;
    std::vector<T> storage_;
};

template<class T>
std::ostream& operator<<(std::ostream& os, vector_2d<T> const& v)
{
    const char* sep = " [";
    os << "[";
    auto extent = v.extent();
    for(auto y = std::size_t(0) ; y < extent.y ; ++y)
    {
        os << sep;
        const char* sep2 = " ";
        for (auto x = size_t(0) ; x < extent.x ; ++x)
        {
            std::cout << sep2 << v[{x, y}];
            sep2 = ", ";
        }
        os << " ]";
        sep = "\n  [";
    }

    os << " ]";

    return os;
}


int main()
{
    auto v = vector_2d<int>({5, 5});
    v[{1, 3}] = 8;
    std::cout << v << std::endl;
}

【讨论】:

    【解决方案4】:

    保持简单

    您只需要 1(一个!)C++ 行:...+ 更新:可选宏(该宏用于回答 @eneski 评论):

    std::vector<std::vector<int>> ve(100, std::vector<int>(100, 0)); // Initialize to 0
    
    // Turns [wr(pair)] syntax to [pair.first][pair.second] syntax:
    #define wr(pr) (pr).first][(pr).second // Wrapper macro
    

    比使用:

    ve[wr(std::make_pair(i, j))] = 35; // For example  
    int val = ve[wr(std::make_pair(i, j))];
    // Or:
    ve[i][j] = 70; // For example
    val = ve[i][j];
    

    没有真正需要使用wr 包装宏。使用ve[i][j],如果你的代码中有std::pair p,使用:ve[p.first][p.second]而不是ve[p]——两者都是一样的。此外,将 (i, j) 和 make_pair on-the-fly 只是为了再次将它们用作 [i][j] 索引是无稽之谈。尽管如此,如果有人坚持使用语法,那么请使用 wr 包装宏。

    --

    但是,在固定顺序范围的情况下,2D std::array 是更好的选择(如果您坚持,您也可以添加包装宏):

    #include <array>
    
    int main()
    {
        int i = 7, j = 5;
    
        std::array<std::array<int, 100>, 100> ar; // 100 X 100
        ar[0].fill(0); ar.fill(ar[0]); // Initialize to 0
    
        ar[i][j] = 35; // For example
    
        return 0;
    }
    

    【讨论】:

    • 问题要求pair,但我在您的回答中看不到任何一对
    • 问题是“但我想将向量的索引作为对 (i,j) 并将值作为整数”并通过 ve[make_pair(i,j)] 阐明其用法。至少这是我所理解的。所以,我不认为你的回答是相关的。
    • @eneski 如果坚持非常精确的语法,而不是理解问题(即ve[make_pair(i, j)] 语法)而不是:@987654335 @ 并使用:ve[make_pair(i, j)]。当然,这里没有任何意义:OP 将 i, j 即时转换为 std::pair,只是为了再次使用 i, j 作为索引。或者,如果有人坚持索引类型,我也会在我的答案中添加一个更新来回答这个问题。
    • 我非常谨慎地建议使用不平衡的宏][
    • @Caleth Than,对于你来说,使用 #define VE(pt) ve[(pt).first][(pt).second] 宏,并使用:VE(std::make_pair(i, j)) = 35; // For example
    【解决方案5】:

    您是否只是尝试像访问 2d 矢量一样访问 1d 矢量内容?也许您可以使用辅助函数将 2d 索引转换为 1d 索引,例如:

    #include <vector> 
    #include <iostream>
    #include <cassert>
    
    template<size_t ROWS, size_t COLS>
    size_t convertIndex(size_t row, size_t col)
    {
        assert(row < ROWS && col < COLS);
        return row * COLS + col;
    }
    
    int main() 
    {
        std::vector<int> v =
        {
            0,1,2,3,4,
            5,6,7,8,9
        };
    
        std::cout << v[convertIndex<2, 5>(1, 3)];
    }
    

    This 输出8

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-10
      相关资源
      最近更新 更多