Если вы хотите скопировать данные в матрице, вы не сможете сделать это менее чем за O (N), будь то строка или столбец, за исключением малого N, где могут помочь аппаратные функции.
Однако, если ваши матрицы неизменны, вы можете использовать дым и зеркала, чтобы создать иллюзию наличия отдельного вектора-столбца.
Код ниже введен прямо в текстовое поле ответа и даже не был скомпилирован. Используйте на свой страх и риск!
Ваш тип матрицы определяется как структура, таким образом:
typedef struct
{
unsigned int refCount; // how many Matrixes are referencing this data ref
size_t lineWidth; // number of doubles between element at row = n, col = 0 and row = n +1, col = 0
double* data; // the actual data
} DataRef;
typedef struct
{
size_t rows; // num rows in matrix
size_t cols; // num cols in matrix
size_t dataOffset; // offset in doubles from the start of data of element at row = 0, col = 0
DataRef* data;
} Matrix;
Чтобы создать новую матрицу (я упустил всю обработку ошибок, чтобы сделать ее проще).
Matrix* matrix_create(size_t rows, size_t cols, const double* values)
{
Matrix* ret = calloc(1, sizeof *ret);
ret->rows = rows;
ret->cols = cols;
ret->dataOffset = 0;
ret->data = calloc(1, sizeof *dataRef);
ret->data->lineWidth = cols;
ret->data->data = allocateAndCopy(rows * cols, values); // mallocs a new block of doubles big enough for the values
ret->data->refCount = 1;
return ret;
}
Чтобы получить доступ к элементу (опять же, нет обработки ошибок, например, ошибки границ)
double matrix_elementAt(Matrix* matrix, size_t row, size_t col)
{
size_t offset = matrix->dataOffset + row * matrix->data->lineWidth + col;
return *(matrix->data->data + offset);
}
Чтобы создать новую матрицу из прямоугольной области другой матрицы (опять же, требуется обработка ошибок)
Matrix* matrix_createFromRegion(Matrix* old, size_t startRow, size_t startCol, size_t rows, size_t cols)
{
Matrix* ret = calloc(1, sizeof *ret);
ret->rows = rows;
ret->cols = cols;
ret->dataOffset = old->dataOffset + startRow * old->dataLineWidth + startCol;
ret->data = old->data;
ret->data->refCount++;
return ret;
}
Чтобы создать новую матрицу из столбца в другой матрице:
Matrix* vector = matrix_createFromRegion(aMatrix, 0, colYouWant, matrix_numRows(aMatrix), 1);
освободить матрицу
void matrix_free(Matrix* aMatrix)
{
if (aMatrix->data->refCount == 1)
{
free(aMatrix->data->data);
free(aMatrix->data);
}
else
{
aMatrix->data->refCount--;
}
free(aMatrix);
}
Если вам нужны изменяемые матрицы, каждый раз, когда вы изменяете элемент, проверьте refCount и, если он больше 1, скопируйте DataRef перед его изменением (уменьшите refCount для старого dataRef), в противном случае измените dataRef на месте.
Теперь вышеприведенное использует множество malloc и поэтому может быть менее эффективным, чем наивная реализация для маленьких матриц. Однако вы можете сохранить список неиспользуемых структур DataRef и структур Matrix, и вместо того, чтобы освобождать их, когда вы закончите, поместите их в свободный список. При размещении новых, получите структуры из свободных списков, если они не пусты. Таким образом, получение матрицы, представляющей столбец существующей матрицы, часто занимает постоянное время.