I have the following code:
int copyOddOnly(int *dest, int *src, int n) {
int copyList = 0;
for(int i = 0; i < n; i++) {
if(src[i]%2!=0) {
dest[i]=src[i];
copyList = copyList + 1;
}
}
return copyList;
}
It's meant to take all the elements with odd values from array src and copy them to array dest. n is the number of elements to be copied from src to dest. It passes most of the tests except for these two:
int a[10] = {0};
ASSERT_EQUALS(3,copyOddOnly(a,descending,5));
ASSERT_EQUALS( "{5,4,3,2,1}",arrayToString(descending,5));
ASSERT_EQUALS( "{5,3,1}",arrayToString(a,3));
ASSERT_EQUALS(5,copyOddOnly(a,mix2,10));
ASSERT_EQUALS( "{-42,12,-9,56,123,32767,48,12,-43,-43}",arrayToString(mix2,10));
ASSERT_EQUALS( "{-9,123,32767,-43,-43}",arrayToString(a,5));
Instead of copying {5,3,1} from arrayToString(a,3) it's copying {5,0,3}. Instead of copying {-9,123,32767,-43,-43} from arrayToString(a,5) it's copying {5,0,-9,0,123}.
My first instinct when writing it was to just have it return n, but for some reason this had it failing even more tests. I have a feeling I'm not getting at something fundamental and I can't figure out what. Any help would be appreciated.
Instead of
dest[i]=src[i];
you probably meant to have
dest[copyList]=src[i];
While it's copying across only the odd elements, it's leaving alone those elements of dest corresponding to even elements of src. Whatever value was originally in e.g. a[1] will still be there after the copy if descending[1] is 4.
You'll need to keep track of how far along dest you are in the loop. This will be equivalent to copyList in the the function:
int copyOddOnly(int *dest, int *src, int n) {
int j = 0;
for (int i = 0; i < n; i++) {
if (src[i]%2 != 0) {
dest[j] = src[i];
j = j + 1;
}
}
return j;
}
First of all take into account that there is standard algorithm std::copy_if declared in header <algorithm> in C++. Your function could look the following way.
#include <algorithm>
//...
int copyOddOnly( int *dest, const int *src, int n )
{
auto last = std::copy_if( src, src + n, dest,
[]( int x ) { return x % 2; } );
return last - dest;
}
If you may not use standard algorithms then the function can look like
int copyOddOnly( int *dest, const int *src, int n )
{
int k = 0;
if ( !( n < 0 ) )
{
for ( int i = 0; i < n; i++ )
{
if ( src[i] % 2 != 0 ) dest[k++] = src[i];
}
}
return k;
}
Related
I'm having trouble trying to come up with the pointer version of this function:
void strncpy(char t[], const char s[], const unsigned int n)
{
unsigned int i = 0;
for(i = 0; i < n and s[i]; i++)
t[i]=s[i];
t[i] = '\0'
}
This function is supposed to copy the first "n" characters of one array to another array and then terminate with a null character. I'm sure this is simple but I'm still learning pointers :P
This is what I have right now:
void strncpy(char * t, const char * s, const unsigned int * n)
{
unsigned int i = 0;
for(i = 0; i < *n and *s; i++)
*t = *s;
*t = '\0';
}
Im calling it in main via:
char array_one[5] = "quiz";
char array_two[5] = "test";
unsigned int x = 2;
strncpy(array_one,array_two,x);
You've failed to increment the pointers, so you're always overwriting the same address. There's also no need to pass n via a pointer:
#include <cstddef>
void my_strncpy(char *t, const char *s, std::size_t n) {
while (n && *s) {
*t++ = *s++;
--n;
}
*t = '\0';
}
NB: note use of size_t to duplicate the standard parameter signature
of the standard strncpy function, although the standard version also returns the original value of t rather than void.
#include <iostream>
// changing the function signature to take an int instead of
// pointer to int - cleaner
void my_strncpy(char * t, const char * s, const unsigned int n)
{
unsigned int i = 0;
for(i = 0; i < n; i++)
{
*t++ = *s++; // copy and increment
}
*t = '\0'; // fixing - added terminating char
}
int main(void)
{
char a[] = "string1";
char b[] = "string2";
my_strncpy(a,b,7); // replace 7 with appropriate size
std::cout << a << std::endl;
}
You need to copy over each character from one string to another and then increment the pointers - you were missing that in your implementation.
I also assume that you will not overshoot the array you are copying from.
Input : {10,9,8,7,6,5,4,3,2,1}
Output : {8,7,6,9,10,5,4,3,2,1}
I'm not sure what the issue is. I think it has something to do with the recursion in mergesort. I'm new to recursion so my understanding is not too good. Any hints?
#include <iostream>
void mergeSort(int a[], int w[], int n);
void merge(int a[], int w[], int n);
using namespace std;
void mergeSort(int a[], int t[], int n) {
if (n > 1) {
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
for (int i = n/2; i < n; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
merge(a, t, n/2);
}
}
void merge(int a[], int t[], int n) {
int leftIndex = 0, leftEnd = n/2;
int rightIndex = n/2, rightEnd = n;
int targetIndex = 0;
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < t[rightIndex])
a[targetIndex++] = t[leftIndex++];
else
a[targetIndex++] = t[rightIndex++];
}
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
while (rightIndex < rightEnd) {
a[targetIndex++] = t[rightIndex++];
}
}
int main() {
const int SIZE = 10;
int a[] = {10,9,8,7,6,5,4,3,2,1};
int w[SIZE];
mergeSort(a,w,SIZE);
for (int i = 0; i < SIZE; i++) {
cout << a[i] << " ";
}
cout << endl;
}
The general problem is pointer confusion. One of the C language quirks that is not immediately obvious is that in
void mergeSort(int a[], int t[], int n);
both a and t are not arrays, but pointers. There is a special rule for this in the language standard. What this means is that in all instantiations of mergeSort on the call stack, t and a refer to the same areas of memory, and this means that every time you do something like
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
you're changing the same region of memory. After you've done so and returned to the previous call frame, this region no longer contains the data you expect it to contain.
The way to solve this is to define a temporary local buffer where you need it, which is in merge. For example:
const int SIZE = 10;
// mergeSort is much simpler now:
void mergeSort(int a[], int n) {
if (n > 1) {
// sort the left side, then the right side
mergeSort(a , n / 2);
mergeSort(a + n / 2, n - n / 2);
// then merge them.
merge(a, n);
}
}
// Buffer work done in merge:
void merge(int a[], int n) {
// temporary buffer t, big enough to hold the left side
int t[SIZE];
int leftIndex = 0 , leftEnd = n / 2;
int rightIndex = n / 2, rightEnd = n ;
int targetIndex = 0;
// copy the left side of the target array into the temporary
// buffer so we can overwrite that left side without worrying
// about overwriting data we haven't yet merged
for(int i = leftIndex; i < leftEnd; ++i) {
t[i] = a[i];
}
// then merge the right side and the temporary buffer to
// the left side. By the time we start overwriting stuff on
// the right side, the values we're overwriting will have been
// merged somewhere into the left side, so this is okay.
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < a[rightIndex]) {
a[targetIndex++] = t[leftIndex++];
} else {
a[targetIndex++] = a[rightIndex++];
}
}
// If there's stuff in the temporary buffer left over,
// copy it to the end of the target array. If stuff on the
// right is left over, it's already in the right place.
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
}
Before explaining the errors, let me first emphasize that a function argument like int a[] is nothing more than a pointer passed to the function. It points to a region of memory.
Now, mergesort requires some temporary memory and works by
copying the data to the temporary memory;
sorting each half of the data in temporary memory;
merging the two halves, whereby writing into the original array.
In step 2, the original array is not needed and can serve as temporary memory for the recursion.
In view of these facts, your code contains two errors:
You don't use the arrays t[] and a[] appropriately. The idea is that a[] is both input and output and t[] a temporary array. Internally, data are first copied to the temporary array, each half of which is sorted, before merging them fills the original array a[].
You don't sort the second half of the temporary array, but the first half twice.
A correct implementation is, for example,
void mergeSort(int*a, int*t, int n) {
if (n > 1) {
for (int i = 0; i < n; i++)
t[i] = a[i]; // copy to temporary
mergeSort(t , a , n/2); // sort 1st half of temporary
mergeSort(t+n/2, a+n/2, n-n/2); // sort 2nd half of temporary
merge(a, t, n);
}
}
Note that since t[] and a[] are pointers, the operation t+n/2 simply obtains the pointer to the second half of the array. The result of your code with this alteration is 1 2 3 4 5 6 7 8 9 10.
First of all, I don't want to use sort. This is just an illustration example. The main purpose of this question is that I want to:
find all possible combinations of m numbers out of n numbers and
process them, then return the unique processed result (since the
processed results of all possible combinations will be compared).
Question start at here
The following code get all possible combinations M numbers out of N numbers. Sum the M numbers and find the largest sum. In doing this I used a recursion function.
However, it seems that I must define a global variable to store the temporary largest sum. Is there any way to get rid of this global variable? For example, define the recursion function to return the largest sum... I don't want the global variable just become an argument &max_sum in the find_sum, since find_sum already have too many arguments.
#include <iostream>
#include <vector>
void find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start);
int max_sum =0;
int main() {
int N = 10;
int M = 3;
std::vector<int> ar(N);
ar = {0,9,2,3,7,6,1,4,5,8};
int index = 0, start =0;
std::vector<int> combine(M);
find_sum(ar, combine, index, start);
std::cout << max_sum <<std::endl;
return 0;
}
void find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start) {
if(index == combine.size()) {
int sum =0;
for(int i=0; i<index; ++i) {
sum += combine[i];
}
if(max_sum < sum) {
max_sum = sum;
}
return ;
}
for(int i = start;
i < ar.size() && ar.size()-i > combine.size()-index;
++i) {
combine[index] = ar[i];
find_sum(ar, combine, index+1, start+1);
}
}
An approach that scales well is to turn find_sum into a function object. The trick is to define a struct with an overloaded () operator that takes a certain set of parameters:
struct FindSum
{
void operator()(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start){
/*ToDo - write the function here, a very explicit way of
/*engineering the recursion is to use this->operator()(...)*/
}
int max_sum; // I am now a member variable
};
Then instantiate FindSum find_sum;, set find_sum.max_sum if needed (perhaps even do that in a constructor), then call the overloaded () operator using find_sum(...).
This technique allows you to pass state into what essentially is a function.
From find_sum, return the so-far maximum sum (instead of void). That means that the recursion-terminating code would be:
if(index == combine.size()) {
int sum =0;
for(int i=0; i<index; ++i) {
sum += combine[i];
}
return sum;
}
and the recursive part would be
int max_sum = 0;
for(int i = start;
i < ar.size() && ar.size()-i > combine.size()-index;
++i) {
combine[index] = ar[i];
int thismaxsum = find_sum(ar, combine, index+1, start+1);
if(thismaxssum > max_sum)
max_sum = thismaxsum;
}
return max_sum;
So, the overall solution is:
#include <iostream>
#include <vector>
int find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start);
int main() {
int N = 10;
int M = 3;
std::vector<int> ar(N);
ar = { 0,9,2,3,7,6,1,4,5,8 };
int index = 0, start = 0;
std::vector<int> combine(M);
int max_sum = find_sum(ar, combine, index, start);
std::cout << max_sum << std::endl;
return 0;
}
int find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start)
{
if (index == combine.size())
{
int sum = 0;
for (int i = 0; i<index; ++i)
{
sum += combine[i];
}
return sum;
}
int max_sum = 0;
for (int i = start;
i < ar.size() && ar.size() - i > combine.size() - index;
++i)
{
combine[index] = ar[i];
int thismaxsum = find_sum(ar, combine, index + 1, start + 1);
if (thismaxsum > max_sum)
max_sum = thismaxsum;
}
return max_sum;
}
Global variables are much better then adding operands and variables to recursion functions because each operand and variable causes heap/stack trashing negatively impact performance and space usage risking stack overflow for higher recursions.
To avoid global variables (for code cosmetics and multi threading/instancing purposes) I usually use context or temp struct. For example like this:
// context type
struct f1_context
{
// here goes any former global variables and stuff you need
int n;
};
// recursive sub function
int f1_recursive(f1_context &ctx)
{
if (ctx.n==0) return 0;
if (ctx.n==1) return 1;
ctx.n--;
return (ctx.n+1)*f1_recursive(ctx.n);
}
// main API function call
int f1(int n)
{
// init context
f1_context ctx;
ctx.n=n;
// start recursion
return f1_recursion(ctx);
}
the f1(n) is factorial example. This way the operands are limited to single pointer to structure. Of coarse you can add any recursion tail operands after the context... the context is just for global and persistent stuff (even if I did use it for the recursion tail instead but that is not always possible).
I want to Write a function which takes 2 arrays-
One array is the source array and the other array is the array of indices.
I want to delete all those elements present at the indices of the source array taking the indices from the second array.
Suppose First array is : {12,5,10,7,4,1,9} and index array is : {2,3,5}.
Then the elements at index 2,3,5. i.e. 10, 7 and 1 are deleted from first array.
So first array becomes : {12,5,4,9}.
If the indices array is sorted,then my O(N) solution is:
#include<iostream>
using namespace std;
int main()
{
int arr[]={12,5,10,7,4,1,9},n=7,indices[]={2,3,5},m=3;
int j=0,k=0;
for(int i=0;i<n,k<m;i++)
{
if(i!=indices[k])
arr[j++]=arr[i];
else
k++;
}
for(i=0; i<j; i++)
cout<<arr[i]<<" ";
return 0;
}
How to do it in O(n) if the indices array is not sorted ?
According to the comments:
Is there any value that will never appear in arr but is representable by int?
You can take that as int max.
Now you can use removeIndices
#include<iostream>
#include<limits>
int removeIndices(int* arr, int n, int* indices, int m){
const int NEVER_IN_ARRAY = std::numeric_limits<int>::max();
for(int i = 0; i < m; i++)
arr[indices[i]] = NEVER_IN_ARRAY;
for(int from = 0, to = 0; from < n; from++)
if(arr[from] != NEVER_IN_ARRAY)
arr[to++] = arr[from];
return n - m;
}
int main(){
int arr[] = {12, 5, 10, 7, 4, 1, 9}, n = 7, indices[] = {2, 3, 5}, m = 3;
int newSize = removeIndices(arr, n, indices, m);
for(int i = 0; i < newSize; i++)
std::cout << arr[i] << " ";
return 0;
}
Edit: With
#include<algorithm>
#include<functional>
We can do:
int removeIndices(int* arr, int n, int* indices, int m){
const int NEVER_IN_ARRAY = std::numeric_limits<int>::max();
std::for_each(indices, indices + m, [arr](int index){ arr[index] = NEVER_IN_ARRAY; });
int* p = std::remove_if(arr, arr + n, std::bind2nd(std::equal_to<int>(), NEVER_IN_ARRAY));
return p - arr;
}
loop thru filter array and mark dead elements with tombstones
create a new array, and copy step-by-step while skipping tombstones
if it's possible use a tombstone value, for example if it is guranteed that -1 doesn't appear in the input then -1 can be the tombstone value
if this is not possible use an array of boolean markers, init them to false
in-place filtering after marking:
for(int i=0,j=0;j<n;i++,j++){
if( a[j] == TOMBSTONE ){
i--; // the loop will add +1
continue;
}
if(i==j)
continue; // skip, no need to write
arr[i]=arr[j];
}
arr input length: n
arr new length: i
May be you want something like this:
#include<iostream>
#define INVALID 99999 //to mark the elements who will disappear
using namespace std;
int main()
{
int arr[] = {0,1,2,3,4,5,6,7,8,9,10};
int indices = {3,1,5};
int indices_len = 3;
int arr_len = 3;
for(int i=0; i<indices_len; i++){
arr[indices[i]] = INVALID;
}
int invalid_count=0;
for(int i=0; i<arr_len; i++){
if(arr[i] == INVALID){
invalid_count++;
}
arr[i-invalid_count] = arr[i];
}
return 0;
}
You must add the result to a new array 1-just iterate over all all elements if the index is in the to delete array continue else copy it to the new array, you can look at the CArray class from MFC it has RemoveAt method
PseudoCode
int old_arr[MAX_SIZE], new_arr[MAX_SIZE];
bool to_del[MAX_SIZE] = {0};
int index_to_del[MAX_SIZE];
for (size_t i = 0; i < MAX_SIZE; ++i)
to_del[index_to_del[i]] = true;
size_t new_size = 0;
for (size_t i = 0; i < MAX_SIZE; ++i)
if (!to_del[i])
new_arr[new_size++] = old_arr[i];
Edit
The above snippet consumes extra space.
If we had to do it in-place, then every time, we delete an element we will have to shift all consecutive elements by 1. In worst case, this could be O(n**2). If you want to do it in-place without yourself copying array elements, you could use vector.
If deletes outnumber reads, then consider using multiset
Here is a solution that does it in-place, does not allocate memory on the heap, does not require flag values, and does it in O(N+M) time:
#include <cstddef>
template<std::size_t N>
std::size_t removeIndices( int(&src)[N], std::size_t srcSize, int const* removal, std::size_t removeSize )
{
bool remove_flags[N] = {false};
for( int const* it = removal; it != removal+removeSize; ++it ) {
remove_flags[*it] = true;
}
int numberKept = 0;
for( int i = 0; i < srcSize; ++i ) {
if( !remove_flags[i] ) {
if (numberKept != i)
src[numberKept] = src[i];
++numberKept;
}
}
return numberKept;
}
Note that it needs full access to the source array, because I create a temporary stack buffer of bool that is the same size. In C++1y, you'll be able to do this without that compile time knowledge using variable length arrays or similar types.
Note that some compilers implement VLAs via (hopefully partial) C99 compatibility already.
Help I don't understand why i can not run this snippet of code it is for a homework assignment and xCode seems to disagree with me when it says I havent defined the function. see bellow in main for the error
template <class Comparable>
Comparable maxSubsequenceSum1( const vector<Comparable> & a, int & seqStart, int & seqEnd){
int n = a.size( );
Comparable maxSum = 0;
for( int i = 0; i < n; i++ )
for( int j = i; j < n; j++ )
{
Comparable thisSum = 0;
for( int k = i; k <= j; k++ )
thisSum += a[ k ];
if( thisSum > maxSum )
{
maxSum = thisSum;
seqStart = i;
seqEnd = j;
}
}
return maxSum;
}
int main(){
vector<int> vectorofints;
vectorofints.resize(128);
for (int i=0; i<vectorofints.size(); i++){
vectorofints[i] = (rand() % 2001) - 1000;
}
maxSubsequenceSum1(vectorofints, 0, 127) //**---->the error i get in xcode is "No matching function for call to maxSubsequenceSum1"
return 0;
}
Change the signature from
Comparable maxSubsequenceSum1( const vector<Comparable> & a,
int & seqStart, int & seqEnd)
to
Comparable maxSubsequenceSum1( const vector<Comparable> & a,
int seqStart, int seqEnd)
The same problem happens if you would do int & i = 0;. You cannot initialize a non-const reference from an rvalue. 0 and 127 are temporary objects that expire at the end of the expression, temporaries cannot bind to non-const references.
You have declared a function that expects two integer references but the one you are calling takes two integers by value.
It should be like this
vector<int> vectorofints;
vectorofints.resize(128);
for (int i=0; i<vectorofints.size(); i++){
vectorofints[i] = (rand() % 2001) - 1000;
}
int k = 0;
int j = 127;
maxSubsequenceSum1(vectorofints, k, j)
return 0;
The compiler is correct. You are calling maxSubsequenceSum1(std::vector<int>&, int, int), you defined maxSubsequenceSum1(std::vector<int>&, int &, int &)
There are 2 quick solutions:
1) Redefine your function to not take a reference.
2) Move your constants to variables and pass them along that way.
Note: there is another problem with your code. You invoke the function maxSubsequenceSum1, but you do not tell it what template parameter to use.
I have been corrected, and the correction is correct. The note is not valid.