Bijective mapping of integers - c++

English is not my native language: sorry for my mistakes. Thank you in advance for your answers.
I'm learning C++ and I'm trying to check to what extent two sets with the same number of integers--in whatever order--are bijective.
Example :
int ArrayA [4] = { 0, 0, 3, 4 };
int ArrayB [4] = { 4, 0, 0, 3 };
ArrayA and ArrayB are bijective.
My implementation is naive.
int i, x=0;
std::sort(std::begin(ArrayA), std::end(ArrayA));
std::sort(std::begin(ArrayB), std::end(ArrayB));
for (i=0; i<4; i++) if (ArrayA[i]!=ArrayB[i]) x++;
If x == 0, then the two sets are bijective. Easy.
My problem is the following: I would like to count the number of bijections between the sets, and not only the whole property of the relationship between ArrayA and ArrayB.
Example :
int ArrayA [4] = { 0, 0, 0, 1 }
int ArrayB [4] = { 3, 1, 3, 0 }
Are the sets bijective as a whole? No. But there are 2 bijections (0 and 0, 1 and 1).
With my code, the output would be 1 bijection. Indeed, if we sort the arrays, we get:
ArrayA = 0, 0, 0, 1;
ArrayB = 0, 1, 3, 3.
A side-by-side comparaison shows only a bijection between 0 and 0.
Then, my question is:
Do you know a method to map elements between two equally-sized sets and count the number of bijections, whatever the order of the integers?
Solved!
The answer given by Ivaylo Strandjev works:
Sort the sets,
Use the std::set_intersection function,
Profit.

You need to count the number of elements that are contained in both sets. This is called set intersection and it can be done with a standard function - set_intersection, part of the header algorithm. Keep in mind you still need to sort the two arrays first.

Related

Create Array as Vector with 10 Million elements and assign random numbers without duplicates

I try to code myself a Table with random generated Numbers. While that is simple as it is, causing that Vector not having any duplicates isn't as easy as I thought. So far my Code looks like that:
QStringList generatedTable;
srand (QTime::currentTime().msec());
std::vector<int> array(10000000);
for(std::size_t i = 0; i < array.size(); i++){
array[i] = (rand() % 10000000000)+1;
}
It generates numbers just fine, but because I'm generating a large amount of array elements (10 Million), even though I'm using 10 Billion possible numbers, it will create duplicates. I already browsed a bit and found something that seems handy to use, but doesn't work properly in my Program. The code is from another stackoverflow User:
#include<iostream>
#include<algorithm>
#include<functional>
#include<set>
int main()
{
int arr[] = {0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1};
std::set<int> duplicates;
auto it = std::remove_if(std::begin(arr), std::end(arr), [&duplicates](int i) {
return !duplicates.insert(i).second;
});
size_t n = std::distance(std::begin(arr), it);
for (size_t i = 0; i < n; i++)
std::cout << arr[i] << " ";
return 0;
}
It basically moves all the duplicates to the end of the Array, but for some reason does it not work anymore when the array gets bigger. The code will always place the iterator n at 32.768 as long the Array stays above a Million. Under a Million it drops slightly to ~31.000. So while the code is nice it doesn't really help me alot. Does someone have a better option I could use? Since I'm still a Qt and C++ beginner do I not know how to solve that problem properly.
If you want to sample N integers without replacement from the range [low, high) you can write this:
std::vector<int> array(N); // or reserve space for N elements up front
auto gen = std::mt19937{std::random_device{}()};
std::ranges::sample(std::views::iota(low, high),
array.begin(),
N,
gen);
std::ranges::shuffle(array, gen); // only if you want the samples in random order
Here's a demo.
Note that this requires C++20, otherwise the range to be sampled from can't be generated lazily, which would require it to be stored in memory. If you want to write something similar before C++20, you can use the range-v3 library.
The simplest but at the same time most efficient thing is to implement a binary search tree. Generate the random number in your range and check if it's not already there. Note that the operations are performed in a time O(n)

How to compare all elements of vector one to vector two and if a max element exists then comparing all the elements of vector two to vector three?

I want to compare all element of vector x to all elements of vector y and if I find a element greater in vector y than being compared to, I have to take that particular element of vector y and compare to all elements of vector z and if it is true return true else if i don't find a greater element in first iteration i,e when elements of vector x are compared to vector y i have to break the loop and return false.
I tried to iterate through all the elements of stackarmies but I don't know how to take the first element of vector one and compare with all the elements of vector, since all the vectors are merged into the last vector.
vector<int> stack;
int noofstack, noofoperations, stackno, OperationType;
// Taking the input number of stacks
cin >> noofstack;
vector<vector<int>> stackarmies;
for (int i = 0; i < noofstack; i++)
{
int stacksize;
//Since vectors are dynamic and we don't need to declare the size but as per the problem statement I've added it/
cin >> stacksize;
for (int k = 0; k < stacksize; k++)
{
//Taking the input of all the vectors one by one and then adding all the vectors into one vector
int armyheight;
cin>>armyheight;
stack.push_back(armyheight);
}
stackarmies.push_back(stack);
Test cases
Input 1
2
3 3 5 4
3 1 1 2
Resulting stackarmies: { {3, 5, 4}, {3, 5, 4, 1, 1, 2} }
Desired output: False
We will take first element of vector 1 : 3 and compare with all
elements of vector 2 , in vector 2 no element is greater than 3.
Input 2
2
3 1 0 4
3 2 1 3
Resulting stackarmies: { {1, 0, 4}, {1, 0, 4, 2, 1, 3} }
Desired output: True
We will take first element of vector 1 : 1 and compare with all
elements of vector 2, in vector 2, the first element is greater than 1,
so true
Input 3
2
3 1 9 0
2 0 11
Resulting stackarmies: { {1, 9, 0}, {1, 9, 0, 0, 11} }
Desired output: True
We will take first element of vector 1 : 1 and compare with all
elements of vector 2, in vector 2, the last element is greater than 1,
so true
Input 4
3
3 0 8 0
3 4 0 11
3 0 9 0
Resulting stackarmies: { {0, 8, 0}, {0, 8, 0, 4, 0, 11} , {0, 8, 0, 4, 0, 11, 0, 9, 0} }
Desired output: True
We will take the second element of vector 1: 8 and compare with
all elements of vector 2 , 11 is greater than 8 so we will compare 11 of
vector 2 with vector , since there are no values greater than 11, so it's
false
I don't know how to take the first element of vector one and compare with all the elements of vector, since all the vectors are merged into the last vector.
You're getting ahead of yourself. Why do you want all the vectors merged into the last vector? Answer: you don't; that's just what happened. Why did all the vectors merge into the last vector? Answer: because you have a bug in your code that reads the data. Fix that bug instead of spending ten times as much effort trying to handle the malformed data.
That whole spiel about what you intend to do next is nothing more than a distraction that wastes the time of the people from whom you are asking help. Ask for help with the real problem (the loading bug) instead of driving people away with a confusing question that assumes bad data is good.
There are several ways to fix the bug. I think the most helpful approach is one that would have avoided the bug in the first place. You try to do too much in a single function. Divide and conquer; when you have a non-trivial sub-step, create a function to handle it. Good programming practices lead to fewer bugs.
Specifically, reading the heights of the fighters in a stack is non-trivial. Delegate that to a helper and reduce the body of your outer for loop to a single line.
for (int i = 0; i < noofstack; i++)
{
//* This is non-trivial, so use a helper function.
stackarmies.push_back(read_fighter_heights());
}
This helper function is responsible for reading a line of data, generating a stack (a vector<int>) from it, and returning that stack. That covers most of the body of your loop, leaving only the simple task of pushing the returned stack onto your vector of stacks.
Creating this helper function from your existing code is fairly simple. Mostly, just move the body of the loop into an appropriate function definition. In addition, you should notice that stack is needed (only) in this function, so also move that variable's declaration into the new function's definition.
vector<int> read_fighter_heights()
{
vector<int> stack;
int stacksize;
//Since vectors are dynamic and we don't need to declare the size but as per the problem statement I've added it/
cin >> stacksize;
for (int k = 0; k < stacksize; k++)
{
//Taking the input of all the vectors one by one and then adding all the vectors into one vector
int armyheight;
cin>>armyheight; //* Reading a single integer is trivial, so no need for another function here.
stack.push_back(armyheight);
}
return stack;
}
Presto! Problem solved. All you had to do was be more organized.
Addendum: The reason this solves the problem is that extra step of moving the declaration of stack. In the original code, this variable was declared outside the outer loop, and it was never cleared. The result was that it accumulated values from each line that was read. In this version, the variable is re-initialized before reading each line, so values do not accumulate. You could get the same result by moving the line in the original code, without splitting off a new function. However, splitting off a new function is a good habit to get into, as it almost forces you to declare stack at the right level, avoiding the problem in the first place.
bool CompareVectors(vector<vector<int>> st)
{
bool result = true;
for (int k = 0; k < st.size(); k++)
{
if (k != st.size() - 1)
{
if (result)
{
for (auto i = st[k].begin(); i != st[k].end(); ++i)
{
for (auto j = st[k+1].begin(); j != st[k+1].end(); ++j)
{
if (*i < *j)
{
result = true;
break;
}
else
{
result = false;
}
}
if (result)
{
break;
}
}
}
}
}
return result;
}

How can I check equivalency between two arrays in C++?

So I have two arrays and I need to find a way to find the equivalency between two different arrays in C++. This is the function I made:
bool equivalent(int a[], int b[], int n)
for (int i=0; i < n; i++){
if (b[(i + 2) % 5] == a[i])
return true;
else return false;
}
}
and this is the array:
int main() {
cout << boolalpha;
int a1[5] = {1, 2, 3, 4, 5};
int a2[5] = {3, 4, 5, 1, 2};
cout << equivalent(a1, a2, 5) << endl;
I know my arthmetic is correct, because for example, a2[4], 4 plus 2 is 6, mod 5 is 1, and in the a1[0] position, there is a value of 2 which is the same as the a2[4] value. My only problem is, the resultant should be true, but because the for loop starts at 0, the whole function messes up, as the second arrays index would need to start at a different number for it to work. How would I go about solving this?
How would I go about solving this?
By using a debugger. Step through the program line by line. If the behaviour is different than it is supposed to, you've found the problem.
There are two problems with the program:
I know my arthmetic is correct, because for example, a2[4], 4 plus 2 is 6, mod 5 is 1, and in the a1[0] position, there is a value of 2 which is the same as the a2[4] value.
But you're comparing a1[0] with a2[2], not with a2[4]. You've got the order of the arguments reversed.
You only compare a1[0] and then return the result. In order to compare the entire array, you must not return until all elements have been checked (except the branch which returns false can return early).
I think easy way is to convert both array into string then compare both.

Computing permutations using a number of elements

I am trying to generate all possible permutations of a set of elements. The order doesn't matter, and elements may be present multiple times. The number of elements in each permutation is equal to the total number of elements.
A basic recursive algorithm for computing permutations following the schema (as I am writing in C++, the code will look similar to it):
elems = [0, 1, .., n-1]; // n unique elements. numbers only exemplary.
current = []; // array of size n
perms(elems, current, 0); // initial call
perms(array elems, array current, int depth) {
if(depth == elems.size) print current;
else {
for(elem : elems) {
current[depth] = elem;
perms(elems, current, depth+1);
}
}
}
Would produce a large number of redundant sequences, e.g.:
0, 0, .., 0, 0
0, 0, .., 0, 1 // this
0, 0, .., 0, 2
. . . . .
. . . . .
0, 0, .., 0, n-1
0, 0, .., 1, 0 // is the same as this
. . . . . // many more redundant ones to follow
I tried to identify when exactly generating values can be skipped, but have so far not found nothing useful. I am sure I can find a way to hack around this, but I am also sure, that there is a rule behind this which I just haven't managed to see.
Edit: Possible solution+
elems = [0, 1, .., n-1]; // n unique elements. numbers only exemplary.
current = []; // array of size n
perms(elems, current, 0, 0); // initial call
perms(array elems, array current, int depth, int minimum) {
if(depth == elems.size) print current;
else {
for(int i=minimum; i<elems.size; i++) {
current[depth] = elems[i];
perms(elems, current, depth+1, i);
}
}
}
Make your first position varies from 0 to n. Then make your second position to 1. Then make your first position varies from 1 to n. Then set second at 2 --> first from 2 to n and so on.
I believe one such rule is to have the elements in each sequence be in non-decreasing order (or non-increasing, if you prefer).

Initializing arrays in C++

I'm trying to initialize the last element in the array
int grades[10];
to grade 7 but it doesn't seem to work
I'm using C++ btw
If you want to initialize them all at definition:
int grades[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 7 };
If you want to initialize after:
int grades[10];
grades[9] = 7;
But, be aware that grades 0..8 will still be uninitialized, and will likely be junk values.
One more thing, if you initialize only the first element (if explicit array size is specified) or a shorter initiliazation list, the unspecified elements are fill with 0. E.g.
int grades[10] = {8}; //init with one element
is the same as:
int grades[10] = { 8, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
or
int grades[10] = { 1, 9, 6, 16 }; //or init with a shorter than array size list with a minimum of 1 element
is the same as:
int grades[10] = { 1, 9, 6, 16, 0, 0, 0, 0, 0, 0 };
I find it handy for initializing an array with 0 values.
float coefficients[10] = {0.0f}; //everything here is full of 0.0f
when You write something like
int a[5] = {0};
it sets the whole array to zero on the contrary
int a[5] = {3};
sets only the first element and the rest may be anything(garbage values);
if You want to set the whole array with some value then u can go for the
std :: fill()
something like this
std::fill(arr, arr+100, 7); // sets every value in the array to 7
and if there is a character array You can always go for the memset function
The last element is grades[9], since arrays in C++ are zero-based (e.g. grades[0] to grades[9] are 10 elements). Is that what you're doing?
You might need to subtract one from the grade to use as your subscript value, or set the extent to one more.
Remember that an array with ten elements will have grades[0] through grades[9], and that grades[10] is an error.