Segregate Even and Odd numbers In an Integer Array using Recursion - arrays

I am doing an algorithm exercise, which asks to rearrange an array of integers, to put all the even-valued elements before odd-valued elements.
I thought for a while and came up with the following pseudo code:
int[] Rearrange(int [] arr)
{
if arr.length=1
return arr;
if arr[0] is even
return arr[0] followed by Rearrange(arr.subarray(1,arr.length))
else
return Rearrange(arr.subarray(1,arr.length)) followed by arr[0]
}
I am bit concerned about my proposed solution above, since I need to do a copy operation in each recursion cycle, which is expensive. Experts please kindly advise, thanks!

Recursion is expensive, and your approach would create tons of extra copies. Sometimes recursion yields an elegant solution, and other times it is absolutely the wrong tools for the job. This is a wrong-tool-for-the job case.
Instead, write a method that keeps a head index and a tail index. Initialize the head pointer to the beginning of the array and the tail index to the end.
At each pass, loop through the items at the head of the list, looking for odd values. When you find one, stop, then look for an even value from the end, looking backwards. When you find one, switch the two values (using a third int as temporary storage.) Repeat forever. When the head and tail indexes meet, you're done.
Something like this:
int head_index = 0;
int tail_index = array.count;
int temp;
while (true)
{
//Find the next odd number at the front of the array.
while (array[head_index] %2==0) && head_index < tail_index)
head_index++;
//Find the next even number at the end of the array.
while (array[tail_index]%2==1 && head_index < tail_index)
tail_index--;
//If the pointers meet, we're done
if (head_index <= tail_index)
break;
//Swap the items at the current indexes
temp = array[head_index];
array[head_index] = array[tail_index];
array[tail_index] = temp;
}
(Completely untested, and I'm tired, but the basic idea should work)
It's more-or-less C syntax pseudo code.
It should run in O(n) time, with the only extra RAM needed being your 2 indexes and the temporary holding variable.

Even though the question was answered, I'm putting the recursive version of solving this problem here so that people, who are wondering, can see why recursion is a bad approach for this problem.
public static int[] segregate(int[] array, int left) {
int leftIndex = left;
if(left == array.length) {
return array;
}
for(int i = leftIndex + 1; i < array.length; i++) {
if(array[leftIndex] % 2 == 1) {
if(array[i] % 2 == 0) {
int temp = array[leftIndex];
array[leftIndex] = array[i];
array[i] = temp;
}
}
}
return segregate(array, leftIndex + 1);
}
As can be seen from the code, the method will call itself N times. When you consider the fact that the complexity of for loop in the method is O(N), the total complexity of recursion will be O(n*2) which is worse than non-recursive solution.

Related

Best/worst case of finding minimum element in an array

I am trying to find the minimum element in an array, and I've been asked to figure out the number of comparisons needed while using the naïve approach. So the code I've written is:
int findMin(int arr[], int size) {
int comparisons = 0;
int temp = arr[0];
for (int i = 1; i < size; i++) {
comparisons++;
if (arr[i] < temp) {
temp = arr[i];
}
}
return comparisons;
}
Doesn't this require n-1 comparisons in all cases? Because I'll have to check all elements from arr[1] to arr[arr_length-1], and best case/worst case doesn't come into play as I don't know if the element is minimum unless I encounter all the elements of the array atleast once. Thus, it always does n-1 comparisons to get to the minimum element right?
One of my friends says its going to be 2(n-2)+1 worst case and n-1 best case but I don't know how that is? Am I wrong or is something else going on here?
With the unsorted array, since it don't have any information about the order of the unseen element, it have to look at them all, hence the time complexity is n-1.
Your algorithm requires n-1 comparisons in all cases, which means n-1 in the worst case and also n-1 in the best case. There are no optimal inputs or pessimal inputs of your function.
FYI: What is the best, worst and average case running times of an algorithm?

Best and worst case runtimes of my search algorithm (similar to bubble sort)?

So I know this algorithm is pretty simple, but I can't wrap my head around the time complexity of the code. It takes in an array (say 5 numbers) and sorts it in increasing order and in a similar manner to bubble sort (but not quite the same). What are the best and worst case runtimes of this algorithm?
int sort(int arr[1...n]){
while(i <= n){
k = n;
while(k >= i+1){
if (arr[k-1] > arr[k]){
tmp = arr[k-1];
arr[k-1] = arr[k];
arr[k] = tmp;
}
k--;
}
i++;
}
}
My reasoning:
The worst case would be if the array was in reverse sorted order, say [5,4,3,2,1]. I know the outer while loop would be executed n times, but the inner while loop is what throws me off. For each iteration of the outer while, I think the inner while executes i+1 times, so with the array I gave, it would execute the inner while 4,3,2,and then finally 1 time (that's a total of (n-1) executions of the inner while loop)...Putting it together I have n*(n-1), so does that mean worst case is O(n^2)?
The best case is when the array is already sorted, say [1,2,3,4,5].So in that case we would never need to do nay swapping of numbers, and the if statement in the inner while is never executed. But the code seems to loop through everything despite the fact that the array is already sorted. We still go through both while loops which leads me to believe it's still n*(n-1), but that seems off to me. Any help is appreciated.
In the worst case there will be 1+2+3+...(n-1) iterations, so that's n(n-1)/2 => n^2/2 - n/2.
Neglecting the constants, the algorithm is of worst case O(n^2 - n) complexity, which is just O(n^2).
It's no surprise that the code "loops through everything," even when the array is already sorted. You don't tell it not to.
You need to add a sentinel value that tells it stop when the array is already sorted.
In your code, if the internal if statement is never entered during a single pass, then you know that the array is sorted. So what you do is initialize a flag at the start of each iteration of the outer loop. If the if statement is ever entered, then you set the flag. If, the flag is not set at the end of the out loop iteration, then you know that the array is sorted. Here's the code:
int sort(int arr[1...n]){
bool didSwap = true;
while(i <= n && didSwap){
didSwap = false;
k = n;
while(k >= i+1){
if (arr[k-1] > arr[k]){
tmp = arr[k-1];
arr[k-1] = arr[k];
arr[k] = tmp;
didSwap = true;
}
k--;
}
i++;
}
}
That will make your code "early out" when the array is sorted.

Is my implementation of insertion Sort correct?

This is my first question on stack overflow. I have just started my journey in the world of programming through CS50. My code for insertion sort in C is a little different from what the instructor's pseudocode suggested. I just wish to know if the following code is correct and how can I make it better? Thanks alot.
int arr[6] = {23, 42, 4, 16, 8, 15};
for (int i = 1; i < 6; i++) // Iterating over the unsorted portion of array.
{
int element = arr[i]; // This is the first element of the unsorted portion.
int temp = -1;
for(int j = i-1; j >= 0 && element < arr[j]; j--) // Iterating over the unsorted portion of array from right to left.
{
arr[j+1] = arr[j];
temp = j;
}
if(temp != -1) // If temp does not change, the element is already sorted.
{
arr[temp] = element;
}
}
Congrats, your code does work.
The first way to seeing this is putting this code in a function, like main(), and printing every element in order after running the algorithm. If the result is NOT what you expected, then it certainly isn't working, however, the contrary is not true. But if you pass the first try, you should start testing your code against other cases, especially corner cases.
Another helpful option here is using GDB, a debugger that can display the entire array at every step your code takes, especially the one implemented on CS50 IDE, which is actually very pleasing to watch.
Also, HackerRank's challenges on insertion sort might help you out learning this. Other than that, good luck with your course, hope you enjoy!

Grid containing apples

I found this question on a programming forum:
A table composed of N*M cells,each having a certain quantity of apples, is given. you start from the upper-left corner. At each step you can go down or right one cell.Design an algorithm to find the maximum number of apples you can collect ,if you are moving from upper-left corner to bottom-right corner.
I have thought of three different complexities[in terms of time & space]:
Approach 1[quickest]:
for(j=1,i=0;j<column;j++)
apple[i][j]=apple[i][j-1]+apple[i][j];
for(i=1,j=0;i<row;i++)
apple[i][j]=apple[i-1][j]+apple[i][j];
for(i=1;i<row;i++)
{
for(j=1;j<column;j++)
{
if(apple[i][j-1]>=apple[i-1][j])
apple[i][j]=apple[i][j]+apple[i][j-1];
else
apple[i][j]=apple[i][j]+apple[i-1][j];
}
}
printf("\n maximum apple u can pick=%d",apple[row-1][column-1]);
Approach 2:
result is the temporary array having all slots initially 0.
int getMax(int i, int j)
{
if( (i<ROW) && (j<COL) )
{
if( result[i][j] != 0 )
return result[i][j];
else
{
int right = getMax(i, j+1);
int down = getMax(i+1, j);
result[i][j] = ( (right>down) ? right : down )+apples[i][j];
return result[i][j];
}
}
else
return 0;
}
Approach 3[least space used]:
It doesn't use any temporary array.
int getMax(int i, int j)
{
if( (i<M) && (j<N) )
{
int right = getMax(i, j+1);
int down = getMax(i+1, j);
return apples[i][j]+(right>down?right:down);
}
else
return 0;
}
I want to know which is the best way to solve this problem?
There's little difference between approaches 1 and 2, approach 1 is probably a wee bit better since it doesn't need the stack for the recursion that approach 2 uses since that goes backwards.
Approach 3 has exponential time complexity, thus it is much worse than the other two which have complexitx O(rows*columns).
You can make a variant of approach 1 that proceeds along a diagonal to use only O(max{rows,columns}) additional space.
in term of time the solution 1 is the best because there is no recursie function.
the call of recursive function takes time
Improvement to First Approach
Do you really need the temporary array to be N by M?
No.
If the initial 2-d array has N columns, and M rows, we can solve this with a 1-d array of length M.
Method
In your first approach you save all of the subtotals as you go, but you really only need to know the apple-value of the cell to the left and above when you move to the next column. Once you have determined that, you don't look at those previous cells ever again.
The solution then is to write-over the old values when you start on the next column over.
The code will look like the following (I'm not actually a C programmer, so bear with me):
The Code
int getMax()
{
//apple[][] is the original apple array
//N is # of columns of apple[][]
//M is # of rows of apple[][]
//temp[] is initialized to zeroes, and has length M
for (int currentCol = 0; currentCol < N; currentCol++)
{
temp[0] += apple[currentCol][0]; //Nothing above top row
for (int i = 1; i < M; i++)
{
int applesToLeft = temp[i];
int applesAbove = temp[i-1];
if (applesToLeft > applesAbove)
{
temp[i] = applesToLeft + apple[currentCol][i];
}
else
{
temp[i] = applesAbove + apple[currentCol][i];
}
}
}
return temp[M - 1];
}
Note: there isn't any reason to actually store the values of applesToLeft and applesAbove into local variables, and feel free to use the ? : syntax for the assignment.
Also, if there are less columns than rows, you should rotate this so the 1-d array is the shorter length.
Doing it this way is a direct improvement over your first approach, as it saves memory, and plus iterating over the same 1-d array really helps with caching.
I can only think of one reason to use a different approach:
Multi-Threading
To gain the benefits of multi-threading for this problem, your 2nd approach is just about right.
In your second approach you use a memo to store the intermediate results.
If you make your memo thread-safe (by locking or using a lock-free hash-set) , then you can start multiple threads all trying to get the answer for the bottom-right corner.
[// Edit: actually since assigning ints into an array is an atomic operation, I don't think you would need to lock at all ].
Make each call to getMax choose randomly whether to do the left getMax or above getMax first.
This means that each thread works on a different part of the problem and since there is the memo, it won't repeat work a different thread has already done.

Sorting alphabetically in C using strcmp

I am trying to sort records (structs) by their names. And I'm using strcmp to swap to detect the alphabetical order. The swapping works fine, however it doesn't always sort the entire list. It always leaves some records in thier incorrect alphabetic order.
void sort_by_name(){
printf("%d\n", counter);
int i=0, j=0;
patient *temp;
for(;j<=counter;j++){
for(;i<counter-1;i++){
if(strcmp(pRecords[i]->name, pRecords[i+1]->name) > 0){
temp = pRecords[i];
pRecords[i] = pRecords[i+1];
pRecords[i+1]=temp;
}//if loops
}//2nd for loop
}//1st for loop
}
counter-- number of records in the system.
I think your specific problem is that you're not re-initialising i to 0 each time you start the inner loop.
This is a relatively simple bubblesort where the inner loop runs over the list of N items, N times (controlled by the outer loop) to get them sorted. But your inner loop runs over them once then seems to go off elsewhere, beyond the end of the array. That's unlikely to provide useful results :-)
Your more general issue is: why are you not using the language facilities to do this, specifically qsort? If you're trying to educate yourself on sorting, that's fine, but if you just want to sort, there's little point re-inventing the wheel.
For what it's worth, I prefer the following algorithm in bubble sort. It stops early if the list is sorted and it doesn't look at already sorted items:
void sort_by_name(){
int i, didSwap = 1, limit = numitems - 1;
patient *temp;
while (didSwap) {
didSwap = 0;
for (i = 0; i < limit; i++) {
if (strcmp (pRecords[i]->name, pRecords[i+1]->name) > 0) {
temp = pRecords[i];
pRecords[i] = pRecords[i+1];
pRecords[i+1] = temp;
didSwap = 1;
}
}
limit--;
}
}
The didSwap variable controls when to exit. If you traverse the entire unsorted section without swapping then obviously, you're finished. The limit controls that unsorted section and reduces gradually since, after each pass, there's a greater already-sorted section at the end of the list (the higher elements bubble up to the end of the list, one per pass).
I think you are trying to implement bubble sort. The loop count variables seem to be a bit off.
for(;i<counter-1;i++){
should be
for(i=counter-2;i>=j; i--){
You must reset the i after every iteration of the 'j' loop. And work backwards to have the smallest number bubble up to the front.

Resources