Some mysterious stack mechanism in C++ - c++

While learning how to write quick sort I came across a certain implementation that is very unclear for me. Here is the beginning of it:
void quick_sort_iterative(int start, int end)
{
range stack[32]; // 1. why 32? why not 2? why not 1024? what is it?
range * s = stack; // 2. just a simple pointer = an array?
s->start = start; // 3. are these two values currently on top of the stack?
s->end = end;
s++; // 4. how does it work? it's pushing something on the stack?
// sort as long as there are any ranges [start, end] to sort left
while (s > stack) // 5. comparing a pointer and an array and it works?
Could someone please explain me those 5 things? :) Thank you.
Here is the entire code (the last one on the page, with the descriptions):
code

So. Presumably range is some object with two integer parameters start and end. I can't tell much more than that.
For whatever reason, the designers of the algorithm believe that they won't need more than 32 fake stack frames.
The array decays to a pointer. You can think of this as &stack[0].
s->start is currently the same as s[0].start.
s now points to &stack[1].
The array decays to a pointer. So that is true as long as s doesn't point to &stack[0].

Maybe just a number picked from their nether region, or perhaps arrived at through careful examination of the maximum stack depth of the algorithm. I'm guessing the former.
Any array variable will naturally decay to a pointer when used in a context that requires a pointer.
If you consider the first element of the "stack" array to be the top, then yes.
Given the assumption in 3 then incrementing the pointer would indeed be moving to the next element down on the stack.
See 2. Presumably the loop is decrementing s and they want to stop when it reaches the top of the stack again.

Related

How can I test whether an array element is defined or not (where element can be defined as 0)?

DISCLAIMER: I'm very new to C++ so I'm sorry if this is a stupid question!
I'm trying to read in data to an 1000 element array (double) and then if there are less than 1000 data points to read in ignore the excess elements for the rest of my program.
I've defined a 1000 element array and read in the data and now want to carry out a function on each element which has been defined by the read in data point. How do I test if an element is defined yet? I would use a Boolean algebra test i.e. if(array[i]) {\\function} but the data points can be any natural number including zero, so I don't know if this would work. How would I solve this problem?
The most typical approach to the problem of "the number of things in my array is not fixed ahead of time" is to have a variable that keeps track of how many things are actually in the array. Then, you just loop over that many things.
Since you add the C++ tag, you can (and should) use the vector class to manage everything for you — and you even get the added benefit that it can grow beyond 1000 elements should you happen to have more than that.
(aside: if you insist on sticking with a 1000-long array, you really should make sure you do something appropriate should you actually get more than 1000 data points)
You could initialize your array with a sentinel value like NAN (i.e., not a number):
double array[1000];
std::fill(std::begin(array), std::end(array), NAN);
Then fill sequentially your array:
array[0] = 1.2;
array[1] = 2.3;
array[2] = 3.4;
And then break the loop as soon as this value is met:
for(int i(0); i < 1000; ++i) {
if(isnan(array[i])) break;
function(array[i]);
}
LIVE DEMO

Translating the following C++ code into Nim

I'm trying to learn Nim by converting different pieces of code, and I've stumbled upon something which I've never seen before.
#include<bits/stdc++.h>
...
for(int t=q&1?u+x:u+x>>1;t>1;)t/=p[++cnt]=sieve[t];
...
sort(p+1,p+cnt+1);
I understand what the ternary operator is and how it works, what I don't quite get is what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers). How does using an increment as the index of "p" work?
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does (the fact that it's taking an integer added to an array obviously doesn't help).
Lets first start of by making the code a little more readable. A little bit of whitespace never hurt anybody.
for(int t = (q & 1? u + x: u + x >> 1); t > 1;)
{
t /= p[++cnt] = sieve[t];
}
what's going on with the variables "t" and "cnt" (both integers) and the array "p" (an array of integers)
So t is being set to either u + x or u + x >> 1 depending on what q & 1 is. Then inside the loop we are dividing t by whatever the value of sieve at the index of t is. We are also assign that value to the p array at the position of ++cnt. ++cnt is using the pre increment operator to increase the value of cnt by 1 and then using that value for the index of p.
Then there's the sort function, in which I completely gave up because I couldn't find any documentation on what it does
For this I am assuming they are using the std::sort() function. When dealing with arrays the name of the array is treated as a pointer to the first element of the array. So when we see sort(p+1,p+cnt+1); you can translate it to sort(one from the begining of the array, cnt + 1 elements from the begining of the array);. So this is going to sort all of the elements in the array from one from the begining of the array to one less than cnt + 1 elements from the begining of the array.
Are you trying to learn Nim as you said, or trying to learn C? Both things you asked about are pretty basic c:
++cnt has the side effect (cnt=cnt+1) combined with the value that cnt ends up with. That value is used as the index. The side effect is a side effect.
p+1 and p+cnt are each pointers. The name of an array is treated as a constant pointer to the first element of that array in most uses within C. A pointer plus an integer is another pointer, pointing that number of elements past the original.

Replacing For loop with memcopy, memmove, or std:copy?

I've got shift function where i an continuously sending it new data points and it will shift my points by an offset of 1. This is to achieve a "graphical shifting" where the points represent points on a graph.
The shifting function is the following:
void Chart_Buffer::ShiftData()
{
for(int index = 0; index < (_channel_Samples - 1); ++index)
{
_sample_Points[index].y = _sample_Points[index + 1].y;
}
return;
}
The problem with this is that it is running through a huge array of up to 800 data points and it does this every time for every new data point added, so i wanted to see if i can optimize this process by shifting all values out by an offset of 1 without running through a for loop. I looked at implementations of memcopy, memmove, and std::copy, but i cant figure out how to use them for my purpose.
Basically, if i have elements 0-799 in the array, i want to shift elements 1-799 by 1 so that i have 0-798 and then just add the new element to the array.
Edit: _sample_Points is type tagPOINT with the following structure:
typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;
It's hard to give a firm answer to this without knowing what you are doing with _sample_Points. But I believe that I can firmly say that copying every element in the array down one is an expensive approach.
In the best case: You just need to access the front of the array and add to the back of the array. If that's the case you're describing a queue.
To add a new element to the back of a queue use: push
To inspect the front element use: front
To "copy everything down one" (just delete the front element) use: pop.
Otherwise you'd be in the case where: You need random access to the array. If that's the case you can still get potentially better performance from a deqeu.
To add a new element to the back of a deque use: push_back
To inspect the front element use: front
To "copy everything down one" (just delete the front element) use: pop_front
So if you use a queue for your _sample_Points Chart_Buffer::ShiftData could be replaced by _sample_Points.pop().
If you use a deque for your _sample_Points Chart_Buffer::ShiftData could be replaced by _sample_Points.pop_front().
It looks like that you are looking for a std::deque. It is a double ended queue, which means you can pop an element from the back and push on the front.
If what you are looking for is to keep the elements of your array in a certain order, this will help you do just that.
Now if you also want to have them contiguously on memory, then you could do it like this:
memmove(array+1, array, sizeof(element)*(array_size-1));
array[0] = new_element;
You cannot do this without less operations than you are already doing, whether you spell all of them or you call an algorithm. The problem is that the operation is not what you described initially, it is not shifting the data, but shifting part of the data (only the y coordinate) but leaving the other half as it is.
If you don't want to spell out the operation, you can play with the transform algorithm in a way similar to the answer by id256, but I am not sure whether that is an improvement really, the loop in the question is easier and cleaner than the transform...
If it is an acceptable amount of refactoring of your code, you could also let go of tagPOINT and instead of having one _sample_Points, have two arrays, one for the x and one for the y. Then you can memmove() the array of ys. Like:
LONG _sample_Points_x[DIMENSION];
LONG _sample_Points_y[DIMENSION];
void Chart_Buffer::ShiftData() {
memmove(_sample_Points_y, _sample_Points_y + 1, (DIMENSION-1) * sizeof _sample_Points_y[0]);
}

Implementing own quicksort on dynamic array

I have to implement my own sort on a dynamic string array, e.g. of such array is:
string * sortArray;
I then read in the size of the array from a text file and make the array as long as needed and fill it. So, I have...
sortArray = new string[_numberOfNames];
for(int i = 0; i < _numberOfNames; ++i){
sin >> _data[i];
}
Now I need to create my own sorting method and I thought I'd go with quicksort. My problem is, I'm not sure how to go about it.
When I choose a pivot, how can I then go about setting up two more dynamic string arrays to put the lower values and highers values in to, then recurse on? There is no way of knowing before hand how big each array needs to be before I start putting values into them.
I thought I could do something like define the size of each array as being the same as the array being sorted, and then some how remove any unwanted empty spaces from the end, but I'm not sure this is possible?
Any help would be much appreciated.
P.S. I know about the std::sort, I already have this in the program, I'm just trying to implement a sort myself.
Two options as from the comments above:
1.) Use std::vector. There you can have variable size arrays.
2.) Use an "in place" version of quicksort that does the sorting in your original array. See http://en.wikipedia.org/wiki/Quicksort#In-place_version
Lets say you have array size N
and you pivot value is x
what you should do is like that, have two pointers one to the beginning(0) and one to the end (N-1). they should both move to the middle. when ever the beginning pointer value is greater than x and the end pointer value is lower than x switch their values. after you finished and placed x in his new location (where the two pointers met) continue recursionally for the part left to x and right to x.

Queue + Stack C++

How do u push Items to the front of the array, ( like a stack ) without starting at MAXSIZE-1? I've been trying to use the modulus operator to do so..
bool quack::pushFront(const int nPushFront)
{
if ( count == maxSize ) // indicates a full array
{
return false;
}
else if ( count == 0 )
{
++count;
items[0].n = nPushFront;
return true;
}
intBack = intFront;
items[++intBack] = items[intFront];
++count;
items[(top+(count)+maxSize)%maxSize].n = nPushFront;
/*
for ( int shift = count - 1; shift >= 0; --shift )
{
items[shift] = i€tems[shift-1];
}
items[top+1].n = nPushFront; */
return true;
}
"quack" meaning a cross between a queue and a stack. I cannot simply shift my elements by 1 because it is terribly inefficient. I've been working on this for over a month now. I just need some guidence to push_front by using the modulus operator...I dont think a loop is even necessary.
Its funny because I will need to print the list randomly. So if I start adding values to the MAXSIZE-1 element of my integer array, and then need to print the array, I will have garbage values..
not actual code:
pushFront(2);
pushFront(4);
cout << q;
if we started adding from the back i would get several null values.
I cannot just simply shift the array elements down or up by one.
I cant use any stls, or boosts.
Not sure what your problem is. Are you trying to implement a queue (which also can work as a stack, no need for your quack) as a ring buffer?
In that case, you need to save both a front and a back index. The mechanics are described in the article linked above. Pay attention to the “Difficulties” section: in particular, you need to either have an extra variable or pay attention to leave one field empty – otherwise you won’t know how to differentiate between a completely empty and a completely full queue.
Well, it seems kind of silly to rule out the stl, since std::deque is exactly what you want. Amortized constant time random access. Amortized constant insert/removal time from both the front and the back.
This can be achieved with an array with extra space at the beginning and end. When you run out of space at either end, allocate a new array with twice the space and copy everything over, again with space at both the end and the beginning. You need to keep track of the beginning index and the end index in your class.
It seems to me that you have some conflicting requirements:
You have to push to the head of a C++ array primitive.
Without shifting all of the existing elements.
Maintain insertion order.
Short answer: You can't do it, as the above requirements are mutually exclusive.
One of these requirements has to be relaxed.
To help you without having to guess, we need more information about what you are trying to do.