Логика цикла для хранения значений 2D-массива в одном векторе лайнера - PullRequest
0 голосов
/ 28 сентября 2018

У меня есть одно требование, где мне нужно сохранить 2 значения оси в векторе лайнера, некоторые значения, такие как [x = 0] [y = 1] и [y = 0] [x = 1], я не знаю, как сохранить

Я просто добавил i + j, чтобы найти индекс, но теперь он работает во всех случаях

У меня 0> = x <= 200 и 0> = y <= 103 </p>

где x приращение x = x + 1 y приращение y = y + 1.5

есть ли какая-либо общая формула, которую я могу вывести для линейного сохранения всех данных

Ответы [ 3 ]

0 голосов
/ 28 сентября 2018

Ваше описание расплывчато.Но я могу понять, что вы хотите хранить значения из двумерных индексов в одномерном массиве.Общая техника состоит в том, чтобы использовать что-то вроде следующего:

Предположим, row, col являются двумерными индексными координатами

<1-d index> = <max number of columns> * row + col
0 голосов
/ 28 сентября 2018

Если я правильно понял, вам нужен способ хранения двумерного массива с плавающей запятой в C ++.Вам понадобится некоторое преобразование, потому что C ++ «поддерживает только одномерные массивы» (это не совсем верно, но мы будем притворяться, что это так).

Сначала нам нужно узнать диапазоны и приращения.Вы предоставили их, и для X диапазон составляет [0, 200], а для Y [0, 103] с приращениями 1 и 1.5 соответственно.

Это означает, что у нас есть ((200-0)/1) = 200 возможных значений для X и ((103-0)/1.5) = 68.666... возможные значения для Y. Мы выберем 69 возможных значений для Y.

Итак, у нас может быть следующий массив:

int my_array_of_ints[69 * 200];

Например, элемент [X=0][Y=0] будетбудет нашим [0 * 69 + 0] индексом (элемент my_array_of_ints[0]), в то время как наш [X=1][Y=1.5] будет нашим [1 * 69 + 1] индексом (элемент my_array_of_ints[70]).Обратите внимание, что у нас не может быть элементов с [Y = 0,5] или [Y = 1], потому что приращение Y установлено на 1,5 (т. Е. Y должно быть 0 или 1,5 или 3 или 4,5 или 6 или ...).

Эта функция для преобразования 2D-индекса в 1D-линейный индекс будет иметь вид:

#include <cmath>

int get_element(float x, float y){
    int index_x = std::round(x / 1);
    int index_y = std::round(y / 1.5);
    if ((0 <= index_x) && (index_x < 200) &&
        (0 <= index_y) && (index_y < 69)){
        return my_array_of_ints[index_y * 200 + index_x];
    } else {
         // You should decide what to do if x or y is out-of-range
         return 0;
    }
}

Где:

  • 1 - это приращение x
  • 1.5 - приращение y
  • 200 - количество возможных значений x в этом диапазоне с этим приращением
  • 69 - количество возможных значений yв этом диапазоне с этим приращением.

Итак, мы могли бы сделать что-то вроде этого:

get_element(1, 1.5)

И оно вернуло бы значение [X=1][Y=1.5] внутри my_array_of_ints.

Оборачивание этого кода вокруг класса, шаблонизация типа массива, обобщение диапазонов и приращений и предоставление фиктивной основной:

#include <cmath>
#include <iostream>

template <typename Datatype> class Vector2D {
    float x_increment;
    float x_minimum;
    float x_maximum;

    float y_increment;
    float y_minimum;
    float y_maximum;

    // For example, Y range [0, 103] with increment 1.5
    // results in 69 possibles values for Y, and we need to
    // remember to "linearize" the indexes
    int x_possibles;
    int y_possibles;

    Datatype *array;
    public:
    Vector2D(float x_increment, float y_increment,
             float x_maximum, float y_maximum,
             float x_minimum=0, float y_minimum=0)
        : x_increment(x_increment), x_minimum(x_minimum),
          x_maximum(x_maximum), y_increment(y_increment),
          y_minimum(y_minimum), y_maximum(y_maximum),

          // These two may seem arcane, but they are the
          // generalization of how we found the values initially
          x_possibles(std::ceil((x_maximum-x_minimum)/x_increment)),
          y_possibles(std::ceil((y_maximum-y_minimum)/y_increment)),
          array(new Datatype[y_possibles * x_possibles]) {

        // This may help to understand this 2D Vector
        std::cout << "Creating 2D vector X in range ["
            << x_minimum << ", " << x_maximum
            << "] with increment of " << x_increment
            << " (totalizing " << x_possibles
            << " possible values for x) "
            << " and Y in range [" << y_minimum
            << ", " << y_maximum << "] with increment of "
            << y_increment << " (totalizing " << y_possibles
            << " values for y)."
            << std::endl;
    }

    // Frees up the raw array
    ~Vector2D(){
        delete this->array;
    }

    Datatype& get_element(float x, float y){
        int index_x = std::round((x-x_minimum)/this->x_increment);
        int index_y = std::round((y-y_minimum)/this->y_increment);

        // This debug message may help understand this function
        // It is, in some sense, the answer of this question
        std::cout << "The 2D point [X=" << x << ", Y=" << y
                  <<  "] is mapped into the vector index ["
                  << index_y << " * " << x_possibles
                  << " + " << index_x << "]" << std::endl;

        if ((0 <= index_x) && (index_x < x_possibles) &&
            (0 <= index_y) && (index_y < y_possibles)){
            return this->array[index_y * x_possibles + index_x];
        } else {
            // You should decide what to do if x or y is out-of-range
            return this->array[0];
        }
    }
};


int main(){
    // And you could use that class like this:

    // A 2D-like vector with X [0, 200] inc. 1
    // and Y [0, 103] inc. 1.5 of floats
    Vector2D<float> my_data(1, 1.5, 200, 103, 0, 0);

    // Sets [X=1][Y=1] to 0.61345
    my_data.get_element(1, 1) = 0.61345;

    auto elem1 = my_data.get_element(1, 1);
    // Prints the [X=1][Y=1] to screen
    std::cout << "[X=1][Y=1] is "
              << elem1
              << std::endl;

    // Gets a few more interesting points
    my_data.get_element(0, 0);
    my_data.get_element(1, 1.5);
    my_data.get_element(10, 15);
    my_data.get_element(200, 103);

    // A separator
    std::cout << "---" << std::endl;

    // Another example, this time using chars
    // X is [-10, 1] inc. 0.1 and Y is [-5, 3] inc. 0.05
    Vector2D<char> my_chars(0.1, 0.05, 1, 3, -10, -5);

    // Sets [X=-4.3][Y=2.25] to '!'
    my_chars.get_element(-4.3, 2.25) = '!';

    auto elem2 = my_chars.get_element(-4.3, 2.25);
    std::cout << "[X=-4.3][Y=2.25] is "
              << elem2
              << std::endl;

}

Выходы:

Creating 2D vector X in range [0, 200] with increment of 1 (totalizing 200 possible values for x)  and Y in range [0, 103] with increment of 1.5 (totalizing 69 values for y).
The 2D point [X=1, Y=1] is mapped into the vector index [1 * 200 + 1]
The 2D point [X=1, Y=1] is mapped into the vector index [1 * 200 + 1]
[X=1][Y=1] is 0.61345
The 2D point [X=0, Y=0] is mapped into the vector index [0 * 200 + 0]
The 2D point [X=1, Y=1.5] is mapped into the vector index [1 * 200 + 1]
The 2D point [X=10, Y=15] is mapped into the vector index [10 * 200 + 10]
The 2D point [X=200, Y=103] is mapped into the vector index [69 * 200 + 200]
---
Creating 2D vector X in range [-10, 1] with increment of 0.1 (totalizing 110 possible values for x)  and Y in range [-5, 3] with increment of 0.05 (totalizing 160 values for y).
The 2D point [X=-4.3, Y=2.25] is mapped into the vector index [145 * 110 + 57]
The 2D point [X=-4.3, Y=2.25] is mapped into the vector index [145 * 110 + 57]
[X=-4.3][Y=2.25] is !

Надеюсь, что это может помочь.

0 голосов
/ 28 сентября 2018
vector_1d_index = vector_2d_row_index * vector_2d_row_length + vector_2d_column_index

... при условии, что ваш 2D-вектор i) главный ряд и ii) прямоугольный (строки одинаковой длины).

(vector_1d_size = vector_2d_row_count * vector_2d_row_length).

...