按方案对矩阵进行排序

时间:2019-12-19 19:44:13

标签: c++ sorting matrix

我需要按以下方案对矩阵的负元素进行排序。我试图从另一个角度进行排序,但是它也不起作用。我认为,我需要将矩阵元素放入一维数组中。应该按鸡尾酒排序,但是排序的类型不是我的主要问题。

Scheme

我的代码:

int main() {
const int n = 4, m = 4;

int t, v[n*m], arr[n][m], i, j, tmp, lt, rt;
lt = 0;
rt = t;

srand(time(NULL));

for (i = 0; i < n; i++) {
    for(j=0; j < m; j++) {
        arr[i][j] = rand() % 100 - 50;
    }
    cout << endl;
}
t = 0;

for (i = 0; i < n; i++) {
    for(j = 0; j < m; j++) {
        if (arr[i][j] < 0) {
        v[t] = arr[i][j];
        t++;    
        }

    }
}

while(lt <= rt) {
    for (i = rt; i >= lt; i--) {
        if(v[i] > v[i-1]) {
            swap(v[i], v[i-1]);
        }
    }

    lt++;

    for (i = lt; i <=rt; i++) {
        if(v[i] > v[i-1]) {
            swap(v[i], v[i-1]); 

        }
    }
    rt--;
}


for (i = 0; i < t; i++) {
    cout << v[i] << " ";
}

int r = 0;

for (i = 0; i < n; i++) {
    for(j = 0; j < m; j++) {
        if(arr[i][j] < 0) {
            arr[i][j] = v[r];
            r++;
        }
    }
}
}

1 个答案:

答案 0 :(得分:1)

这个问题听起来很简单,但事实并非如此。其中有很多“间接”,您需要在其中使用索引而不是值。

我很快检查了您的代码。主要是C代码(不是C ++)和越野车。

示例:

int t;
rt = t;

具有一个未初始化的变量,用作数组索引。那是一个致命的错误。您还使用了VLA(可变长度数组)。这在C ++中是不允许的。您正在使用纯C样式数组。您不应该这样做。使用std::vector,它可以动态增长,也可以至少增长std::array。并请给您的变量更有意义的名称。

我将向您展示(一种可能的)解决方案,但是我将使用C ++。

当前问题的核心是找到给定矩阵中元素的行和列索引。那不容易。

但是好的,让我们开始吧。如果您使用矩阵绘制图片,然后在对角线上添加虚线,则会看到索引。

enter image description here

如果矩阵的维数为dim,则总是有dim + dim – 1个对角线。对角线首先具有增加的元素数,然后在中间的主要最长的对角线上命中,元素数量减少。因此,我们遍历所有对角线的数量,除以中间对角线,然后计算相应的行和列索引。这有点棘手,但是一段时间后您会发现。

结果行和列索引将存储在结构中。具有所有行和列索引的所有对角线将存储在struct向量中。此外,我们将原始矩阵单元的值相加。

关于排序。开发自己的排序算法显然是您的任务。为此,我创建了一个函数yourSort,您可以在其中放入自己的算法。我只是使用标准算法(std::sort)。您可以用自己的函数替换std::sort

主要,我放置了一些驱动程序代码。首先,我们创建一个矩阵,并用随机值填充它。然后我们计算行索引和列索引。具有负值的条目将被提取并排序。然后,将结果复制回原始矩阵。

如上所述,由于索引的间接性和仅使用负数的约束,所以不太容易。

但是无论如何。请参阅:

#include <iostream>
#include <vector>
#include <utility>
#include <random>
#include <algorithm>
#include <iterator>
#include <iomanip>

// Create types that are easy to understand
using RowIndex = size_t;
using ColumnIndex = size_t;

// Here we store the position (row and column) and the value of one cell in the matrix
struct PositionAndValue {
    // Constructors
    PositionAndValue() {};
    PositionAndValue(const RowIndex r, const ColumnIndex c, const int v) : rowIndex(r), columnIndex(c), value(v) {};
    // Data
    RowIndex rowIndex{};
    ColumnIndex columnIndex{};
    int value{};
};

// Main data types
using Columns = std::vector<int>;
using Matrix = std::vector<Columns>;
using Diagonal = std::vector<PositionAndValue>;

// Fill matrix with random values. Standard function
void fillMatrixRandom(Matrix& m) {
    std::random_device rd;  
    std::mt19937 gen(rd()); 
    std::uniform_int_distribution<> dis(-50, 50);
    std::for_each(m.begin(), m.end(), [&](Columns &c) {std::for_each(c.begin(), c.end(), [&](int &j) { j = dis(gen);}); });
}

// Calculate the indices for all diagonals
Diagonal calculateDiagonalIndices(const Matrix& matrix) {

    // The return value
    Diagonal diagonalIndices{};

    // Matrix dimension
    const size_t MatrixDimension{ matrix.size() };
    // Overall number of diagonals for this matrix
    const size_t NumberOfDiagonals{ MatrixDimension + MatrixDimension - 1 };
    // index of middle (longest) diagonal
    const size_t MiddleDiagonal { NumberOfDiagonals / 2 + 1 };

    // Counter for element index in one specific diagonal
    size_t elementInDiagonal{ 0 };

    for (size_t diagonalIndex = 1; diagonalIndex <= NumberOfDiagonals; ++diagonalIndex) {
        // If we are above the middle diagonal
        if (diagonalIndex <= MiddleDiagonal) {
            // Number of elements in diagonal will increase
            ++elementInDiagonal;
            for (size_t j = 0; j < elementInDiagonal; ++j) {
                // Calculate row and column and add to result
                const RowIndex row{ j };
                const ColumnIndex col{ diagonalIndex - j - 1 };
                diagonalIndices.emplace_back(PositionAndValue(row, col, matrix[row][col]));
            }
        }
        else {
            // We are below the middle diagonal
            // Number of elements in diagonal will decrease
            --elementInDiagonal;
            for (size_t j = 0; j < elementInDiagonal; ++j) {
                // Calculate row and column and add to result
                const RowIndex row{ diagonalIndex + j - MatrixDimension };
                const ColumnIndex col{ MatrixDimension - j - 1 };
                diagonalIndices.emplace_back(PositionAndValue(row, col, matrix[row][col]));
            }
        }
    }
    return diagonalIndices;
}

// Simple sorting function using std algorithms
template <typename T, typename ValueType>
void yourSort(std::vector<T>& vec, ValueType T::* mPtr) {
    // We will extract the negative values
    std::vector<ValueType> vt{};
    // Extract
    std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T & s) {return s.*mPtr; });

    // Sort. ***** Please put here your sorting function
    std::sort(vt.begin(), vt.end());

    // Put back
    std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable{s.*mPtr = vt[i++]; });
}
// Driver code
int main() {
    // Lets use a matrix of this size
    constexpr size_t MatrixDimension = 4U;

    // Small lambda for printing a matrix
    auto printMatrix = [](const Matrix & m) {std::for_each(m.begin(), m.end(), [](const Columns & c) {
        for (int i : c) std::cout << std::setw(4) << i; std::cout << "\n"; }); std::cout << "\n"; };

    // Define a matrix and fill it with random values
    Matrix matrix(MatrixDimension, Columns(MatrixDimension));
    fillMatrixRandom(matrix);
    printMatrix(matrix);

    // Calulate the indices on the diagonals
    Diagonal diagonal{ calculateDiagonalIndices(matrix) };

    // Extract the negatives
    Diagonal negativesOnDiagonal{};
    std::copy_if(diagonal.begin(), diagonal.end(), std::back_inserter(negativesOnDiagonal),
        [](const PositionAndValue & pv) { return pv.value < 0; });

    // Sort
    yourSort(negativesOnDiagonal, &PositionAndValue::value);

    // Copy back
    std::for_each(negativesOnDiagonal.begin(), negativesOnDiagonal.end(),
        [&matrix](const PositionAndValue & pv) { matrix[pv.rowIndex][pv.columnIndex] = pv.value; });

    printMatrix(matrix);
    return 0;
}