Finding the Intersect of 'n' Generic Arrays - c++

EDIT : Added far more detail.
I'm trying to write an algorithm that finds the intersection (points common to all) of n arrays. My program takes these arrays and stores them in a two dimensional array on which the operations take place. For example, here is a sample main method:
int a[] = { 12, 54, 42 };
int b[] = { 54, 3, 42, 7 };
int c[] = { 3, 42, 54, 57, 3 };
IntersectionTableau<int> x(3); // Where 3 is the max number of arrays allowed
// to be stored.
x.addArray(a, 3);
x.addArray(b, 4);
x.addArray(c, 9);
x.run(); // Finds the intersection.
These added arrays will be stored in T** arrays and their sizes in int* sizes. T is a generic type. What is an efficient algorithm that will let me do this on a variable number of arrays of generic types?
Here is what I'm currently attempting to do:
template <class T>
inline
void IntersectionTableau<T>::run() {
T* commonElements = d_arrays[0];
for (int i = 1; i < d_currentNumberOfArrays; ++i) {
commonElements = getIntersection(commonElements, d_arrays[i], d_sizes[i - 1], d_sizes[i]);
}
d_results = commonElements;
}
template <class T>
inline
T* IntersectionTableau<T>::getIntersection(T* first, T* second, int sizeOfFirst, int sizeOfSecond) {
T* commonElements;
if (sizeOfFirst > sizeOfSecond) {
commonElements = new T[sizeOfFirst];
} else {
commonElements = new T[sizeOfSecond];
}
for (int i = 0; i < sizeOfFirst; ++i) {
for (int j = 0; j < sizeOfSecond; ++j) {
if (first[i] == second[i]) {
commonElements[i] = first[i];
}
}
}
return commonElements;
}
The first function takes the first two arrays and sends them to the second function, which returns an array of the intersections between those two arrays. Then, the first function compares the intersection array with the next array in d_arrays and so on. My problem is when I go to print out an element from d_results a garbage value is produced, and I'm unsure why. Could someone tell me what I'm doing wrong, or alternatively, a better way to accomplish this?

There are at least two problems in the code:
if (first[i] == second[i])
This should be if (first[i] == second[j]).
commonElements[i] = first[i];
This is trickier to fix. I think you want to have another variable (neither i nor j); let's call it k:
commonElements[k++] = first[i];
Anyway, since you can use C++, you can use a std::vector instead. It stores its size inside; this will reduce confusion:
template <class T>
std::vector<T> // note: adjusted the return type!
IntersectionTableau<T>::getIntersection(...)
{
std::vector<T> commonElements;
for (int i = 0; i < sizeOfFirst; ++i) {
for (int j = 0; j < sizeOfSecond; ++j) {
if (first[i] == second[j]) {
commonElements.push_back(first[i]);
}
}
}
return commonElements;
}
You can turn first and second into vectors too (though you won't benefit much from it right now).
Here are some points to note:
I changed the return type to vector<T>
The old version, which returns an array, requires additional code to specify the length of its result; this version returns the length inside the vector<T> object
The old version, which returns an array, requires delete[] array somewhere later, to prevent a memory leak
The vector-to-pointer hack &commonElements[0] will not work for an empty vector
If your other code works with an array/pointer, you can use the vector-to-pointer hack &commonElements[0], but outside the function, in order to respect the lifetime rules:
T* commonElements = NULL;
for (int whatever = 0; whatever < 10; ++whatever)
{
std::vector<T> elements = xxx.getIntersection(...); // will work
commonElements = &elements[0]; // can pass this pointer to a function receiving T*
print(commonElements); // will work
}
print(commonElements); // cannot possibly work, will probably segfault
print(elements); // cannot possibly work, and compiler will reject this

Related

Merging two sorted array on third by creating a new array on heap

I have a class array inside which I have declared an array its size and length. I am trying to merge two sorted arrays by creating the third array on the heap and both the sorted array will be merged on the third array. But whenever I create a new arr on heap the compiler gives me this error: request for member '..' in '..' which is of non-class type
class Array
{
public:
int A[10];
int length;
int Size;
};
void display(Array arr)
{
int i;
for(i=0;i<arr.length;i++)
{
cout<<arr.A[i]<<" ";
}
}
void Merge(Array *arr1,Array *arr2)
{
int i,j,k;
i=j=k=0;
int *arr3;
arr3=new int[10];
while(i<arr1->length && j<arr2->length)
{
if(arr1->A[i]<arr2->A[j])
arr3->A[k++]=arr1->A[i++];
else
arr3->A[k++]=arr2->A[j++];
}
for(;i<arr1->length;i++)
{
arr3->A[k++]=arr1->A[i];
}
for(;j<arr2->length;j++)
{
arr3->A[k++]=arr1->A[j];
}
}
int main()
{
Array arr1{{1,3,5,7},4,4};
Array arr2{{2,4,6,8},4,4};
Array *arr3;
arr3=Merge(&arr1,&arr2);
display(*arr3);
return 0;
}
The root cause of all your problems is that you use C-Style array with a magical size 10. Like in int A[10];. This is a major problem and should be avoided in C++.
Additionally, and the same, In C++ we usually do not use raw pointer for owned memories or newand such stuff.
Anyway. The design will never work, if the number of elements in both Array classes is greater then 5. Because then you will definitely get an out of bounds problem.
You must use a std::vector.
So, all bad. But I know that I will hear now, that the teacher said, no vector but new. The teacher should be fired or begin to teach C instead of C++.
Anyway again, I will fix the major bugs for you. But the sorting algorithm will work neither.
So,
If you want to return an Array, then change the signature of your function aand return an Array.
You do want to have a new Array, not new intes. So, please allocate a new Array instead.
Do not forget to release the newed Arrary at then end.
Set size and length of the new array.
Refactor your complete code.
Code example with some fixes:
#include <iostream>
class Array
{
public:
int A[10];
int length;
int Size;
};
void display(Array arr)
{
int i;
for (i = 0; i < arr.length; i++)
{
std::cout << arr.A[i] << " ";
}
}
Array* Merge(Array* arr1, Array* arr2)
{
int i, j, k;
i = j = k = 0;
Array *arr3 = new Array;
while (i < arr1->length && j < arr2->length)
{
if (arr1->A[i] < arr2->A[j])
arr3->A[k++] = arr1->A[i++];
else
arr3->A[k++] = arr2->A[j++];
}
for (; i < arr1->length; i++)
{
arr3->A[k++] = arr1->A[i];
}
for (; j < arr2->length; j++)
{
arr3->A[k++] = arr1->A[j];
}
arr3->length = arr1->length + arr2->length;
return arr3;
}
int main()
{
Array arr1{ {1,3,5,7},4,4 };
Array arr2{ {2,4,6,8},4,4 };
Array* arr3;
arr3 = Merge(&arr1, &arr2);
display(*arr3);
delete[]arr3;
return 0;
}

deleting duplicates from a sorted vector

26. Remove Duplicates from Sorted Array
Given a sorted array nums, remove the duplicates in-place such that
each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by
modifying the input array in-place with O(1) extra memory.
Example 1:
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of
nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length. Example
2:
Given `nums = [0,0,1,1,1,2,2,3,3,4],
Your function should return length = 5, with the first five elements
of nums being modified to 0, 1, 2, 3, and 4 respectively.
It doesn't matter what values are set beyond the returned length.
Clarification:
Confused why the returned value is an integer but your answer is an
array?
Note that the input array is passed in by reference, which means
modification to the input array will be known to the caller as well.
Internally you can think of this:
// nums is passed in by
reference. (i.e., without making a copy) int len =
removeDuplicates(nums);
// any modification to nums in your function would be known by the
caller. // using the length returned by your function, it prints the
first len elements. for (int i = 0; i < len; i++) {
print(nums[i]); }
i am getting this runtime error while submitting it on leetcode it works fine on coding blocks but shows this error in leetcode compilor
Line 924: Char 9: runtime error: reference binding to null pointer of type 'int' (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/stl_vector.h:933:9
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int k=nums[0];
for(auto i=nums.begin()+1;i<nums.end();i++)
{
if(*i==k) nums.erase(i) , i--;
else k=*i;
}
return nums.size();
}
};
Can anybody help me in finding the cause of error?
Your code works just fine, missing one edge case (an empty nums):
if (nums.empty()) {
return 0;
}
Updated Code:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.empty()) {
return 0;
}
int k = nums[0];
for (auto i = nums.begin() + 1; i < nums.end(); i++) {
if (*i == k) {
nums.erase(i) , i--;
}
else {
k = *i;
}
}
return nums.size();
}
};
Maybe we could just write a simple loop using size(). This'd pass on LeetCode:
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>
// Start
static const struct Solution {
using SizeType = std::uint_fast16_t;
static const int removeDuplicates(
std::vector<int>& nums
) {
const SizeType len = std::size(nums);
SizeType count = 0;
for (SizeType i = 1; i < len; ++i) {
if (nums[i] == nums[i - 1]) {
++count;
} else {
nums[i - count] = nums[i];
}
}
return len - count;
}
};

Issue finding size of dynamic int array that contains a zero

We are not allowed to use vectors.
Another noobie with a problem. I am trying to find the index of a dynamic int array that is initialized to a size of 50. We can only use a dynamic int array.
Say for example I’m only entering 10 integers into this array: 1 9 5 3 8 0 8 2 0 6
The rest of the array is NULL. The goal is to keep the integer values that were entered into this array and put them into an output file. So the size of the array of ints I want is 9. But when I do the following:
int index = 0;
while (intArray[index])
{
index++;
}
It tells me that the index is 5 and thus only 5 values get copied into the output file. I know it’s because of the 0 in the array. If there is no 0 in the array, the results come out as expected. How do I bypass this so that the index is correctly reflected as 9 and all the values get copied properly? I appreciate any input!
As pointed out in the comments the best approach here, given that you cannot use std::vector (*sigh*), is to make your own minimal dynamic_array (mimicking a std::vector) which knows its own size at all times.
It's interface could look something like this:
template<typename _Ty>
class dynamic_array {
public:
typedef _Ty value_type;
typedef const _Ty& const_reference;
typedef _Ty& reference;
typedef std::size_t size_type;
//... other necessary typedefs
dynamic_array() : arr(), arr_size(0), allocated_size(0) {}
dynamic_array(size_type n) : arr_size(n), allocated_size(n) { allocate(n); }
~dynamic_array() { delete arr; }
size_type size() const noexcept { return arr_size; }
const_reference operator[](size_type n) const { return arr[n]; }
reference operator[](size_type n) { return arr[n]; }
void push_back(const value_type& _val) {
++arr_size;
// actual implementation of pushing back _val up to you
}
private:
value_type* arr;
size_type arr_size; // number of elements
size_type allocated_size; // actual number of allocated elements in memory
void allocate(size_type n) { arr = new value_type[n]; }
};
Then to iterate through this via indices you would simply do:
dynamic_array<int> darr;
// populate darr
for (int i = 0; i < darr.size(); ++i) {
// do stuff with each element accessing via: darr[i] as before
}
Edit - If you can use std::unique_ptr then use this instead of the raw pointer value_type* arr to avoid any potential memory management headaches.
There is no such thing as NULL for integer value. So there are 3 usual approaches, that used:
Special value, marker of the end. This aproach is used for C-style strings, where '\0' used as end. For integer this approach will not work as 0 is "normal" value. You may use some other special value, like std::numeric_limits<int>::min or std::numeric_limits<int>::max, but this would be not very good approach.
Have another variable, that holds current size of array. Note this is usually different, than for how many elements were allocated. This could be wrapped into a class. This is how std::vector is implemented.
Have another variable, pointer, that points to the pone element after the last one. This could be useful for using in standard algorithms.
Approach 2 and 3 are very close and one can be converted very easy to another. So I would recommend to rewrite your algorithm using start and behind_end iterator:
auto end = myArray + 5; // 5 elements in array
for( auto it = myArray; it != end; ++it ) {
std::cout << *it << endl;
}
this code can be easily templatized and used with standard containers.
You could do something like this only if you are sure that the input data are not negatives:
#include <iostream>
int main()
{
int MyArray[50]; // declare your array
// ..
for (int i = 0; i < 50; i++)
MyArray[i] = -1; // fill with negatives
MyArray[0] = 0; // some data
MyArray[1] = 10; // some data
for (int i = 0; i < 50; i++)
{
if (MyArray[i] >= 0 )
{
std::cout << MyArray[i];
// write to your file
}
}
//..
return 0;
}
boost::static_vector would help here. It is essentually a cross between vector and array: either a stack-allocated vector with fixed capacity or uninitialized array with some facilities to track logical size.
Example of use:
#include "boost/container/static_vector.hpp"
#include <iostream>
namespace cnt = boost::container;
void foo()
{
cnt::static_vector<int, 50> buf = {1, 9, 5, 3, 8, 0, 8, 2, 0, 6,};
std::cout << buf.size();
}
int main()
{
foo();
}

initialize array passed by pointer

The function cannot initialize an array because sizeof() returns bytes of an int pointer
not the size the memory pointed by myArray.
void assignArray(int *myArray)
{
for(int k = 0; k < sizeof(myArray); ++k)
{
myArray[k] = k;
}
}
Are there other problems ?
Thanks
Well no, there are no other problems. The problem you stated is the only thing stopping you from initialising the array.
Typically, this is solved by simply passing the size along with the pointer:
void assignArray(int* myArray, std::size_t mySize)
{
for (std::size_t k = 0; k < mySize; ++k)
myArray[k] = k;
}
Note that I've used std::size_t for the size because that is the standard type for storing sizes (it will be 8 bytes of 64-bit machines, whereas int usually isn't).
In some cases, if the size is known statically, then you can use a template:
template <std::size_t Size>
void assignArray(int (&myArray)[Size])
{
for (std::size_t k = 0; k < Size; ++k)
myArray[k] = k;
}
However, this only works with arrays, not pointers to allocated arrays.
int array1[1000];
int* array2 = new int[1000];
assignArray(array1); // works
assignArray(array2); // error
I don't see other problems. However, you probably wanted this:
template<int sz>
void assignArray(int (&myArray)[sz])
{
for(int k = 0; k < sz; ++k)
{
myArray[k] = k;
}
}
Unless, of course, even the compiler doens't know how big it is at compile time. In which case you have to pass a size explicitly.
void assignArray(int* myArray, size_t sz)
{
for(int k = 0; k < sz; ++k)
{
myArray[k] = k;
}
}
If you don't know the size, you have a design error.
http://codepad.org/Sj2D6uWz
There are two types of arrays you should be able to distinguish. One looks like this:
type name[count];
This array is of type type[count] which is a different type for each count. Although it is convertable to type *, it is different. One difference is that sizeof(name) gives you count*sizeof(type)
The other type of array looks like this:
type *name;
Which is basically just a pointer that you could initialize with an array for example with malloc or new. The type of this variable is type * and as you can see, there are no count informations in the type. Therefore, sizeof(name) gives you the size of a pointer in your computer, for example 4 or 8 bytes.
Why are these two sizeofs different, you ask? Because sizeof is evaluated at compile time. Consider the following code:
int n;
cin >> n;
type *name = new type[n];
Now, when you say sizeof(name), the compiler can't know the possible future value of n. Therefore, it can't compute sizeof(name) as the real size of the array. Besides, the name pointer might not even point to an array!
What should you do, you ask? Simple. Keep the size of the array in a variable and drag it around where ever you take the array. So in your case it would be like this:
void assignArray(int *myArray, int size)
{
for(int k = 0; k < size; ++k)
{
myArray[k] = k;
}
}

quicksort (n arrays should be treated as 1 and values remapped as needed)

I have a linked list of arrays (struct at bottom of post)
Each array may have values like the below example
Array1[] = {6,36,8,23};
Array2[] = {8,23,5,73};
Array3[] = {2,5,1,9};
I need to sort these so that all 3 arrays are treated as 1 large array...
I need to use quicksort so that it uses in-place processing... I am working with very large arrays and cannot afford to use additional memory..
The result should be something like this
Array1[] = {1,2,5,5};
Array2[] = {6,8,8,9};
Array3[] = {23,23,36,73};
Currently i am only able to sort each array individually... but thats not exactly what i need :(
struct iSection {
unsigned long Section_Count; // Total # of points in this block of memory
int *Section_Arr; // Point cloud for current block of memory
struct iSection *Next; // Pointer to next section
} iSection;
struct iDatabase {
struct iSection *First_Section;
struct iSection *Last_Section;
} iDatabase;
It's not that hard, more an interfacing issue then an algorithmics issue.
Write a wrapper container that provides an interface for accessing members and writing (say operator[] in C++) and internally it maps the size_t index argument to the right array. This wrapper class does need the size of every array though to be able to correctly map the index.
An example pseudocode operator[] would be:
int& JointDatabase::operator[](size_t index) {
// database is an iDatabase
iSection *cur = database.First_Section;
while (cur != database.Last_Section && index >= cur->Section_Count) {
index -= cur->Section_Count;
cur = cur->Next;
}
return cur->Section_Arr[index];
}
Then use this wrapper class as you would use a normal container in your Quicksort algorith.
If you can make sure that Array1, Array2, and Array3 are declared one after another and in continuous memory layout, then you can give the Array1 (the first one) in the sort() and give the combined size of all the arrays.
To check the continuous alignment you can use following trick.
template<size_t SIZE1, size_t SIZE2, size_t SIZE3>
bool Check(int (&a1)[SIZE1], int (&a2)[SIZE2], int (&a3)[SIZE3])
{
return (&a3[SIZE3 - 1] - &a1[0]) == (SIZE1 + SIZE2 + SIZE3);
}
Usage,
bool aligned = Check(Array1, Array2, Array3);
This is an example for 3 arrays, you can make it according to your need. And you can pass Array1,2,3 or Array3,2,1 depending on your machine.
Tested only in my brain:
struct ArrayWrapper {
int** arrays;
int* running_sums;
ArrayWrapper(int **arrays, int *arrays_length, int N) {
running_sums = new int*[N+1];
int sum = 0;
for (int i = 0; i < N; i++) {
running_sums[i+1] = sum;
sum += arrays_length[i];
}
}
int& operator[] (int index) {
int array_start = binary search `running_sum` for the closest number to `index` (round down)
return arrays[array_start][index - running_sums[array_start]]
}
}
so if you have something like:
array1 = {...}
array2 = {...}
...
arrayN = {...}
arrays = {array1, array2, ..., arrayN}
arrays_length = {array1_length, array2_length, ..., arrayN_length}
ArrayWrapper wrapper = new ArrayWrapper(arrays, arrays_length, N);
// wrapper then can be treated like normal array:
wrapper[10] = x;
x = wrapper[10];