0

I need to sort negative elements of matrix by scheme below. I've tried to sort from another corner, but it is not working too. I think, that I need to put elems of matrix in 1d array. It should be sorted in Cocktail sort, but sort's type not my main problem.

Scheme

My code:

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++;
        }
    }
}
}
Bernardo Duarte
  • 4,074
  • 4
  • 19
  • 34
  • 1
    Suggestion: While developing and debugging comment out the `srand(time(NULL));`. The program will always generate the same random numbers and that makes it much easier to see the differences in the program behaviour between edits to the code. – user4581301 Dec 19 '19 at 19:55
  • @user4581301 It will not generate the same number because his `rand` is in the `for` loop. It will generate a new number every loop. – nakE Dec 19 '19 at 20:28
  • @nakE Apologies for being unclear. Without providing a different seed with `srand` every execution of the program will generate the same sequence of random numbers. This allows testing against the same matrix every time. – user4581301 Dec 19 '19 at 20:58
  • You shouldn't use srand anymore since was introduced about 10 years ago for several reasons: https://stackoverflow.com/questions/19665818/generate-random-numbers-using-c11-random-library/59019862#59019862 – Ingo Mi Dec 20 '19 at 08:37

1 Answers1

1

The question sounds easy, but it is not. There is a lot of “indirection” in it, where you need to work with indices instead of values.

I shortly checked you code. It is mostly C–Code (not C++) and buggy.

Example:

int t;
rt = t;

With that you have an uninitialized variable, used as an array index. That is a fatal bug. You are also using VLA’s (Variable Length Array). This is not allowed in C++. And you are using plain C-Style arrays. This you should not do. Use std::vector, which can grow dynamically or at least std::array instead. And please give your variable more meaningful names.

I will show you one (out of the many possible) solutions, but I will use C++.

The core of the problem at hand is to find the row and column indices of the elements in the given matrix. That is not easy.

But ok, let’s start with that. If you draw a picture with the matrix and then add dotted lines over the diagonals, then you see the indices.

enter image description here

If the dimension of the matrix is dim then there are always dim + dim – 1 diagonals. The diagonals have first a rising number of elements and after hitting the main, longest diagonal in the middle, decreasing number of elements. So we iterate over the number of all diagonals, split by the middle diagonal, and calculate the corresponding row and column indices. This is a bit tricky, but after some time you will find out.

The resulting row and column indices will be stored in a struct. All diagonals with all row and column indices will be stored in a vector of struct. Additionally, we add the values of the original matrix cells.

Regarding the sorting. It is obviously your task to develop an own sorting algorithm. For that purpose, I created a function yourSort where you can put in your own algorithm. I simply use standard algorithms (std::sort). You may replace std::sort by your own function.

In main I put some driver code. First, we create a matrix and fill it with random values. Then we calculate the row and column indices. The entries with the negative values will be extracted and sorted. Then we copy the result back to the original matrix.

As said above, not so easy, because of the indirection with the indices and the constraint to use only negative numbers.

But anyway. Please see:

#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;
}

A M
  • 14,694
  • 5
  • 19
  • 44