C++ int array pointers recursively to find prime factors - c++

I am trying to make a function that can return the prime factors of a given number in an array (or multi-set, but I'm trying to use an array).
For example, if I put in 12, I want to get 2, 2, and 3, not 2, and 3 like with a set. This is so that I can use these to see if it is a Smith number or not, so I need the numbers seperately.
Also, I am taking a recursive approach.
I have tried (to no avail) to return the array many ways, including passing an initial pointer into the code which points to a space to store the array.
I've tried just initializing the array in the function and then returning it.
From what I can tell, I can get the array back from the base case iteration and then when trying to construct a new array with size oldArray+1 to copy values to, things get messy. This is where I get lost.
From what I've read, although this isn't the most efficient implementation, I should be able to make it work.
I have a function, nextPrime(int n), which given n will give back the next prime up from that number.
See source below:
int* find(int n, int p) {
int root = (int) floor(sqrt(n));
if (p > root) {
// Base case, array gets initialized and returned
// depending on value of n and p.
if (n > 1) {
factors = new int[1];
factors[0] = n;
return factors;
}
else {
factors = new int[0];
return factors;
}
}
else
if (n%p == 0){
// Inductive step if p is a factor
int newFloor = (int) floor(n/p);
factors = find(newFloor, p);
// Initialize new array.
int* newFactors;
newFactors = new int[(sizeof(factors) / sizeof(int)) + 1];
// Add p to first slot, fill rest with contents of factors.
factors[0] = p;
for (int i = 0; i < (sizeof(factors) / sizeof(int)); i++) {
newFactors[i+1] = factors[i];
}
return newFactors;
}
else {
// Inductive step p isn't a factor of n
factors = find(n, factors, nextPrime(p));
return factors;
}
}
As I say, the error is with returning the array and using its value, but why does it seem to return OK from the first iteration?

Something like this could work. Not terribly efficient !!
void FindFactors( int number , std::vector<int>& factors )
{
for ( int i = 2; i <= number; ++i )
{
if ( number % i == 0 )
{
factors.push_back( i );
FindFactors( number / i , factors);
break;
}
}
}
int main()
{
std::vector<int> factors;
FindFactors( 121 , factors );
return 0;
}
After you call the function factors will contain only the prime factors.

You should be using std::vector for this. The main problem you have is that a pointer to an array has no way of knowing the number of items the array contains. Concretely, the part where you say sizeof(factors) is wrong. As I understand, you're expecting that to give you the number of items in the array pointed to by factors, but it really gives you the number of bytes needed to store a pointer to int.
You should be either returning a vector<int> or passing it in as a reference and updating it each time you find a factor.

Related

Manipulating array's values in a certain way

So I was asked to write a function that changes array's values in a way that:
All of the values that are the smallest aren't changed
if, let's assume, the smallest number is 2 and there is no 3's and 4's then all 5's are changed for 3's etc.
for example, for an array = [2, 5, 7, 5] we would get [2, 3, 4, 3], which generalizes to getting a minimal value of an array which remains unchanged, and every other minimum (not including the first one) is changed depending on which minimum it is. On our example - 5 is the first minimum (besides 2), so it is 2 (first minimum) + 1 = 3, 7 is 2nd smallest after 2, so it is 2+2(as it is 2nd smallest).
I've come up with something like this:
int fillGaps(int arr[], size_t sz){
int min = *min_element(arr, arr+sz);
int w = 1;
for (int i = 0; i<sz; i++){
if (arr[i] == min) {continue;}
else{
int mini = *min_element(arr+i, arr+sz);
for (int j = 0; j<sz; j++){
if (arr[j] == mini){arr[j] = min+w;}
}
w++;}
}
return arr[sz-1];
}
However it works fine only for the 0th and 1st value, it doesnt affect any further items. Could anyone please help me with that?
I don't quite follow the logic of your function, so can't quite comment on that.
Here's how I interpret what needs to be done. Note that my example implementation is written to be as understandable as possible. There might be ways to make it faster.
Note that I'm also using an std::vector, to make things more readable and C++-like. You really shouldn't be passing raw pointers and sizes, that's super error prone. At the very least bundle them in a struct.
#include <algorithm>
#include <set>
#include <unordered_map>
#include <vector>
int fillGaps (std::vector<int> & data) {
// Make sure we don't have to worry about edge cases in the code below.
if (data.empty()) { return 0; }
/* The minimum number of times we need to loop over the data is two.
* First to check which values are in there, which lets us decide
* what each original value should be replaced with. Second to do the
* actual replacing.
*
* So let's trade some memory for speed and start by creating a lookup table.
* Each entry will map an existing value to its new value. Let's use the
* "define lambda and immediately invoke it" to make the scope of variables
* used to calculate all this as small as possible.
*/
auto const valueMapping = [&data] {
// Use an std::set so we get all unique values in sorted order.
std::set<int> values;
for (int e : data) { values.insert(e); }
std::unordered_map<int, int> result;
result.reserve(values.size());
// Map minimum value to itself, and increase replacement value by one for
// each subsequent value present in the data vector.
int replacement = *values.begin();
for (auto e : values) { result.emplace(e, replacement++); }
return result;
}();
// Now the actual algorithm is trivial: loop over the data and replace each
// element with its replacement value.
for (auto & e : data) { e = valueMapping.at(e); }
return data.back();
}

while every value in array is different than specific int value

I have an array of values e.g. 1, 4, 7, 2.
I also have another array of values and I want to add its values to this first array, but only when they all are different from all values that are already in this array. How can I check it? I've tried many types of loops, but I always ended with an iteration problem.
Could you please tell me how to solve this problem? I code in c++.
int array1[7] = {2,3,7,1,0};
int val1 = rand() % 10;
int val2 = rand() % 10;
int array2[2] = {val1, val2};
and I am trying to put every value from array2 into array1. I tried loop
for (int x:array2)
{
while((val1 && val2) == x)
{
val1 = rand() % 10;
val2 = rand() % 10;
}
}
and many more, but still cannot figure it out. I have this problem because I may have various number of elements for array2. So it makes this "&&" solution infinite.
It is just a sample to show it more clearly, my code has much more lines.
Okay, you have a few problems here. If I understand the problem, here's what you want:
A. You have array1 already populated with several values but with space at the end.
1. How do you identify the number of entries in the array already versus the extras?
B. You have a second array you made from two random values. No problem.
You want to append the values from B to A.
2. If initial length of A plus initial length of B is greater than total space allocated for A, you have a new problem.
Now, other people will tell you to use the standard template library, but if you're having problems at this level, you should know how to do this yourself without the extra help from a confusing library. So this is one solution.
class MyArray {
public:
int * data;
int count;
int allocated;
MyArray() : data(nullptr), count(0), allocated(0) {}
~MyArray() { if (data != nullptr) free(data); }
// Appends value to the list, making more space if necessary
void add(int value) {
if (count >= allocated) {
// Not enough space, so make some.
allocated += 10;
data = (data == nullptr) malloc(allocated * sizeof(int))
: realloc)data, allocated * sizeof(int));
}
data[count++] = value;
}
// Adds value only if not already present.
void addUnique(int value) {
if (indexOf(value) < 0) {
add(value);
}
}
// Returns the index of the value, if found, else -1
int indexOf(int value) {
for (int index = 0; index < count; ++index) {
if (data[index] == value) {
return index;
}
}
return -1;
}
}
This class provides you a dynamic array of integers. It's REALLY basic, but it teaches you the basics. It helps you understand about allocation / reallocating space using old-style C-style malloc/realloc/free. It's the sort of code I was writing back in the 80s.
Now, your main code:
MyArray array;
array.add(2);
array.add(3);
array.add(7);
// etc. Yes, you could write a better initializer, but this is easy to understand
MyArray newValues;
newValues.add(rand() % 10);
newValues.add(rand() % 10);
for (int index = 0; index < newValues.count; ++index) {
array.addUnique(newValues.data[index]);
}
Done.
The key part of this is the addUnique function, which simply checks first whether the value you're adding already is in the array. If not, it appends the value to the array and keeps track of the new count.
Ultimately, when using integer arrays like this instead of the fancier classes available in C++, you HAVE TO keep track of the size of the array yourself. There is no magic .length method on int[]. You can use some magic value that indicates the end of the list, if you want. Or you can do what I did and keep two values, one that holds the current length and one that holds the amount of space you've allocated.
With programming, there are always multiple ways to do this.
Now, this is a lot of code. Using standard libraries, you can reduce all of this to about 4 or 5 lines of code. But you're not ready for that, and you need to understand what's going on under the hood. Don't use the fancy libraries until you can do it manually. That's my belief.

C++, Overloading, Creating functions in the class that receive an array and the size of the array as input, and find the smallest value

I am currently learning C++. I run into troubles when I work on an Overloading problem. The function in the class supposed to receive the array and size of the array as input and output the smallest value. There are three arrays in total including int, float, and char. My code works only under int. I can't understand why I have attached my code below. Can anyone tell my mistake?
I know there must be a better method than mine, I really wanna to figure out why my code doesn't work for float and char case. Any help will be greatly appreicated.
For the int case, it can correctly output the smallest value which is 2. However for the float condition, it keeps giving me 0 instead a number from the float list.
Main function
int main()
{
Compare c;
int arrayInt[5] = {65,43,2,898,678};
float arrayInF[4] = {4.5,4.9,4.3,6.5};
char arrayInC[6] = {'w','z','t','h','e','c'};
std::cout<<c.findSmaller(arrayInt, 5)<<" is the smallest of the input array\n";
std::cout<<c.findSmaller(arrayInF, 4)<<" is the smallest of the input array\n";
std::cout<<c.findSmaller(arrayInC, 6)<<" is the smallest of the input array\n";
return 0;
}
Class
class Compare
{
public:
int findSmaller(int input1[],int input2);
float findSmaller(float input1[],int input2);
};
int Compare::findSmaller(int input1[], int input2)
{
int small;
for(int i=0;i<input2;i++)
{
if(input1[i]<input1[i+1])
{
small = input1[i];
input1[i+1] = small;
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
}
return small;
}
float Compare::findSmaller(float input1[], int input2)
{
float small;
for(int i=0;i<input2;i++)
{
if(input1[i]<input1[i+1])
{
small = input1[i];
input1[i+1] = small;
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
}
return small;
}
char Compare::findSmaller(char input1[], int input2)
{
char small;
for(int i=0;i<input2;i++)
{
if(input1[i]<input1[i+1])
{
small = input1[i];
input1[i+1] = small;
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
}
return small;
}
The reason the code does not work as you expect is two fold
because your algorithm is destructive
because you are overstepping array bounds
your code snippet:
if(input1[i]<input1[i+1]) // <-- 2) over step array when i = (input2 - 1)
{
small = input1[i];
input1[i+1] = small; // <-- 1) this will overwrite the NEXT value
}
else
{
small = input1[i+1];
input1[i+1] = small;
}
if you walk through this with your arrayInt input
int arrayInt[5] = {65,43,2,898,678};
the data becomes {65, 43, 2, 2, 2} as it executes, destroying the original data.
c and c++ use 0 base indexing, meaning a 4 element array is indexed 0, 1, 2, 3, etc so when you are iterating "i < input2" where input2 = 5 the first iteration i will equal 0 and the last iteration i will equal 4. When your code then makes reference to input1[i+1] that would then be input1[5] which is out of bounds but not necessarily undefined nor 0. You see, the compiler will try to allocate an array in a continuous block of memory like so:
| item 0 | item 1 | item 2 | item 3 | item 4 | etc.
referencing input1[5] will simply return the next block of memory interpreted as the expected data type, an integer in the case of arrayInt.
Since the 3 arrays are declared together, the compiler allocated their space together, this means that arrayInt is adjacent to arrayInf in physical memory, which also means that arrayInt[5] would be the same as (int)arrayInf[0]. 4.5 float is a large integer and will engage the destructive nature of your algorithm, meaning that when iterating over the arrayInt you actually overwrote the 4.5 float with an integer 2 and that's going to be interpreted as a really small float, so you've clobbered the first element of the arrayInf array.
#Bo-r gives an example of a better algorithm for doing what you want.
float arrayInF[4] = {4.5, 4.9, 4.3, 6.5};
has 4 values (use whitespace in your code, it makes reading it much easier)
You pass in an input2 (use more descriptive variable names, too) of 4 which means that
for(int i=0;i<input2;i++)
i goes up to 3.
You then access array indices 3 and 3+1=4 here (and other places as well):
if(input1[i]<input1[i+1])
When you only have valid indices up to 3, which completely breaks your program. Once you read/write invalid memory locations, the behavior of your program becomes undefined. It may still look like it's working sometimes, but that's just sheer luck.
This problem is not limited to just the float implementation.
Seems you haven't declare and implemented the method char Compare::findSmaller(char *input1, int input2).
A example of such an implementation would be:
char Compare::findSmaller(char input1[], int input2) {
assert(input2 >0);
char small = input1[0];
for (int i = 1; i < input2; i++)
if (input1[i] < small)
small = input1[i];
return small;
}

Dynamic Programming, Traversal Method

int fib(int numb){
vector<int> temp;
int str;
if(numb==0 || numb==1){
return numb;
}
else{
str=(fib(numb-1)+fib(numb-2));
temp.push_back(str);
return str;
}
for(int i=0;i<temp.size();i++){
if(temp[i]==numb){
return temp[i];
}}
Fibonacci function and it work but how do I check if the for loop part of the function really works? Its for a traversal method of finding a existing number and returning it instead of processing another recursion.
Your loop can't possibly work. It will never work. Because there's no way to get to the loop. Every code path before the loop ends with a return statement.
Walk through your code, statement by statement, and see for yourself that your code will never reach the loop.
You must process the stored elements before returning any value. More, as you store elements in vector during recursive calls, the vector temp must be static.
And the research should not be that: you should store in the vector the values, said differently, what you want it temp[i] is fib(i).
A simple way to do that is to make use that C++ allows initializing of static values through functions. You could then initialize temp to { 0, 1}, and when asked for a value, just look if the number is higher than temp.size:
if it is, compute it and store it into temp - as you compute them with values of fib(n-1) and fib(n-2), when you compute it you know that the temp vector already contains fib(n-1), and does not still contains fib(n) => you have just to push it back into temp
it not just extract it from temp
Code could be:
// return a temporary vector containing 0 and 1
std::vector<int> inifib() {
std::vector<int> t;
t.push_back(0);
t.push_back(1);
return t;
}
int fib(unsigned int numb) {
static std::vector<int> temp = inifib(); // initialize once the static temp with size 2 and values 0,1
if (numb >= temp.size()) {
int cr = fib(numb-1) + fib(numb - 2);
temp.push_back(cr); // when we are here, temp contains everything up to fib(numb - 1) - just push
}
return temp[numb];
}

c++ type error message from compiler, what does it mean?

I'm using g++ on fedora linux 13.
I'm just practicing some exercises from my c++ textbook
and can't get this one program to compile. Here is the code:
double *MovieData::calcMed() {
double medianValue;
double *medValPtr = &medianValue;
*medValPtr = (sortArray[numStudents-1] / 2);
return medValPtr;
}
Here is the class declaration:
class MovieData
{
private:
int *students; // students points to int, will be dynamically allocated an array of integers.
int **sortArray; // A pointer that is pointing to an array of pointers.
double average; // Average movies seen by students.
double *median; // Median value of movies seen by students.
int *mode; // Mode value, or most frequent number of movies seen by students.
int numStudents; // Number of students in sample.
int totalMovies; // Total number of movies seen by all students in the sample.
double calcAvg(); // Method which calculates the average number of movies seen.
double *calcMed(); // Method that calculates the mean value of data.
int *calcMode(); // Method that calculates the mode of the data.
int calcTotalMovies(); // Method that calculates the total amount of movies seen.
void selectSort(); // Sort the Data using selection sort algorithm.
public:
MovieData(int num, int movies[]); // constructor
~MovieData(); // destructor
double getAvg() { return average; } // returns the average
double *getMed() { return median; } // returns the mean
int *getMode() { return mode; } // returns the mode
int getNumStudents() { return numStudents; } // returns the number of students in sample
};
Here is my constructor and destructor and selectSort():
MovieData::MovieData(int num, int movies[]) {
numStudents = num;
// Now I will allocate memory for student and sortArray:
if(num > 0) {
students = new int[num];
sortArray = new int*[num];
// The arrays will now be initialized:
for(int index = 0;index < numStudents;index++) {
students[index] = movies[index];
sortArray[index] = &students[index];
}
selectSort(); // sort the elements of sortArray[] that point to the elements of students.
totalMovies = calcTotalMovies();
average = calcAvg();
median = calcMed();
mode = calcMode();
}
}
// Destructor:
// Delete the memory allocated in the constructor.
MovieData::~MovieData() {
if(numStudents > 0) {
delete [] students;
students = 0;
delete [] sortArray;
sortArray = 0;
}
}
// selectSort()
// performs selection sort algorithm on sortArray[],
// an array of pointers. Sorted on the values its
// elements point to.
void MovieData::selectSort() {
int scan, minIndex;
int *minElement;
for(scan = 0;scan < (numStudents - 1);scan++) {
minIndex = scan;
minElement = sortArray[scan];
for(int index = 0;index < numStudents;index++) {
if(*(sortArray[index]) < *minElement) {
minElement = sortArray[index];
minIndex = index;
}
}
sortArray[minIndex] = sortArray[scan];
sortArray[scan] = minElement;
}
}
The compiler is giving this error:
moviedata.cpp: In memberfunction
'double * MovieData::calcMed()':
moviedata.cpp:82: error: invalid
operands of types 'int*' and 'double'
to binary 'operator/'
I'm not sure what to make of this error, i've tried static casting the types with no luck, what does this error message mean?
you are trying to divide a pointer by a double, which the compiler is saying it does not know how todo.
sortArray is probably defined by
int ** sortArray;
its also worth noting you are returning a pointer to a stack variable, who's value will be undefined as soon as you return out of the function.
sortArray[numStudents - 1] is a pointer to int, which can't be on the left side of a division (when you remember pointers are addresses, this makes sense). If you post more of your code, we can help you correct it.
Perhaps you want something like:
int *MovieData::calcMed() {
return sortArray[(numStudents - 1) / 2];
}
This returns the middle element in your array, which should be a pointer to the middle student. I'm not clear why you're sorting lists of pointers (not the actual values), or why you're returning a pointer here. The return value + 1 will be a pointer to the next value in students, which is not the next greater value numerically. So you might as well return the actual student (int from students). If you do this, you can also average the two middle elements when the count is even (this rule is part of the typical median algorithm).
Note that I changed the return type to int *, the type of sortArray's elements. Also, your comment is incorrect. This is the median, not the mean.
Also, your selection sort is wrong. The inner loop should start at scan + 1.
Your code shows a lack of understanding of pointers. You need to do more reading and practice on simpler examples.
More specifically:
double medianValue; creates a double variable. What for? You're apparently going to return a double * and returning a pointer to a local variable is always wrong, because local variables are "recycled" when their function ends.
double *medValPtr = &medianValue; creates a pointer called medValPtr and sets it to the location of medianValue. Well.
Due to the current contents of medValPtr, *medValPtr = (sortArray[numStudents-1] / 2); has the same effect as typing medianValue = (sortArray[numStudents-1] / 2); (supposing it were to compile at all).
Which it doesn't because sortArray[numStudents-1] is, at a guess, the last item in the array sortArray but happens to be a pointer to something else. You can't divide a pointer (numerically you can, but C++ disallows it's always wrong).
Finally you return medValPtr; which is wrong because medValPtr is pointing to a local variable.
You probably want something like:
int *MovieData::calcMed() {
return sortArray[numStudents/2];
}