2

次のような配列がある場合:

int map[21][28] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

その配列内の値で構成されるより小さな配列を作成するにはどうすればよいですか?
このようなビット:

int zoomedMap[7][7] =
{

    2, 2, 1, 1, 1, 1, 1,
    1, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1
};

これが役立つかどうかはわかりませんが、次のとおりです。

  • 両方の配列の正確な次元を知っています
  • できればX/Y値を変更するだけで、より小さな配列の位置を移動できるようにしたい
4

4 に答える 4

1

うまくいけば明らかなことですが、サブ配列は文字通り、メイン配列内のデータの「ブロック」にすぎません (いくつかの興味深いパーティション分割があります)。境界をチェックしていて、境界外の状態が発生しないと仮定すると、ポインター演算とメイン配列に関するいくつかの基本情報を使用してサブ配列をシミュレートできます。

  • ブロックは常に[row][column]位置からオフセットされるため[0][0]、それらの値 (行と列) が必要です。
  • column+widthブロックの幅は、メイン配列の幅を超えないように固定されています。その幅が必要です。
  • row+heightブロックの高さは、メイン配列の高さを超えないように固定されています。その高さが必要です。
  • メイン配列であるベースアドレスが必要であることは明らかです(あなたの場合はmap)。

これは、おそらく例によって最もよく示されます。以下は、最終的な解決策ではありません。それは、あなたが持つであろうニーズの 10 分の 1 にも対処できない可能性があります。むしろ、探しているものを取得するために、ポインター、いくつかのオフセット、いくつかのサイズ、および少しの演算のみを使用してこれを行う方法についてのアイデアを提供することを目的としています。(単純な配列のように) 有害な制限を超えることを妨げるものは何もないので、用心してください。

// internal rerefential to a submatrix in a larger fixed matrix.
template<typename T>
class Sub2D
{
public:
    template<size_t R, size_t C>
    Sub2D(T(&ar)[R][C], int top, int left, int height, int width)
    : parent(ar[0])
    , row(top)
    , col(left)
    , max_row(R)
    , max_col(C)
    {
        if ((row+width) >= R || (col+height) >= C)
            throw std::out_of_range("");
    }

    // retrieve our subrow offset into the main 2D array
    T* operator [](size_t n)
    {
        // enable at your desire, but as Alex pointed out, all
        // the standard containers let you shoot yourself in the
        // foot with this operator. why not this one too =P
        //if (row+n >= max_row)
        //    throw std::out_of_range("");

        return parent + ((row+n)*max_col + col);
    }

private:
    T* parent;
    size_t row, col;
    size_t max_row, max_col;
};

質問の配列が基になっているものであると仮定すると、次のように使用されます。

int main()
{
    // take the submatrix & [6][7] that is 7x7 in dimension.
    Sub2D<int> sub(map, 6,7, 7,7);
    for (size_t i=0;i<7;++i)
    {
        for (size_t j=0;j<7;++j)
            cout << sub[i][j] << ' ';
        cout << endl;
    }
    cout << endl;

    // update an element at location [1][1] of our sub-matrix.
    sub[1][1] = 9;

    // reprint the *entire* main array. it better have updated.
    for (size_t i=0;i<sizeof(map)/sizeof(map[0]);++i)
    {
        for (size_t j=0;j<sizeof(map[0])/sizeof(map[0][0]);++j)
            cout << map[i][j] << ' ';
        cout << endl;
    }
    cout << endl;

    return 0;
}

次の出力が生成されます。

2 2 1 1 1 1 1 
1 0 0 0 0 0 1 
1 0 0 0 0 0 1 
1 0 0 0 0 0 1 
1 0 0 0 0 0 1 
1 0 0 0 0 0 1 
1 1 1 1 1 1 1 

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 2 2 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 9 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

9 が期待どおりの位置にあることに注目してください。

範囲チェックの改善、ポインタの移動、他のメモリバッファへのスナップショットなど、このようなテンプレートクラスに追加できることは明らかにもっとたくさんありますが、ポイントは基本的なget-me-thisサブマトリックスポインタと特にパフォーマンスに関しては、いくつかのオフセットを打ち負かすのは困難です。

于 2013-01-13T11:25:04.970 に答える
0

要件によっては、これで十分な場合があります。

int (*zoomedMap)[28] = reinterpret_cast<int (*)[28]>(&map[X][Y]);

これにより、2次元配列であるかのように使用できる識別子が得られますzoomedMap[i][j]。新しいアドレスを割り当てることで、ズームしたマップを大きな配列内で簡単に移動できます。

すべての参照が元の配列内に残っている場合は、C ++の実装に応じて、floatへのポインターをfloatの配列へのポインターにキャストできます。これは一般的です。

zoomedMap同じメモリをポイントしたままにしmapます。したがって、一方を変更せずにもう一方を変更することはできません。それをしたい場合は、コピーを作成する必要があります。

于 2013-01-13T13:38:08.707 に答える
0

ループを使用して常に静的に実行できます。

const int pos_x = 6, pos_y = 7, size_x = 7, size_y = 7;

int newMap[size_x][size_y] = {0};

for( int i = pos_x; i != pos_x+size_x; ++i ) {
    for( int j = pos_y; j != pos_y+size_y; ++j) {
        newMap[i-pos_x][j-pos_y] = map[i][j];
    }
}

これはあまり安全ではありませんが、動的に動作させるのは困難です。必要な機能を備えたマトリックス ラッパー クラスを作成することもできます。または、すでに存在するものを見つけて拡張します(既存のマトリックスクラスのSTLまたはBoostを調べ始めます)

于 2013-01-13T10:29:00.990 に答える
0

Boost のuBLASモジュールを読んでください。まさに探しているものである Matrix および MatrixRange クラスを提供します。

本質的に、zoomedMapはより大きな行列へのインテリジェントなポインタであり、逆参照して正しい結果を得る方法を理解しています。

于 2013-01-13T10:15:35.323 に答える