for(int i = 1; i < upto; i *= 2)
{ for(int j = 0; j < (upto - i); j += (2*i))
{ int end2 = (2*i < (upto - j)) ? 2*i : upto - j;
mymerge(&(array[j]), i, end2); } }
I'd like to know how upto
is defined here. Is it the size of array
? Calling it size
or count
might make this clearer.
This is a weird format. Here you always put your {
on a new line and then put the code after it on the same line. Elsewhere you put your {
on the same line and put the code after it on a new line.
}else if(arr[i].dob >= arr[j].dob){
temp[k] = arr[j];
j += 1; }
Again, I have trouble following the rules around your formatting. On one line, you start your }
on a new line and then later you put it at the end of a line. By doing this you make it hard to scan the code quickly. The read has to check each line to see if there are any {
or }
on it. It's much easier if they are consistently in the same place so that the reader can follow the structure quickly.
There are three main formats:
Always a new line (BSD style)
if ( true )
{
// code here
}
else
{
// more code
}
Always close alone on a new line (half cuddled)
if ( true ) {
// code here
}
else {
// more code
}
Always share if you can (K&R)
if ( true ) {
// code here
} else {
// more code
}
Most of the code that you'll be reading will follow one of these rules. If your code does as well, then it's going to be much easier for people to follow. We'll already know the rules. I prefer the last version, but there are arguments for and against each.
I also prefer to have spaces between almost all tokens. Note that I write if (
rather than if(
. This helps separate things like an if
from function calls. It also makes it easier to see the if
as it is separate from the opening parenthesis and the first token of the expression. Your format has things like if(arr[i].dob
which one has to read moderately thoroughly to see what goes with what.
people * temp = new people[end2];
You redo this for each call to your helper function. Better would be to do this outside the function and reuse the array for each call. You may only be using \$O(n)\$ memory at any time, but you are doing \$O(n \log n)\$ memory allocations. You could do just one (and you have to do that one anyway to do the last merge).
Note that using a standard data type (e.g. std::vector
) and letting C++ manage the memory for you should do much the same thing. A smart enough compiler could allocate the memory ahead of time and just do one. If you're doing it manually, try to be at least as smart as the compiler might be.
You ask about iterative and recursive solutions. A purely iterative solution with no function calls is potentially faster, but a good compiler should optimize most of that away. If speed is that important to you, profile both solutions and see if there is a significant difference.
Unless the compiler can optimize out the recursion, a recursive solution will generally be the slowest. Each function call requires the program to save the current state of the world on the stack. Doing so recursively means that you would have to maintain up to \$O(\log n)\$ function calls at any one time. The point of recursion is generally to improve elegance and readability rather than performance.
I won't cover it again, but I agree with Loki Astari's answer on using the <
and ++
operators. That would also make it easier to run this same sort with std:sort
which is proven correct (less chance of bugs) and might be more efficient. At least it's a possibility worth profiling.
As a side issue, I usually do sorting like this in the database. This is a relatively straightforward three column index in a database. Then sorts are done via insertion sort at write time rather than sorting all the data at read time. You don't post the rest of the code, so it's not clear to me why you are not doing this in the database.