【问题标题】:Simple array use in C++?在 C++ 中使用简单的数组?
【发布时间】:2012-02-22 03:10:49
【问题描述】:

我有一个正方形网格。每个方块要么是黑色的,要么是白色的。网格范围从 X:-10 到 10 和 Y:-10 到 10。我想用 2D 布尔数组表示网格 - 黑色为真,白色为假。数组索引只是正数——所以如果我想用数组创建网格,它会是bool array [21][21]。这可以完成工作,但是当我尝试访问元素时会变得混乱。例如,如果我想访问网格上的坐标“0,3”,我的数组索引将是 [11][14]。这行得通,但它真的很乱。

是否有任何“更清洁”的方式可以让索引与坐标对应?

【问题讨论】:

  • 如果每个轴上的网格范围从 -10 到 10,那么您的数组不应该是 21 x 21 的网格吗?
  • @AndréCaron 你的权利。我修好了。

标签: c++ c arrays algorithm containers


【解决方案1】:

您可以将逻辑封装到提供所需接口的类中。为了使它有点通用,您可以考虑要存储的类型和维度可能会有所不同:

 template <typename T, int DimX, int DimY>
 class offset_array2d
 {
    T data[ DimX*DimY ];
    static const int offset_x = DimX / 2;
    static const int offset_y = DimY / 2;
 public:
    offset_array2d() : data() {}
    T& operator()( int x, int y ) {
       return data[ (x+offset_x) + (y+offset_y)*DimY ];
    }
    T const & operator()( int x, int y ) const {
       return data[ (x+offset_x) + (y+offset_y)*DimY ];
    }
 };

实现可能需要一些细节,但总体思路就在那里。应该有错误报告和更多的东西......维度可以作为运行时属性(而不是模板参数),但这需要动态分配、适当的析构函数和复制构造函数......我真的不想进入所有这一切只是为了这个想法。

频谱的另一端是用户代码,现在很简单:

 int main() {
    offset_array2d<bool,21,21> board;
    for ( int i = -10; i < 11; ++i )
      board( i, i ) = true;          // write the diagonal
 }

【讨论】:

  • 关于构造函数:offset_array2d(): data() {} 应该可以完成这项工作......我想它应该是 + 而不是 -offset_x 中的 -
  • @MatthieuM.:您在这两个帐户上都是对的,感谢您指出错误。
  • @DavidRodríguez-dribeas:我很高兴 :) 这一次我注意到它们而不是制造它们!
【解决方案2】:

您可以通过一个函数简单地访问您的数组,该函数将计算数组中的正确偏移量(x 和 y 加 10):

bool grid[21][21];

bool getSquareColour(size_t x, size_t y)
{
   // add bounds checking here
   return grid[x+10][y+10];
}

设置正方形也是如此。我会将所有这些包装到一个 Grid 类中。

您可能还想使用std::vector&lt;bool&gt; 而不是bool[],它将每个bool 存储为单独的位,并为您提供std::vector 类的额外(可能不需要)功能。

【讨论】:

  • 要覆盖域 -10 .. +10,您需要将数组设置为 [21][21]。
  • @BicycleDude:糟糕,复制+粘贴了array 的OP(现已编辑)声明,甚至没想过要检查它,谢谢。
  • @AusCBloke bool grid[21][21] 仍然小于它可以被替换的 std::vector 的实现。更别提数据了。为什么要增加复杂性!?
  • @Daniel:这只是对他将来可能做的任何其他事情的建议,我知道像这样的小事完全没有必要。
  • 小窍门:将返回类型更改为bool &amp;,然后您就不需要设置器了:getSquareColour(5, 5) = false 可以工作。
【解决方案3】:

我很确定这会调用未定义的行为。我也很确定这适用于我关心的每一个架构。

#include <cassert>


int main () {
   bool grid_[21][21];
   bool (*grid)[21];

   grid = (bool (*)[21])(&grid_[10][10]);
   assert(&grid_[0][0] == &grid[-10][-10]);
   assert(&grid_[0][20] == &grid[-10][10]);
   assert(&grid_[20][20] == &grid[10][10]);
}

【讨论】:

    【解决方案4】:

    你应该做一个辅助函数

    #define OFFSET 10
    
    void place_elem(int x, int y, bool color){
    
         //put bounds checks here
         a[OFFSET+x][OFFSET+y] = color;
    
    }
    

    所以

    place_elem(0, -3, true) == (a[10][7] = true)

    如果您担心对数组的每次更改都进行函数调用的开销,那么您可以改用宏:

    #define PLACE_ELEM(x, y, c) (a[OFFSET+x][OFFSET+y] = c)
    

    但是,除非您完全了解使用宏的安全问题,否则不要这样做。此外,如果您使用 C99 或 C++,您可以使用内联方法/函数。这将做同样的事情,但没有危险。

    此外,枚举可能比布尔值更好

    思考:

    enum Color {BLACK, WHITE};
    

    【讨论】:

    • 在这种情况下并不重要,但枚举通常不会占用 int 的大小吗?因此将他的尺寸要求增加sizeof(int)?在更大的网格中可能很重要。
    • 你是对的,但有时为了清晰是值得的
    【解决方案5】:

    只是为了提供一个易于使用(但有点难以实现和维护)的替代答案,创建一个使用 getter 和 setter 隐藏复杂性的 C++ 类。您还可以考虑重载运算符。由于该字段是二进制的,因此我选择使用按位运算来打包数据:

    class SimpleArray
    {
    public:
      SimpleArray()
      {
        memset(data, 0, sizeof(data));
      }
    
      void set(int x, int y, bool value)
      {
        if (x >= -10 && x <= 10 && y >= -10 && y <= 10)
        {
          if (value)
          {
              data[y + 10] |= (1 << (x + 10));
          }
          else
          {
              data[y + 10] &= ~(1 << (x + 10));
          }
        }
      }
    
      bool get(int x, int y)
      {
        if (x >= -10 && x <= 10 && y >= -10 && y <= 10)
        {
          return (data[y + 10] & (1 << (x + 10))) != 0;
        }
        return false;
      }
    
      private:
        unsigned int data[21];
    };
    

    【讨论】:

      【解决方案6】:

      我将创建一个整数映射(map),而不是增加/减少您的索引,您可以在其中将特定索引分配给您的特定值。

      然后,您可以将映射的值传递给您的平方值(例如,您在平方表中将映射的结果传递给键值 -10 => 0(索引))。

      这里有一个地图示例: http://www.yolinux.com/TUTORIALS/CppStlMultiMap.html

      当然地图比一个简单的函数使用更多的内存,但它的可重用性更好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-30
        • 2011-03-15
        相关资源
        最近更新 更多