generate unique numbers to 2-Dimensional array using linear search

740 views Asked by At

The program compiles and I can enter a number, but it doesn't generate or it display the array. When I take out the while condition with the linear search in the randomFillUnique function, it generates and displays the array, but not unique numbers. I needed a 2D array with no duplicate numbers.

#include <iostream>
#include <string>
#include <random>
#include <ctime>
using namespace std;

int** gen2Array(int n);
void randomFillUnique(int** arr, int n);
bool lSearch(int** arr, int n, int target);
void display(int** arr, int n);

int main()
{
    int number;
    cout << "Enter a number: ";
    cin >> number;
    randomFillUnique(gen2Array(number), number);
    system("pause");
    return 0;
}
int** gen2Array(int n)
{
    int** arr2D = new int*[n];
    for (int index = 0; index < n; index++)
        arr2D[index] = new int[n];
    return arr2D;
}
void randomFillUnique(int** arr, int n)
{
    static default_random_engine e;
    uniform_int_distribution<int> u(1, n*n);
    e.seed(static_cast<int>(time(NULL)));

    bool result = false;
    for (int row = 0; row < n; row++)
    {
        for (int col = 0; col < n; col++)
        {
            arr[row][col] = u(e);   //generate random number
            result = lSearch(arr, n, arr[row][col]);
            while (result == true)
            {
                arr[row][col] = u(e);   //generate random number
                result = lSearch(arr, n, arr[row][col]);
            }
        }
    }
    display(arr, n);
    delete[] arr;
}
bool lSearch(int** arr, int n, int target)
{
    bool found = false;
    for (int row = 0; row < n; row++)
        for (int col = 0; col < n; col++)
        {
            if (arr[row][col] == target)
            {
                found = true;
                return found;
            }
        }
    return found;
}
void display(int** arr, int n)
{
    for (int row = 0; row < n; row++)
    {
        for (int col = 0; col < n; col++)
            cout << arr[row][col];
        cout << endl;
    }
}
3

There are 3 answers

2
Jeremy Kahan On BEST ANSWER

Because you are setting the entry in the array to u(e) before you lsearch, lsearch always returns true and your while loops forever. The below, adapted from your code, should fix that (I am assuming the rest of the code behaves as one would expect). As user4581301 points out, there may be better approaches, but I am going with yours enough to get it working, I hope.

void randomFillUnique(int** arr, int n)
{
static default_random_engine e;
uniform_int_distribution<int> u(1, n*n);
e.seed(static_cast<int>(time(NULL)));
int nextEntry;
bool result = false;
for (int row = 0; row < n; row++)
{
    for (int col = 0; col < n; col++)
    {
        result = true;
        while (result == true)
        {
            nextEntry = u(e);   //generate random number
            result = lSearch(arr, n, nextEntry);
            if (result != true)
               {arr[row][col]=nextEntry;}
        }
    }
}
display(arr, n);
delete[] arr;
}
1
Jack Deeth On

An alternative approach would be to create a container of all the unique integers which will go into the array, using iota:

std::vector<int> invalues(n*n, 0);
std::iota(invalues.begin(), invalues.end(), 1);

Then shuffle that container:

std::shuffle(invalues.begin(), invalues.end(),
             std::mt19937{std::random_device{}()});

Then feed the values one by one into the matrix.

You could also use a vector<vector<int>> instead of built-in arrays:

using matrix = std::vector<std::vector<int>>;

// initialising a vector<vector<int>> to be a certain size is a bit clumsy
matrix m(size_y, std::vector<int>(size_x, 0));

Then feeding the input values into the matrix:

for (auto &row : m) {
  for (auto &elem : row) {
    elem = invalues.back();
    invalues.pop_back();
  }
}

Then displaying the matrix:

for (const auto &row : m) {
  for (const auto &elem : row) {
    std::cout << elem << " ";
  }
  std::cout << std::endl;
}

Here's a full example in an online compiler.

1
user4581301 On

OK. Here's the easier way to do this I commented on. If std::vector is disallowed, a simple 1D vector will suffice, but a sane software engineer would think really, really hard before selecting it over a vector.

I made a few other changes to fix a couple other bugs.

#include <iostream>
#include <string>
#include <random>
#include <vector>
#include <algorithm> // std::shuffle and std::iota
#include <ctime>
using namespace std;

int** gen2Array(int n);
void randomFillUnique(int** arr, int n);
bool lSearch(int** arr, int n, int target);
void display(int** arr, int n);
//Added to properly delete the 2dArray
void del2Array(int ** arr, int n);

int main()
{
    int number = 10;
    randomFillUnique(gen2Array(number), number);
    system("pause");
    return 0;
}
int** gen2Array(int n)
{
    int** arr2D = new int*[n];
    for (int index = 0; index < n; index++)
        arr2D[index] = new int[n];
    return arr2D;
}

//Added to properly delete the 2dArray
void del2Array(int ** arr,
               int n)
{
    for (int index = 0; index < n; index++)
        delete arr[index];
    delete arr;
}
void randomFillUnique(int** arr, int n)
{
    //do the seeding here
    static default_random_engine e(static_cast<int>(time(NULL)));
// otherwise
//    e.seed(static_cast<int>(time(NULL)));
// runs every time reseeding the RNG to potentially the give the same results
// if run more than once in a second. Plus the seeding is expensive.

    std::vector<int> v(n*n); // make and size vector
    std::iota (v.begin(), v.end(), 0); // init vector with 1 through n*n
    std::shuffle(v.begin(), v.end(), e);

    size_t index = 0;
    for (int row = 0; row < n; row++)
    {
        for (int col = 0; col < n; col++)
        {
            arr[row][col] = v[index++];   //generate random number
        }
    }
    display(arr, n);
    del2Array (arr, n); // frankly I don't think you want his here
                        // why fill an array only to delete it?
                        // more logical to display and delete back in main.
}

void display(int** arr, int n)
{
    for (int row = 0; row < n; row++)
    {
        for (int col = 0; col < n; col++)
            cout << arr[row][col] << "\t"; //added a tab to make the printing easier to read
        cout << endl;
    }
}

Documentation on std::vector

Documentation on std::shuffle

Documentation on std::iota. Which uses exactly this technique to demonstrate iota. Funny, huh?