Merge two sorted arrays - c++

This is my code for merging 2 sorted arrays:
#include<iostream>
using namespace std;
void merge(int arr1[], int n, int arr2[], int m, int arr3[]) {
int i = 0, j = 0;
int k = 0;
while( i<n && j<m) {
if(arr1[i] < arr2[j]){
arr3[k++] = arr1[i++];
}
else{
arr3[k++] = arr2[j++];
}
}
}
void print(int ans[], int n) {
for(int i=0; i<n; i++) {
cout<< ans[i] <<" ";
}
cout << endl;
}
int main() {
int arr1[5] = {1,3,5,7,9};
int arr2[3] = {2,4,6};
int arr3[8] = {0};
merge(arr1, 5, arr2, 3, arr3);
print(arr3, 8);
return 0;
}
I expect to get the output:
1 2 3 4 5 6 7 9
But instead the output I get is:
1 2 3 4 5 6 0 0
What is the cause of that ?

You need to handle the case where you reached the end of the shorter list, and need to copy the rest of the longer one.
This is handled in the code below by the 2 additional while loops.
Also it's advisable to use std::vectors instead of old c style arrays. It will save you the need to manually track the array sizes.
#include <iostream>
#include <vector>
void merge(std::vector<int> const & arr1, std::vector<int> const & arr2, std::vector<int> & arr3) {
int i = 0, j = 0;
int k = 0;
arr3.resize(arr1.size() + arr2.size());
while (i < arr1.size() && j < arr2.size()) {
if (arr1[i] < arr2[j]) {
arr3[k++] = arr1[i++];
}
else {
arr3[k++] = arr2[j++];
}
}
// Copy the rest of arr1 (if needed):
while (i < arr1.size()) {
arr3[k++] = arr1[i++];
}
// Copy the rest of arr2 (if needed):
while (j < arr2.size()) {
arr3[k++] = arr2[j++];
}
}
void print(std::vector<int> const & ans) {
for (size_t i = 0; i < ans.size(); i++) {
std::cout << ans[i] << " ";
}
std::cout << std::endl;
}
int main() {
std::vector<int> arr1 = { 1,3,5,7,9 };
std::vector<int> arr2 = { 2,4,6 };
std::vector<int> arr3;
merge(arr1, arr2, arr3);
print(arr3);
return 0;
}
Output:
1 2 3 4 5 6 7 9
A side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.

this loop
while( i<n && j<m) {
stops when you reach the end of the shortest array. In this case, when m=3. You need to continue to copy the remaining elements from the larger array

Assume for a second that there are "sentinel" values arr1[n] == arr2[m] == ∞. Then the code below would work, as it will fully traverse both arrays, without going past (mind the ||).
int i = 0, j = 0 k = 0;
while (i < n || j < m) {
if (arr1[i] < arr2[j]) {
arr3[k++]= arr1[i++];
}
else {
arr3[k++]= arr2[j++];
}
}
Now you can emulate the presence of the sentinels by refining the comparison condition:
arr1[i] < arr2[j]
becomes
(i < n && j < m && arr1[i] < arr2[j]) || (i < n && j >= m)
which can be written
i < n && (j >= m || arr1[i] < arr2[j])
(check the cases n == i and m == j).
Notice that it is more efficient to split the code in three successive loops, processing separately the situations where one of the arrays has been fully seen.

You have to consider the edge case:-
when one of the linked lists ends. Then you have to loop through the other list and add the remaining elements.
So in your case, arr2 has 3 values and arr1 has 5 values. So your while loop ends when one of the list elements ends. So in the above case, arr2 will end so you have to add arr1 elements in arr3
After a while loop, you have to add this code
while (i < arr1.size()) arr3[k++] = arr1[i++];
while (j < arr2.size()) arr3[k++] = arr2[j++];

You forgot one thing!
If arr1 is 1,2,3 and arr2 is 4,5,6. Then you will only copy arr1 into arr3. You need to do the loop you have written; BUT then when you exit the loop one of the arrays will have items still left to copy and you simply need to copy the remaining elements.
void merge(int arr1[], int n, int arr2[], int m, int arr3[])
{
int i = 0, j = 0;
int k = 0;
while (i < n && j < m)
{
if(arr1[i] < arr2[j]){
arr3[k++] = arr1[i++];
}
else{
arr3[k++] = arr2[j++];
}
}
// Copy any remaining elements.
// Note: Only one of these loops will do any work
// The other loop is a noop.
while (i < n) {
arr3[k++] = arr1[i++];
}
while (j < m) {
arr3[k++] = arr2[j++];
}
}
We can simplify a couple of things:
if(arr1[i] < arr2[j]){
arr3[k++] = arr1[i++];
}
else{
arr3[k++] = arr2[j++];
}
// Could be written as:
arr3[k++] = (arr1[i] < arr2[j]) ? arr1[i++] : arr2[j++];
The tertiary operator is a shortcut operator and only one side is evaluated.
Other things to note about C++
merge(arr1, 5, arr2, 3, arr3);
This would be better written as:
// Do not hard code the length of the array.
// Somebody in the future will come along and change the
// array and not look to where it is used and thus cause
// an error. Use `std::size()` to get the length of the array.
merge(arr1, std::size(arr1), arr2, std::size(arr2), arr3);
I would also change the operation to use iterators. This makes it easier to use some of the standard functions.
template<typename I1, typename I2, typename I3>
void merge(I1 b1, I1 e1, I2 b2, I2, e2, I3 dst)
{
while (b1 < e1 && b2 < e2)
{
*dst++ = (*b1 <= *b2) ? *b1++ : *b2++;
}
dst = std::copy(b1, e1, dst);
dst = std::copy(b2, e2, dst);
}
Then you can use it like:
merge(std::begin(arr1), std::end(arr1),
std::begin(arr2), std::end(arr2),
std::begin(arr3));

Related

Question about comparing two unordered arrays and removing elements in a[] that can be found in b[]

There is a problem that I can't solve it. Here are two unordered arrays
int a1[] = { 5, 7, 14, 0, 6, 2, 9, 11, 3 }; int n = 9;
int b[] = { 6, 4, 3, 10, 9, 15, 7 }; int m = 7;
I want to compare them and remove elements in a[] that can be found in b[]. The following code return a correct value of n to me. The correct value should be 4 but it give me 5 even if I successfully sorted array a1[]. It gave me a result like this:
a1[] = { 5, 2, 14, 0 ,11 }
There is a slightly difference between my result and the model answer. I mean the order of the elements in a1[]. The model answer is
a1[] = {5, 11, 14, 0, 2}
Can you guys help me to figure out the problem?
int removeAll_unordered(int *a, int& n, const int *b, int m)
{
for (int i = 0; i < m; i++) {
int j = 0;
for (j = 0; j < n; j++)
{
if (b[i] == a[j])
{
a[j] = a[n - 1];
n -= 1;
}
}
}
return n;
}
If you write code in C++ you should use what standard library provides for you - in your case std::vector and std::remove_if algo:
void removeAll_unordered( std::vector<int> &a, const std::vector<int> &b )
{
auto end = std::remove_if( a.begin(), a.end(), [b]( int i ) {
return std::find( b.begin(), b.end(), i ) != b.end();
} );
a.erase( end, a.end() );
}
Live code 1
But this usage is very inefficient, so using standard library as well which provides std::unordered_set aka hash set we can easily make it optimized:
void removeAll_unordered( std::vector<int> &a, const std::vector<int> &b )
{
auto end = std::remove_if( a.begin(), a.end(),
[set = std::unordered_set<int>( b.begin(), b.end() )]( int i ) {
return set.count( i );
} );
a.erase( end, a.end() );
}
Live code 2
I found one problem in you code, I couldn't compile though, but it should work.
In your code,
if (b[i] == a[j])
{
a[j] = a[n - 1];
n -= 1;
}
When an element in b is found in a, you replace that value with a[n-1], this is okay, but that value was not compared with b[i] as j got incremented, So I correct this part. If you run with different inputs you will able to catch this problem.
int removeAll_unordered(int *a, int& n, const int *b, int m)
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n;)
{
if (a[j] == b[i]) // replace a[j] with a[n-1] and decrease n
{
a[j] = a[n - 1];
n--;
}
else
j++; // otherwise increase j
}
}
return n;
}
To get the exact answer (order of the elements in a after the removal)
here is the modified code:
int duplicates = 0; // counts total numbers that removed from a[]
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m;)
{
if (a[i] == b[j]) // replace a[j] with a[n-1] and decrease n
{
if (i == n - 1) // when we reach the last element of a that matches in b
{
n--; // updating length of a[]
duplicates++; // one more removed
break;
}
a[i] = a[n - 1];
n--; // updating length of a[]
duplicates++; // one more removed
j = 0;
}
else
j++; // otherwise increase j
}
}
return duplicates; // returned total removed numbers
I found the problem of your code. You change the variables in the for loops. First for loop use the 'n' variable for their maximum value and second for loop use 'm' value.
Then you only decreasing n value but you didn't check the new i th value. Because now i th value changed. So, you want check again that value also. For that you can decrease 'i' value also.
And also you mentioned above your answer is 5 not 4. Then it correct answer. Because you write this code thinking about 9 elements of the array. Not the 0 to 8. So, if you write this code thinking about 0 to 8 elements you can get whatever you want. If you want 4 you can decrease final value by one. Then you can get your value.
Modified cord given below.
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (b[j] == a[i])
{
a[i] = a[n - 1];
n -= 1;
i = i - 1;
}
}
}
return n;

Computing square-root with bit shifting algorithm always outputs the same number

I'm struggling with the bit shifting algorithm for computing the square root of big numbers. I've got arrays of 32bit words and doesn't matter the input, the output is always the same number. Previously the algorithm worked with 1 bit per array cell, but when I switched to words in cells it doesn't work anymore.
I wrote methods that work perfectly separately (adding words, subtracting words, shifting bits to the right) but the whole program doesn't give what I expect.
When the input number has 0 in it's first position, the output is 0, when it has any number but the 1st cell of the array isn't 0, the output is always the same.
The variables:
uint32_t var[4] = {0,0,0,0};
uint32_t w_number[word_len] = {1, 0,0,234324};
uint32_t one[word_len] = {0,0,0,0};
uint32_t var[word_len] = {0,0,0,0};
uint32_t buff[word_len] = {0,0,0,0};
uint32_t result[word_len] = {0,0,0,0};
The code:
one[0] = 1L << 30;
while (isBigger(one, input))
{
shiftR_word(one);
shiftR_word(one);
}
while (!isZero(one))
{
add_word(result, one, var); //the result of one+result is put in Var.
if ((isBigger(input, var) || equals(input, var))) // if (input >= var)
{
subtract_word(input, var, input); // input-=var
shiftR_word(result);
add_word(result, one, result);
}
else
{
shiftR_word(result);
}
shiftR_word(one);
shiftR_word(one);
}
std::cout << "\nOut: ";
printAsBit(result);
std::cout << std::endl;
Here's the shifting algorithm I'm using that may cause the problems.
void shiftR_word(uint32_t w_number[], int n=4)
{
// n - how many words
//(n*32b word) >> 1
bool* odd = new bool[n];
for (int i = 0; i < n; i++)
{
if( w_number[i] & 1 )
odd[i]=true;
else
odd[i]=false;
}
for (int i = 0; i < n; i++)
w_number[i] >>= 1;
for (int i = 0; i <= n-1; i++)
{
if(odd[i])
{
w_number[i+1] = w_number[i+1] | 1 << 31;
}
}
delete[] odd;
}
The add function:
void add_word(uint32_t a[], uint32_t b[], uint32_t result[], int len=4)
{
int carry=0;
for (int i = len-1; i >=0; i--)
{
result[i]=a[i]+b[i]+carry;
carry = (a[i]>result[i] || b[i]>result[i]) ? 1 : 0;
}
}
isBigger method:
bool isBigger(uint32_t a[],uint32_t b[] ,int len=4)
{
for (int i = 0; i < len; i++)
{
if (a[i]>b[i])
{
return true;
}
}
return false;
}
I am unable to spot the error in the code, especially that all of the methods seem to work when I test them separately.
isBigger does not work. If you have (length 2) values of {2, 5} for a and {6, 3} for b it will return true when it should return false. Inside the loop, you want to return false if a[i] < b[i], and only check the next value if the two values are equal.
bool isBigger(const uint32_t a[], const uint32_t b[], int len = 4)
{
for (int i = 0; i < len; i++)
{
if (a[i] > b[i])
return true;
if (a[i] < b[i])
return false;
}
// Only get here if `a` and `b` are equal
return false;
}
Additionally, shiftR_word has Undefined Behavior, because w_number[i+1] can be past the end of the array (when i == n-1, you'll access w_number[n - 1 + 1] or w_number[n]). Your loop condition in this instance should be i < n-1. However, that function is rather inefficient. It can be rewritten to only need one loop and no memory allocation, but that's left as an exercise for the reader.

How can I sort array elements by number of divisors?

My problem is that I hit an obstacle while I was solving some exercises.
The source of the problem is that I have to write a program which sort descending an array by the number of each element's divisors, but when two element has the same number of divisors it should sort ascending those values.
My code so far:
#include <iostream>
#include <fstream>
using namespace std;
int cntDiv(int n) //get number of divisors
{
int lim = n;
int c = 0;
if(n == 1)
return 1;
for(int i = 1; i < lim; i++)
{
if(n % i == 0)
{
lim = n / i;
if(lim != i)
c++;
c++;
}
}
return c;
}
int main()
{
ifstream fin("in.txt");
int n, i, j;
fin >> n;
int v[n];
for(i = 0; i < n; i++)
fin >> v[i];
int div[n];
for(i = 0; i < n; i++)
div[i] = cntDiv(v[i]);
for(i = 0; i < n - 1; i++)
{
for(j = i + 1; j < n; j++)
{
if(div[i] < div[j] && div[i] != div[j]) //if the number of divisors are different
{
int t = v[i];
v[i] = v[j];
v[j] = t;
t = div[i];
div[i] = div[j];
div[j] = t;
}
if(div[i] == div[j] && v[i] > v[j]) //if the number of divisors are the same
{
int t = v[i];
v[i] = v[j];
v[j] = t;
}
}
}
for(i = 0; i < n; i++)
{
cout << v[i] << " ";
}
return 0;
}
In.txt:
5
12 20 4 100 13
Output:
100 12 20 4 13
Although it works fine with this one and many other. For bigger inputs it exceeds the time limit which is 0.1s. Any advice how should I rewrite the sorting? (I wrote bubble sort because I could not implement sorting array by property via quicksort)
Use an array of structures. The structure would contain the original value and a container of divisors:
struct Number_Attributes
{
int number;
std::list<int> divisors;
};
You can then write a custom comparator function and pass to std::sort:
bool Order_By_Divisors(const Number_Attributes& a,
const Number_Attributes& b)
{
return a.divisors.size() < b.divisors.size();
}
The sorting then becomes:
#define ARRAY_CAPACITY (20U)
Number_Attributes the_array[ARRAY_CAPACITY];
//...
std::sort(&array[0], &array[ARRAY_CAPACITY], Order_By_Divisors);
The generation of divisors is left as an exercise for the OP.
Reworking your code with std::sort:
std::vector<std::pair<int, int>> customSort(const std::vector<int>& v)
{
std::vector<std::pair<int, int>> ps;
ps.reserve(v.size());
// We don't have zip sort :/
// So building the pair
for (auto e : v)
{
ps.emplace_back(e, cntDiv(e));
}
std::sort(ps.begin(), ps.end(), [](const auto&lhs, const auto& rhs) {
// descending number of divisors, increasing value
return std::make_tuple(-lhs.second, lhs.first)
< std::make_tuple(-rhs.second, rhs.first);
});
return ps;
}
int main()
{
const std::vector<int> v = {12, 20, 4, 100, 13};
const auto res = customSort(v);
for(const auto& p : res)
{
std::cout << p.first << " ";
}
}
Demo

What don't I understand about passing a pointer as a parameter? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I made the following tidbit of code to move the zeros to the front of an array (By the way, is there a more elegant and efficient procedure?). For some reason, when I test the function, it doesn't modify the array, like it should be doing. I can't figure out what's going wrong.
void zeros_to_front(int* arr, int sz) {
std::vector<int> nonzeroesVec;
for (int k = 0; k < sz; ++k) {
if (arr[k] != 0)
nonzeroesVec.push_back(arr[k]);
}
int numzeroes = sz - nonzeroesVec.size();
int j(0), k(0);
while (j < numzeroes)
arr[j++] = 0;
while (j < sz)
arr[j++] = nonzeroesVec[k++];
}
If you don't care about the order of the non-zero elements afterward, you can use this:
void swap(int& x, int& y)
{
x ^= y;
y ^= x;
x ^= y;
}
void zerosToFront(int arr[], int size)
{
if(size < 1)
{
return;
}
int front = 0;
for(int i = 0; i < size; i++)
{
if(arr[i] == 0)
{
swap(arr[i], arr[front++]);
}
}
}
It iterates once through the array, and whenever it finds a zero, it swaps that zero to the front of the array. It's O(n), which is as efficient as you can get.
However, if you do care about order, you can use:
void zerosToFront(int arr[], int size)
{
if(size < 1)
{
return;
}
for(int i = 0; i < size; i++)
{
if(arr[i] == 0)
{
for(int j = 0; j < i; j++)
{
swap(arr[i - j], arr[i - j- 1]);
}
}
}
}
This iterates through the array once, and whenever it finds a zero, the inner for loop essentially shifts everything before the zero we found over to the right to make room for the zero at the beginning of the list. However, this is O(n^2) due to the inner for loop, hence less efficient. For relatively small arrays you won't notice the performance difference, though.
Edit:
Actually, I just realized something interesting. If you traverse the array backwards, you can push the zeros to the front and retain the ordering of the non-zero elements in O(n) time.
void ztf(int arr[], int size)
{
if(size < 1)
{
return;
}
int back = size - 1;
for(int i = size - 1; i >= 0; i--)
{
if(arr[i] != 0)
{
arr[back--] = arr[i];
}
}
while(back >= 0)
{
arr[back--] = 0;
}
}
Just thought that was nifty.
Whatever the symptom is, I can't seem to reproduce it:
#include <stdio.h>
#include <vector>
void zeros_to_front(int* arr, int sz) {
std::vector<int> nonzeroesVec;
for (int k = 0; k < sz; ++k) {
if (arr[k] != 0)
nonzeroesVec.push_back(arr[k]);
}
int numzeroes = sz - nonzeroesVec.size();
int j(0), k(0);
while (j < numzeroes)
arr[j++] = 0;
while (j < sz)
arr[j++] = nonzeroesVec[k++];
}
int main(int argc,char *argv[])
{
int ptr[5] = {0};
ptr[0] = 1;
zeros_to_front(ptr,5);
for (int i = 0;i < 5;++i){
printf("%d",ptr[i]);
}
return 0;
}
works as expected and prints out "00001".
I suggest something like this:
#include <vector>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <iterator>
void
shake(int * arr, std::size_t N)
{
bool changed;
do
{
changed = false;
for (std::size_t i = 0; i != N - 1; ++i)
{
if (arr[i + 1] == 0 && arr[i] != 0)
{
std::swap(arr[i], arr[i + 1]);
changed = true;
}
}
}
while (changed);
}
int
main ()
{
std::vector<int> vec { 1, 0, 2, 0, 3, 0, 0, 4, 5, 0 };
shake(&vec[0], vec.size());
std::copy(vec.begin(), vec.end(),
std::ostream_iterator<int>(std::cout, ", "));
}

Merging two arrays in ascending order (both arrays are same size)

My friend and I are struggling with a merging function. It requires that both arrays have the same size, thus the merged array twice the number. This is what we have so far:
void mergeTwoSortedArrays(const int a1[], const int a2[], int mergedArray[], int n)
{
int i = 0;
int j = 0;
int k = 0;
while (i <= n && j <= n)
{
if (a1[i] == a2[j])
{
mergedArray[k] = a1[i];
mergedArray[k] = a2[j];
i++;
j++;
}
k++;
}
}
It's not working however. Any tips?
Is this for merge sort or something? The usual approach is to do the combined merge, much like you have done already, followed by a copy. Here's the first part. You were a little confused. Read through this and you'll see it makes sense:
while (i < n && j < n) {
if (a1[i] <= a2[j]) {
mergedArray[k++] = a1[i++];
} else {
mergedArray[k++] = a2[j++];
}
}
Then you handle the remaining elements. Obviously the loop finishes when only one array reaches the end. So now you need two much simpler loops. Only one will execute - no need for complicated tests:
while (i < n) mergedArray[k++] = a1[i++];
while (j < n) mergedArray[k++] = a2[j++];
I turned your tests into < instead of <=, because the arrays are zero-based.
This is what i came up with -
void mergeTwoSortedArrays(const int a1[], const int a2[], int mergedArray[], int n) {
int i = 0;
int j = 0;
int k = 0;
// Iterate and compare two input arrays until at least one of them reaches to boundary.
while (i < n && j < n) {
if (a1[i] < a2[j]) {
mergedArray[k++] = a1[i++];
}
else if (a1[i] > a2[j]) {
mergedArray[k++] = a2[j++];
}
else if (a1[i] == a2[j]) {
mergedArray[k++] = a1[i++];
mergedArray[k++] = a2[j++];
}
}
// Copy the remaining items from the other array, without comparison until, boundary.
while (i < n) mergedArray[k++] = a1[i++];
while (j < n) mergedArray[k++] = a2[j++];
}
I don't know if you're trying to merge them as in interleave them or just concatenate two distinct arrays. If it's striding:
#include <iostream>
void mergeTwoArraysIntoOne(const int* lhs, const int* rhs, int* dst, size_t numElements) {
const int* const endLhs = lhs + numElements;
const int* const endRhs = rhs + numElements;
for ( ; lhs < endLhs ; ) {
while (rhs < endRhs && *rhs < *lhs)
*(dst++) = *(rhs++);
*(dst++) = *(lhs++);
}
while (rhs < endRhs)
*(dst++) = *(rhs++);
}
void dumpArray(int* array, size_t elements) {
for (size_t i = 0; i < elements; ++i)
std::cout << array[i] << " ";
std::cout << std::endl;
}
int main() {
int array1[] = { 1, 2, 3 };
int array2[] = { 10, 20, 30 };
int array3[] = { 1, 11, 31 };
int result[6];
mergeTwoArraysIntoOne(array1, array2, result, 3);
dumpArray(result, 6);
mergeTwoArraysIntoOne(array2, array1, result, 3);
dumpArray(result, 6);
mergeTwoArraysIntoOne(array1, array3, result, 3);
dumpArray(result, 6);
mergeTwoArraysIntoOne(array3, array1, result, 3);
dumpArray(result, 6);
mergeTwoArraysIntoOne(array2, array3, result, 3);
dumpArray(result, 6);
mergeTwoArraysIntoOne(array3, array2, result, 3);
dumpArray(result, 6);
return 0;
}
Live demo: http://ideone.com/7ODqWD
If it's just concatenating them:
std::copy(&lhs[0], &lhs[numElements], &dst[0]);
std::copy(&rhs[0], &rhs[numElements], &dst[numElements]);