User has to make an array from any amount of numbers and I need to rearrange the array, so that the elements from EVEN places would move to the start of an array and from UNEVEN places to the end. For example A=[1,2,3,4,5,6] would turn into B=[2,4,6,1,3,5]. Also I need to use POINTERS.... I am very bad at pointers, so help would be very much appreciated.
This is as far as I got myself. I am not using pointers here though, because I don't know how to.. :(
void switcharoo(int a, int b[]){
int temp[a], j=0;
for(int i=1;i<a;i+=2){
temp[j] = b[i];
j++;
}
for(int i=0;i<a;i+=2){
temp[j] = b[i];
j++;
}
b = temp;
}
Oups, you have still to improve your C++ knowledge...
int temp[a] is not valid C++ as you have been told in comment - Variable Length Arrays are a C feature
b is passed as a pointer (an arrays decays to a pointer to its first element when passed to a function). When you write b=temp; at the end of you function, you only change a local copy... which immediately goes out of scope: in short the current code is just a no-op.
array indices start at 0
If you want to train in using pointers, you could do something like that:
void switcharoo(int a, int b[]) {
int *even = new int[a]; // allocate an array of same size
int *odd = even + a / 2; // point at the mid array element
for (int i = 0; i<a - 1; i += 2) {
*odd++ = b[i]; // odd elements in high part
*even++ = b[i + 1]; // even in low part
}
if (0 != a % 2) { // one odd element remains
*odd++ = b[a - 1];
}
even = odd - a; // make even point again to start of allocated array
odd = even; // store a copy
for (int i = 0; i<a; i++) { // copy back in original array
b[i] = *even++;
}
delete[] odd; // and delete the allocated array
}
Related
I implemented a mergesort algorithm but it returns the exact same array I pass as an input. The following is the code. I am suspecting the pseudocode that our professor gave us is wrong. But I am not sure. I have tried to implement is as best as I can.
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
double* merge(double* b, double* c, int N) {
int i = 0;
int j = 0;
double* result = new double[N];
for(int k = 0; k < N; k++) {
if ((i < len(b)) && (j >= len(c) || b[i] <= c[j])) {
result[k] = b[i++];
} else {
result[k] = c[j++];
}
}
return result;
}
void merge_sort(double* a, int N) {
if (N >= 2) {
int mid = (N+1)/2;
double *left = new double[mid];
double *right = new double[mid];
for (int i = 0; i < mid; i++) {
left[i] = a[i];
}
for (int j = 0; j < mid; j++) {
right[j] = a[mid + j];
}
merge_sort(left, mid);
merge_sort(right, mid);
a = merge(left, right, N);
}
}
Any help would be really appreciated.
In the last line, you assign your result to the local var a, which is then lost. You need to return a, or pass the input as a reference/pointer, otherwise any changes are only to the local copy.
Arguments in the function are basically local variables, they behave like any local variable in this function, except their initial value is set by code that calls this function. a is a pointer that stores the address of first element of your double array.
As it's a local variable, you can modify it but when the function ends, it will be discarded like all other local variables of the function.
There are several ways to deal with this problem, each with their own up and downsides. The most obvious is to return final value of a when you're done sorting. You could also pass a pointer TO a pointer to this function, and then you would be able to modify the pointer outside the function:
void function(int** argument){
*argument = another_function();
}
, but that severely restricts the source of your input. It no longer could be a local array passed by address like this:
int x = 10;
int *y = &x; // if this is what you want to change
function(&y); // this works
// now x is still 10, y points to a different place in memory which can store a different value
int x[1]; // if you would like to change this array in place though...
function(x); // this is how you would call the function, but it would fail because it can't change the address that x refers to
You main issue is here:
// You pass in a pointer to the data here.
// the parameter `a` holds a pointer to the data.
void merge_sort(double* a, int N) {
if (N >= 2) {
// STUFF
// Here you write over `a` (which is fine)
// BUT: You don't pass the value back.
// So the caller never knows what the new value is.
a = merge(left, right, N);
}
}
To fix this. I think it is a mistake to allocate a new array in merge(). Rather re-use the array you have. You have already copied the data into left and right to be sorted. The merge should merge the data back into the original array a.
// Change this:
a = merge(left, right, N);
into
merge(a, left, right, N);
Now in merge() you can use a as the destination.
void merge(double* result, double* b, double* c, int N)
// No longer need to allocate space for result now.
There are a couple of other issues:
1: What do you need len() for?
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
You should already know the length of all parts you should not be re-measuring it. Also this function is completely wrong (the double array is not \0 terminated).
2: The length of b and c is not obvious.
double* merge(double* b, double* c, int N) {
You get the wrong value because you call len() which is not correct.
You could calculate from N but that has issues in that you need to make sure both you merge functions use exactly the same method and that is error prone in the long run. I would personally pass the size of each array as parameters to the function.
3: You leak your intermediate arrays!
You call new to allocate storage.
double *left = new double[mid];
double *right = new double[mid];
But you don't deallocate these objects so they are leaked (for every call to new there should be a corespodning call to delete).
Overall. You can solve a cople of issues by using more C++ style techniques (rather than the C style you are using). Iterators and std::vector spring to mind.
I have this function
void shuffle_array(int* array, const int size){
/* given an array of size size, this is going to randomly
* attribute a number from 0 to size-1 to each of the
* array's elements; the numbers don't repeat */
int i, j, r;
bool in_list;
for(i = 0; i < size; i++){
in_list = 0;
r = mt_lrand() % size; // my RNG function
for(j = 0; j < size; j++)
if(array[j] == r){
in_list = 1;
break;
}
if(!in_list)
array[i] = r;
else
i--;
}
}
When I call this function from
int array[FIXED_SIZE];
shuffle_array(array, FIXED_SIZE);
everything goes all right and I can check the shuffling was according to expected, in a reasonable amount of time -- after all, it's not that big of an array (< 1000 elements).
However, when I call the function from
int *array = new int[dynamic_size];
shuffle_array(array, dynamic_size);
[...]
delete array;
the function loops forever for no apparent reason. I have checked it with debugging tools, and I can't say tell where the failure would be (in part due to my algorithm's reliance on random numbers).
The thing is, it doesn't work... I have tried passing the array as int*& array, I have tried using std::vector<int>&, I have tried to use random_shuffle (but the result for the big project didn't please me).
Why does this behavior happen, and what can I do to solve it?
Your issue is that array is uninitialized in your first example. If you are using Visual Studio debug mode, Each entry in array will be set to all 0xCC (for "created"). This is masking your actual problem (see below).
When you use new int[dynamic_size] the array is initialized to zeros. This then causes your actual bug.
Your actual bug is that you are trying to add a new item only when your array doesn't already contain that item and you are looking through the entire array each time, however if your last element of your array is a valid value already (like 0), your loop will never terminate as it always finds 0 in the array and has already used up all of the other numbers.
To fix this, change your algorithm to only look at the values that you have put in to the array (i.e. up to i).
Change
for(j = 0; j < size; j++)
to
for(j = 0; j < i; j++)
I am going to guess that the problem lies with the way the array is initialized and the line:
r = mt_lrand() % size; // my RNG function
If the dynamically allocated array has been initialized to 0 for some reason, your code will always get stack when filling up the last number of the array.
I can think of the following two ways to overcome that:
You make sure that you initialize array with numbers greater than or equal to size.
int *array = new int[dynamic_size];
for ( int i = 0; i < dynnamic_size; ++i )
array[i] = size;
shuffle_array(array, dynamic_size);
You can allows the random numbers to be between 1 and size instead of between 0 and size-1 in the loop. As a second step, you can subtract 1 from each element of the array.
void shuffle_array(int* array, const int size){
int i, j, r;
bool in_list;
for(i = 0; i < size; i++){
in_list = 0;
// Make r to be betwen 1 and size
r = rand() % size + 1;
for(j = 0; j < size; j++)
if(array[j] == r){
in_list = 1;
break;
}
if(!in_list)
{
array[i] = r;
}
else
i--;
}
// Now decrement the elements of array by 1.
for(i = 0; i < size; i++){
--array[i];
// Debugging output
std::cout << "array[" << i << "] = " << array[i] << std::endl;
}
}
You are mixing C code with C++ memory allocation routines of new and delete. Instead stick to pure C and use malloc/free directly.
int *array = malloc(dynamic_size * sizeof(int));
shuffle_array(array, dynamic_size);
[...]
free(array);
On a side note, if you are allocating an array using the new[] operator in C++, use the equivalent delete[] operator to properly free up the memory. Read more here - http://www.cplusplus.com/reference/new/operator%20new[]/
I needed to swap the contents of two std::string arrays of different sizes. Using std::vector<std::string> to use the swap vector method was the answer for other questions like this one, but using a vector was undesirable in my situation, since the swap is the only moment the arrays might have had their lengths changed - this function would only be called once, at initialization, other than that they'd be (very big) fixed length arrays. At the end I re-structured my code to avoid the swap in the first place, but I'm curious if it's feasible. I tried the following, where n is the length of a and m the length of b, but it segfaults.
void swap_strarr(std::string *a, std::string *b, int n, int m) {
int i;
std::string *tmp;
tmp = new std::string[n];
for (i = 0; i < n; i++) {
tmp[i] = a[i];
}
delete []a;
a = new std::string[m];
for (i = 0; i < m; i++) {
a[i] = b[i];
}
delete []b;
b = new std::string[n];
for (i = 0; i < n; i++) {
b[i] = tmp[i];
}
delete []tmp;
}
I first tried without the deletes on a and b. I also tried using std::string**, which shouldn't even work - and it didn't.
So... is it possible? Or, had I done the swap, should I just use std::vector even though they're fixed size arrays (apart from the swap) and a few million elements long?
Why not simply something like:
std::string* tmp = a;
a = b;
b = tmp;
or even simpler (thanks juanchopanza):
std::swap(a, b);
I have this function in my custom dynamic array class that allows the user to insert another array into this one. It works, but I'm like 99% sure that this is not the fastest solution, and I'm wondering if it is possible to combine the two for loops to increase peformance? If so, how? I'm kinda stuck.
thanks in advance.
void insertrange(T item[], int sizerange, int index)
{
int k = this->size;
int j = 0;
if(this->size + sizerange >= this->capacity) //if the size + added size are bigger than the capacity
{
this->enlarge(this->capacity + sizerange); //enlarge the array
}
for(k; k >= index; k--) //for every element from the end to the index where to add the new array
{
this->array[k + sizerange] = a[k]; //replace the element to his new spot
}
for(j; j < sizerange; j++) //vor every element in the new array
{
this->array[index + j] = item[j]; //place it in the new spot
}
size += sizerange;
}
I think the key is that you don't have to copy the empty cells.
void insertrange(T item[], int sizerange, int index)
{
// This actually points past the end of the current array, right?
int onePastLastEntry = this->size;
// Still need to make sure the new array is large enough
if(this->size + sizerange >= this->capacity) //if the size + added size are bigger than the capacity
{
this->enlarge(this->capacity + sizerange); //enlarge the array
}
// you should be able to go forward instead of backwards
for(i = index; i < onePastLastEntry ; i++)
{
// move the current element
this->array[i + sizerange] = a[i];
// then copy the new value
this->array[i] = item[i - index];
}
You could actually do the loop from zero, going to onePastLastEntry - index as well, but that makes the math weird:
// you should be able to go forward instead of backwards
for(i = 0; i < onePastLastEntry - index; i++)
{
// now you have to add the index in two places here
this->array[i + index + sizerange] = a[i + index];
// and add the index in the copy as well
this->array[i + index] = item[i];
}
The only possible performance benefit I see is doing less dynamic allocation every time the array gets larger. It is better in most cases to multiply the capacity by 2 every time you need to reallocate.
You have one extra copy in your k for loop. The k index should start at size-1, not size, so you are copying one extra element beyond the end of your array. However, this will provide negligible speedup. If serious performance improvement is needed, you should look into optimizing the enlarge function or use a different data structure than an array.
You can move the elements, instead of copying them:
for(k; k >= index; k--)
{
this->array[k + sizerange] = std::move(a[k]);
}
Another possible improvement, especially for classes that have an expensive default constructor, is to construct T in place, using the move constructor. When you allocate, instead of allocating with new T[], which default constructs every element, allocate raw bytes with new char[] or malloc. Then you can use placement new to move construct the object on the spot.
I have a Deck object (deck of cards) which is a double-ended queue implemented as a doubly-linked list. I would like to be able to shuffle the queue at will, but the way I would go about it is beyond me. So instead I've opted to pre-shuffle an array a pointers to the cards and enqueue them after the fact. Problem is, the code I have now doesn't seem to be initializing the pointers at all.
void BuildDeck(Deck* deck) {
Card** cards = new Card*[20];
const size_t MAX_INTEGER_LENGTH = sizeof(int) * 4;
char szPostfix[] = "_Card.bmp";
for(int i = 1; i < 21; i++) {
char path[MAX_INTEGER_LENGTH + sizeof(szPostfix) + 1];
sprintf(path,"%d%s",i, szPostfix);
cards[i-1] = new Card(i,path);
}
ShuffleArray(cards);
for (int i = 0; i < 20; i++) {
deck->PushTop(cards[i]);
}
}
void Swap(Card* a, Card* b) {
Card temp = *a;
*a = *b;
*b = temp;
}
void ShuffleArray(Card** cardArray) {
srand(dbTimer());
for (int i = 0; i < 20; i++)
Swap(cardArray[i],cardArray[rand()%20]);
}
I think where I screwed up is in the card[i] = new Card(...) line, but it somehow looks right to me.
Any suggestions would be appreciated.
DISCLAIMER: I know I should be using the standard library for most of this stuff, but I'm trying to teach myself the hard stuff first. It's just the way I learn.
EDIT: I fixed the index problem. Now I've just gotta figure out why some image aren't drawing now... :/ Thanks for the help!
Your code has many problems
You are looping with 1 <= i <= 20 but for an array of 20 elements indexing goes from 0 <= index <= 19. You need to use cards[i-1] = new Card(i,path);
You are allocating the array of pointers cards but you are not deallocating it (memory leak). Either deallocate it with delete[] cards; once you are done or just use a stack based array with Card *cards[20]; instead of allocating it with new.
The way you compute MAX_INTEGER_LENGTH shows you don't really understand what sizeof does.
This is the reason for which the cards don't get shuffled. You wrote a function that swaps two pointers, but the pointers it is swapping are local variables (parameters) of the function, not the elements of the array. One solution is to pass the parameters as pointer references by declaring swap with void Swap(Card *& a, Card *& b), another solution would be passing pointers to pointers (but this would require a more complex syntax of the implementation because of the double indirection and would also require a change in the way you call the function).
In the first for loop your starting index is 0, while in the second for loop the starting index is 0. That could be the problem.
Your code:
for(int i = 1; i < 21; i++) {
char path[MAX_INTEGER_LENGTH + sizeof(szPostfix) + 1];
sprintf(path,"%d%s",i, szPostfix);
cards[i] = new Card(i,path);
}
Here the loop should start from 0 to 20 as:
for(int i = 1 ; i < 21; i++) //incorrect - original code
for(int i = 0 ; i < 20; i++) //correct - fix
And after the fix, you could use i+1 instead of i in :
sprintf(path,"%d%s",i+1, szPostfix);
cards[i] = new Card(i+1,path);
if that is required.