void mergeSubArr(int arr[], int lb, int mid, int ub){
int temp[size], i = lb, j = mid, k = 0;
while(i<mid && j<=ub){
if(arr[i] <= arr[j])
temp[k] = arr[i++];
else
temp[k] = arr[j++];
k++;
}
while(i<mid)
temp[k++] = arr[i++];
while(j<=ub)
temp[k++] = arr[j++];
for(k=0;k<size;k++)
arr[k] = temp[k];
}
void mergeArr(int num[], int lb, int ub){
int mid;
if((ub-lb)>1){
mid = (lb+ub)/2;
mergeArr(num, lb, mid);
mergeArr(num, mid+1, ub);
mergeSubArr(num, lb, mid+1, ub);
}
}
when calling the function mergeArr the output is outputting some other elements which are not initially present in the array? I think there is something wrong with the mergeSubArr function please help me out here in finding a solution.
There are basically two things wrong with your algorithm:
You fill the array temp from index 0 on. Later, you need to copy it to arr, but starting at the lower bound. You also shouldn't copy size elements, because you can't be sure that the original array even has size elements. (Thanks, BLUEPIXY, for spotting this one.) You should probably also make sure that size is big enough to hold all elements.
Your upper bound is inclusive. That means that if (ub - lb > 1) catches the case where there are more than two elements. You still have to treat the case where there are two elements, which may be in the wrong order, either by making the above condition ub - lb > 0 or by having an else clause where you swap the elements if they are in the wrong order.
So make these changes:
int temp[size], i = lb, j = mid, k = lb;
Start the temp array from the lower bound.
for(k = lb; k <= ub; k++)
arr[k] = temp[k];
Copy only the subarray in question.
if (ub - lb > 0) ...
Catch the case where there are two elements, too.
On a personal note, I find the mergesort algorithm much easier when it passes subarrays via pointer arithmetic and length. It forgoes much fiddling with offsets.
All are okk. Instead if((ub-lb)>1) Just replace
if((ub-lb)>0)
OR
if(ub > lb)
Related
I need to implement a quicksort algorithm that uses random pivot; I'm working with big matrices, so i can't afford the worst case.
Now, I've found this implementation that works correctly, but it uses as pivot the first element.
I've modified it to fit my scenario (I'm working with Sparse Matrices, and I need to sort the elements by "row index, col index") and this is what I have:
void quicksortSparseMatrix(struct sparsematrix *matrix,int first,int last){
int i, j, pivot, temp_I, temp_J;
double temp_val;
if(first<last){
pivot=first; //(rand() % (last - first + 1)) + first;
i=first;
j=last;
while(i<j){
while(lessEqual(matrix,i, pivot)&&i<last)
i++;
while(greater(matrix,j, pivot))
j--;
if(i<j){
temp_I = matrix->I[i];
temp_J = matrix->J[i];
temp_val = matrix->val[i];
matrix->I[i] = matrix->I[j];
matrix->J[i] = matrix->J[j];
matrix->val[i] = matrix->val[j];
matrix->I[j]=temp_I;
matrix->J[j]=temp_J;
matrix->val[j]=temp_val;
}
}
temp_I = matrix->I[pivot];
temp_J = matrix->J[pivot];
temp_val = matrix->val[pivot];
matrix->I[pivot] = matrix->I[j];
matrix->J[pivot] = matrix->J[j];
matrix->val[pivot] = matrix->val[j];
matrix->I[j]=temp_I;
matrix->J[j]=temp_J;
matrix->val[j]=temp_val;
quicksortSparseMatrix(matrix,first,j-1);
quicksortSparseMatrix(matrix,j+1,last);
}
}
Now, the problem is that some of the matrices i'm working with are almost sorted and the algorithm runs extremely slow. I want to modify my algorithm to make it use random pivot, but if I apply the change you see commented in the code above pivot=(rand() % (last - first + 1)) + first;, the algorithm does not sort the data correctly.
Can anyone help me figure out how to change the algorithm to use a random pivot and sort the data correctly?
EDIT: this is the struct sparsematrix definition, I don't think you need it, but for completeness...
struct sparsematrix {
int M, N, nz;
int *I, *J;
double *val;
};
Pivot should be a value, not an index. The first comparison should be lessthan (not lessthanorequal), which will also eliminate the need for checking for i < last . After swapping, there should be i++ and j-- . The last two lines should be quicksortSparseMatrix(matrix,first,j); and quicksortSparseMatrix(matrix,i,last); , for this variation of Hoare partition scheme. Example code for array:
void QuickSort(int *a, int lo, int hi)
{
int i, j;
int p, t;
if(lo >= hi)
return;
p = a[lo + 1 + (rand() % (hi - lo))];
i = lo;
j = hi;
while (i <= j){
while (a[i] < p)i++;
while (a[j] > p)j--;
if (i > j)
break;
t = a[i];
a[i] = a[j];
a[j] = t;
i++;
j--;
}
QuickSort(a, lo, j);
QuickSort(a, i, hi);
}
A merge sort on an array of indexes to rows of matrix may be faster: more moves of the indexes, but fewer compares of rows of matrix. A second temp array of indexes will be needed for merge sort.
I tried to implement Quicksort. It works fine except when there is a duplicate key, in which case there is an infinite loop and it never terminates. Can you help me understand what I am doing wrong?
// quick sort
void quickSort(int arr[], const unsigned size)
{
// base case
if (size < 2)
return;
int pivot = arr[size / 2];
unsigned L = 0, U = size - 1;
// partitioning
while (L < U) {
while (arr[L] < pivot)
L++;
while (arr[U] > pivot)
U--;
swap(&arr[L], &arr[U]);
}
quickSort(arr, L); // sort left array
quickSort(&arr[U + 1], size - L - 1); // sort right array
}
You have the less than and greater than conditions. But there is no condition for =. This is why it will run an infinite loop. Change them to <= and >=.
I wrote this code. The idea is to split the array into 2 parts and find the number of sub-sequences that satisfy the given condition. Now there can also be a sub-sequence with elements from both subarrays. Hence I wrote the crossub function.
The subarray function is going on an infinite loop (It's continuously printing the debug statement "BBBBBBBB"). I spent some time on this, but I guess I need some help.
Note : New to programming. I know the code is a piece of shit. But I am getting better.
#include <stdio.h>
#include <stdlib.h>
void crossub(int * A,int mid, int start, int end, int lbound, int ubound, int **k)
{
int leftsum = A[mid];
int crossum;
int rightsum = 0;
int i;int j;
for(i = mid -1; i>=0; i--)
{
leftsum = leftsum + A[i];
for(j = mid +1; j <=end; j++)
{
rightsum = rightsum + A[j];
crossum = rightsum + leftsum;
if (lbound <= crossum && crossum <= ubound) k++;
else if(crossum > ubound) break;
}
}
return;
}
void subarray(int * A, int start, int end, int lbound, int ubound, int *count)
{
printf("BBBBBBBBB ");
if(start == end)
{
if(lbound <= A[start] && A[start] <= ubound)
{
count++;
}
return;
}
int **k; int mid;
k = &count;
while (start <= end)
{
mid = (start + end)/2;
subarray(A, start, mid,lbound,ubound,count);
subarray(A, mid +1, end,lbound,ubound,count);
crossub(A, mid, start, end, lbound,ubound,k);
}
return;
}
int numRange(int* A, int n, int lbound, int ubound)
{
// printf("AAAAAAAAAAA");
int p = 0;
int *count;
count = &p;
subarray(A, 0, n-1,lbound,ubound, count);
return p;
}
int main()
{
int A[] = {30, 5,1,0,2, 15,20,25};
int n = sizeof(A)/sizeof(A[0]);
printf("%d", n);
int lbound = 6; int ubound = 8;
int k = numRange(A, n,lbound, ubound);
printf("%d ", k);
return 0;
}
I'm not sure that recursion is relevant here. The way here is to always have a range and check its sum. Initial range should contain the single first item (range can be defined via start and end indexes), initial value for sum should be equal to value of . Further processing is:
If your sum is less than you're looking for, expand range incrementing its end index and adding value of new item to current value of range's sum;
If your sum is greater than you're looking for, reduce range incrementing its start index and substracting value of excluded item from range's sum;
If your sum is OK for you, return it.
Dealing with ranges:
If your sum is less than you're looking for, and you're unable to increment its end index because it points to the last item in array you're looking through, you may return a result that says no range is satisfying your requirements;
If your sum is greater than you're looking for, and you're unable to increment its start index because it points to the last item in array, you may also return same "no answer" result.
I'm sure there is no efficient way of dealing with ranges using "divide and conquer" strategy.
Regarding your infinite loop, the issue is in the subarray function, namely:
while (start <= end)
{
mid = (start + end)/2;
subarray(A, start, mid,lbound,ubound,count);
subarray(A, mid +1, end,lbound,ubound,count);
crossub(A, mid, start, end, lbound,ubound,k);
}
As you can see, this is going to keep going forever, because you never change the values of start/end, so you keep calling subarray on the same section.
Although, as already stated by the first answer, this might not be the best way, but you can remove the while loop and see if it works, even if it might not be the best solution.
Today, an interviewer asked me this question. My immediate response was that we could simply do a linear search, comparing the current element with the previous element in the array. He then asked me how the problem could be solved in less-than-linear time.
Assumptions
The array is sorted
There is only one duplicate
The array is only populated with numbers [0, n], where n is the length of the array.
Example array: [0,1,2,3,4,5,6,7,8,8,9]
I attempted to come up with a divide-and-conquer algorithm to solve this, but I'm not confident that it was the right answer. Does anyone have any ideas?
Can be done in O(log N) with a modified binary search:
Start in the middle of the array: If array[idx] < idx the duplicate is to the left, otherwise to the right. Rinse and repeat.
If no number is missing from the array, as in the example, it's doable in O(log n) with a binary search. If a[i] < i, the duplicate is before i, otherwise it's after i.
If there is one number absent and one duplicate, we still know that if a[i] < i the duplicate must be before i and if a[i] > i, the absent number must be before i and the duplicate after. However, if a[i] == i, we don't know if missing number and duplicate are both before i or both after i. I don't see a way for a sublinear algorithm in that case.
I attempted to come up with a divide-and-conquer algorithm to solve this, but I'm not confident that it was the right answer.
Sure, you could do a binary search.
If arr[i/2] >= i/2 then the duplicate is located in the upper half of the array, otherwise it is located in the lower half.
while (lower != upper)
mid = (lower + upper) / 2
if (arr[mid] >= mid)
lower = mid
else
upper = mid-1
Since the array between lower and upper is halved in each iteration, the algorithm runs in O(log n).
ideone.com demo in Java
Difference between sum of given array elements and sum of 0 to n-1 natural numbers gives you the duplicated element.
Sum of 0 to n-1 elements is (N * N-1)/2
example array is [0,1,2,3,4,5,6,7,8,8,9]
sum of 0 to 9 natural numbers is : 45
sum of given array elements : 53
53-45 = 8 Which is the duplicated element
#include <bits/stdc++.h>
using namespace std;
int find_only_repeating_element(int arr[] , int n){
int low = 0;
int high = n-1;
while(low <= high){
int mid = low + (high - low)/2;
if(arr[mid] == arr[mid + 1] || arr[mid] == arr[mid - 1]){
return arr[mid];
}
if(arr[mid] < mid + 1){
high = mid - 2;
}else{
low = mid + 1;
}
}
return -1;
}
int main(int argc, char const *argv[])
{
int n , *arr;
cin >> n;
arr = new int[n];
for(int i = 0 ; i < n ; i++){
cin >> arr[i];
}
cout << find_only_repeating_element(arr , n) << endl;
return 0;
}
How about that? (recursion style)
public static int DuplicateBinaryFind(int[] arr, int left, int right)
{
int dup =0;
if(left==right)
{
dup = left;
}
else
{
int middle = (left+right)\2;
if(arr[middle]<middle)
{
dup = DuplicateBinaryFind(arr,left, middle-1);
}
else
{
dup = DuplicateBinaryFind(arr, middle+1, right);
}
}
return dup;
}
The example array is a little bit different from your question. Since n is the length of array and there are one and only duplicate in array, the value of each element in array should be in [0,n-1].
If that is true, then this question is the same one with How to find a duplicate element in an array of shuffled consecutive integers?
The following code should find the duplicate in O(n) time and O(1) space.
public static int findOnlyDuplicateFromArray(int[] a, boolean startWithZero){
int xor = 0;
int offset = 1;
for(int i=0; i < a.length; i++){
if(startWithZero)
xor = xor ^ (a[i] + offset) ^ i;
else
xor = xor ^ a[i] ^ i;
}
if(startWithZero)
xor = xor - offset;
return xor;
}
I am writing a simple merge sort function to sort based on a given compar function:
void merge(int left, int mid, int right, int(*compar)(const void *, const void *))
{
// sublist sizes
int left_size = mid - left + 1;
int right_size = right - mid;
// counts
int i, j, k;
// create left and right arrays
B *left_list = (B*) malloc(left_size*sizeof(B));
B *right_list = (B*) malloc(right_size*sizeof(B));
// copy sublists, could be done with memcpy()?
for (i = 0; i < left_size; i++)
left_list[i] = list[left + i];
for (j = 0; j < right_size; j++)
right_list[j] = list[mid + j + 1];
// reset counts
i = 0; j = 0;
for (k = left; k <= right; k++)
{
if (j == right_size)
list[k] = left_list[i++];
else if (i == left_size)
list[k] = right_list[j++];
// here we call the given comparision function
else if (compar(&left_list[i], &right_list[j]) < 0)
list[k] = left_list[i++];
else
list[k] = right_list[j++];
}
}
void sort(int left, int right, int(*compar)(const void *, const void *))
{
if (left < right)
{
// find the pivot point
int mid = (left + right) / 2;
// recursive step
sort(left, mid, compar);
sort(mid + 1, right, compar);
// merge resulting sublists
merge(left, mid, right, compar);
}
}
I am then calling this several times on the same list array using different comparison functions. I am finding that the sort is stable for the first call, but then after that I see elements are swapped even though they are equal.
Can anyone suggest the reason for this behaviour?
I'm not sure if this will do it but try changing this line:
compar(&left_list[i], &right_list[j]) < 0
to this:
compar(&left_list[i], &right_list[j]) <= 0
This will make it so that if they are already equal it does the first action which will (hopefully) preserve the stability rather than moving things around.
This is just a guess though.
I think you got your sizes wrong
int left_size = mid - left;
And, as pointed by arasmussen, you need to give preference to the left list in order to mantain stability
compar(&left_list[i], &right_list[j]) <= 0
In adition to all of this, you are not calling free after malloc-ing the helper lists. This will not make the algorithm return incorrect results but will cause your program's memory use to grow irreversably everytime you call the sort function.