Same code but Strange behaviour - c++11

This is my code on implementation of merge sort , it is showing no error at all
and giving no output either :
#include<iostream>
using namespace std;
void merge(int arr[],int l,int m,int r)
{
int i,j,k;
int n1 = m-l+1;
int n2 = r-m;
int L[n1],R[n2];
for(i=0;i<n1;i++)
{
L[i]=arr[i+l];
}
for(j=0;j<n2;j++)
{
R[j]=arr[m+1+j];
}
i=0;
j=0;
k=1;
while(i<n1 && j<n2)
{
if(L[i]<=R[j])
{
arr[k]=L[i];
i++;
}
else
{
arr[k]=R[j];
j++;
}
k++;
}
while(i<n1)
{
arr[k]=L[i];
i++;
k++;
}
while(j<n2)
{
arr[k]=R[j];
j++;
k++;
}
}
void mergeSort(int arr[], int l, int r)
{
if(l < r)
{
int m = l+(r-1)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void printArray(int A[],int size)
{
int i;
for( i=0;i<size;i++)
cout<<A[i]<<" ";
}
int main()
{
int arr[]={12,65,34,78,90,65,34};
int arr_size = sizeof(arr)/sizeof(arr[0]);
cout<<"Given array is \n";
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
cout<<"\nSorted array is \n";
printArray(arr, arr_size);
return 0;
}
now here is the piece of code , which is the problem :
void mergeSort(int arr[], int l, int r)
{
if (l < r)
{
int m = l+(r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
if i replace this mergeSort() code with the above program's mergeSort(),
the program gives output.
but have a look , both mergeSort() codes are same (in program code as well as mentioned mergeSort() code)
link to original code ===> http://cpp.sh/6zdip
link to the code after replacing mergeSort ====> http://cpp.sh/7lfo
this is most strange problem ,i have ever faced.

It's not the same code.
on your original code: int m = l+(r-1)/2;
on the working code: int m = l+(r-l)/2;
the letter L minuscule can look like '1', but it's not.
Now, try one thing: make the spacements of your code consistent (by running clang-format on both codes) then use a diff application to verify the differences on your code and the running one.
It was pretty easy to spot when I did this:
> int m = l + (r - 1) / 2;
> ---
> int m = l + (r - l) / 2;

Related

Please spot the error in this merge sort code

I have provided the code for sorting an array using the merge sort algorithm, I'm unable to find the error, this code is not giving the correctly sorted array as it's output. The function mergesort is called recursively to divide the array till its size is reduced to 1. Then multiple arrays are merged using the merge function.
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int m, int l, int h) {
int n1 = m - l + 1, n2 = h - m;
int t1[n1], t2[n2];
for (int i = 0; i < n1; i++) {
t1[i] = a[i + l];
}
for (int i = 0; i < n2; i++) {
t2[i] = a[i + m + 1];
}
int k = 0, p = 0, r = 0;
while (k < n1 && p < n2) {
if (t1[k] <= t2[p]) {
a[r] = t1[k];
k++;
r++;
} else {
a[r] = t2[p];
p++;
r++;
}
}
while (k < n1) {
a[r] = t1[k];
k++;
r++;
}
while (p < n2) {
a[r] = t2[p];
p++;
r++;
}
}
void mergesort(int a[], int l, int h) {
if (l < h) {
int m = l + (h - l) / 2;
mergesort(a, l, m);
mergesort(a, m + 1, h);
merge(a, m, l, h);
}
}
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
mergesort(a, 0, 4);
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
return 0;
}
The bug in the merge function is r should be initialized to l, not 0. You are not merging the slices into the original position.
Also note that the last loop while (p < n2) in this function is redundant: the remaining elements in the right slice are already in the proper place in the original array.
Here is a modified version:
void merge(int a[], int m, int l, int h) {
int n1 = m - l + 1, n2 = h - m;
int t1[n1], t2[n2];
for (int i = 0; i < n1; i++) {
t1[i] = a[i + l];
}
for (int i = 0; i < n2; i++) {
t2[i] = a[i + m + 1];
}
int k = 0, p = 0, r = l;
while (k < n1 && p < n2) {
if (t1[k] <= t2[p]) {
a[r] = t1[k];
k++;
r++;
} else {
a[r] = t2[p];
p++;
r++;
}
}
while (k < n1) {
a[r] = t1[k];
k++;
r++;
}
}
To further simplify the code, here are some more remarks:
it is less confusing to make use the convention that h be the first index beyond the end of the slice. This way the initial call uses the array length and mergesort can compute the slice length as h - l.
variable name l looks confusingly close to number 1.
the arguments to merge are usually in the order l, m, h, and m is the index of the start of the right slice.
the right slice does not need saving.
using variable length arrays with automatic storage t1[n2] may cause a stack overflow for large arrays.
Here is a modified version:
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int lo, int m, int hi) {
int i, j, k;
int n1 = m - lo;
int t1[n1];
for (i = 0; i < n1; i++) {
t1[i] = a[lo + i];
}
i = 0;
j = m;
k = lo;
while (i < n1 && j < hi) {
if (t1[i] <= a[j]) {
a[k++] = t1[i++];
} else {
a[k++] = a[j++];
}
}
while (i < n1) {
a[k++] = t1[i++];
}
}
void mergesort(int a[], int lo, int hi) {
if (hi - lo >= 2) {
int m = lo + (hi - lo) / 2;
mergesort(a, lo, m);
mergesort(a, m, hi);
merge(a, lo, m, hi);
}
}
int main() {
int a[5] = { 1, 5, 2, 4, 3 };
mergesort(a, 0, 5);
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
cout << "\n";
return 0;
}

Quick Sort 3-way Partitiion

I'm trying to implement the Quick sort algorithm with the 3-way partition technique, using "m1" and "m2" as indexes to delimitate the zone where the elements are equal to the pivot.
Here is my code:
public class Sorting {
private static Random random = new Random();
private static int[] partition3(long[] a, int l, int r) {
long x = a[l];
int m1 = l;
int m2 = l;
for (int i = l + 1; i <= r; i++) {
if (a[i] < x) {
m1++;
m2++;
swap(a, m1, m2);
}
if (a[i] == x) {
m2++;
swap(a, i, m1);
}
}
swap(a, l, m1);
int[] m = {m1, m2};
return m;
}
private static void swap(long[] a, int i, int j) {
long temp = a[i];
a[i] = a[j];
a[j] = temp;
}
private static void randomizedQuickSort(long[] a, int l, int r) {
if (l >= r) {
return;
}
int k = random.nextInt(r - l + 1) + l;
long t = a[l];
a[l] = a[k];
a[k] = t;
int m[] = partition3(a, l, r);
randomizedQuickSort(a, l, m[0] - 1);
randomizedQuickSort(a, m[1] + 1, r);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = scanner.nextLong();
}
randomizedQuickSort(a, 0, n - 1);
for (int i = 0; i < n; i++) {
System.out.print(a[i] + " ");
}
}
}
Most of the times it outputs the right answer to my tests, but sometimes doesn't. Can anyone tell me what I'm doing wrong?
Your code fails cases when you have repeating numbers in a list. For instance, your code fails the test case:
1 2 1 3 1
It will return something different every time due to random number generation, but it won't be the correct answer. This is an issue with your partition3() function, specifically the cases within your for loop, where you decide where to increment and flip. In this case:
if (a[i] < x) {
m1++;
m2++;
swap(a, m1, m2);
}
You are missing a swap that moves the i'th index to the proper place. That swap would look like so:
if (a[i] < x) {
m1++;
m2++;
swap(a, m1, m2);
swap(a, m1, i); //The missing swap.
}
In your other if-condition, you are missing two things. First of all, it should be an else-if, to avoid unintended entering of both if-conditions. Second of all, you swap at the wrong location. You should swap at m2 (the second wall), not at m1. This is because the second wall takes care of values the same as the pivot, not the first. Corrected, your second if-condition would look like so:
else if (a[i] == x) { //Note the addition of the else
m2++;
swap(a, i, m2); //Corrected, now swaps at m2
}
With these corrections, your code seems to work as intended.
It's much more easier if "m1" and "m2" (the two delimiters of the 'equal' zone) start from opposed sides. If the element is less than the pivot, you swap with the left delimiter and if is greater than the pivot, you swap with the right one. Otherwise, if it's equal, we just move the "i" index. It would be something like this:
private static int[] partition3(long[] a, int l, int r) {
long x = a[l];
int m1 = l;
int m2 = r;
int i = l + 1;
while(i <= m2) {
if (a[i] > x) {
swap(a, i, m2);
m2--;
} else if (a[i] < x) {
swap(a, m1, i);
m1++;
i++;
} else {
i++;
}
}
int[] m = {m1, m2};
return m;
}

Count the number of occurences of a key in a sorted array recursively

I was trying to solve this problem recursively http://www.geeksforgeeks.org/count-number-of-occurrences-in-a-sorted-array/.
The code I have till now uses a stupid little hack with static variable. Although this works, it would fail if you call the function repeatedly with different keys(as the static variable would still remember the previous set value).
int FindCount(const vector< int > &A, int l, int r, int B)
{
static int count =0;
// cout<<l<<' '<<r<<endl;
if(l <= r)
{
int mid = (l+r)/2;
// cout<<mid<<endl;
if(A[mid] == B)
{
count++;
FindCount(A, l, mid-1, B);
FindCount(A, mid+1, r, B);
}
else if (A[mid] < B)
{
FindCount(A, mid+1, r, B);
}
else
{
FindCount(A, l, mid-1, B);
}
}
return count;
}
I can figure out how it should work but have a hard time converting that into code. It should be something like this, once you find the particular key then return 1 and the continue to recusively search the left and right of the key.
Could you help me do this recusively without the use of static variable with a cleaner code :)
int FindCount(const vector< int > &A, int l, int r, int B)
{
int count = 0;
if(l <= r)
{
int mid = (l+r)/2;
if(A[mid] == B)
{
count++;
count += FindCount(A, l, mid-1, B);
count += FindCount(A, mid+1, r, B);
}
else if (A[mid] < B)
{
count = FindCount(A, mid+1, r, B);
}
else
{
count = FindCount(A, l, mid-1, B);
}
}
return count;
}
This should work, although it is still a O(n) algorithm, not very efficient.
You yet cast away the return value of all invocations but that at the bottom of the recursion stack (a stack grows upwards); instead of the static count you can just add the return value of the recursions to an automatic local variable count.
The code contains a serious bug: you should use size_t and not int. The result could overflow. Indexers and counts should be size_t - which is a unsigned 32-bit integer on 32-bit platforms and a unsigned 64-bit integer on 64-bit platforms.
u_seem_surprised has a perfectly valid answer. Another way to solve this problem is to use lambdas and capture the count variable:
#include <vector>
#include <functional>
size_t FindCount(const std::vector<int> &A, size_t l, size_t r, int B)
{
using namespace std;
size_t count = 0;
function<void(const vector<int>&, size_t, size_t, int)> impl;
impl = [&count, &impl](const vector<int> &A, size_t l, size_t r, int B)
{
if (l <= r)
{
auto mid = (l + r) / 2;
if (A[mid] == B)
{
count++;
impl(A, l, mid - 1, B);
impl(A, mid + 1, r, B);
}
else if (A[mid] < B)
{
impl(A, mid + 1, r, B);
}
else
{
impl(A, l, mid - 1, B);
}
}
};
impl(A, l, r, B);
return count;
}

Big-O of these two functions

Can someone help me find the Big-O of these two functions:
int sum(int A[], int i, int n) {
if (n == 1)
return A[i];
return sum(A, i, n/2) + sum(A, i + n/2, (n+1)/2);
}
and the 'sort' function of:
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
void swapMin(int A[], const int& index) {
int indexMin = index;
for (int i = index-1; i >= 0; --i)
if (A[i] < A[indexMin])
indexMin = i;
swap(A[index], A[indexMin]);
}
void sort(int A[], int n) {
for (int i = n-1; i >= 0; --i)
swapMin(A, i);
}
I believe the first is O(1) and the second is O(n) but I'm not sure if that is correct.
For the first function, you can do this:
And then you can solve it using generating functions.
For the second one, you may use Sigma notation:

Large values in segment tree for product range queries

I wrote code for firing product range queries on an array.
Note: This question not a duplicate to Multiplication in a range. My problem is something different
I wrote the code for this,
// Program to show segment tree operations like construction, query and update
#include <stdio.h>
#include <math.h>
#define R 1000000000
typedef unsigned long long ull;
int getMid(int s, int e) { return s + (e -s)/2; }
ull getProdUtil(ull *st, int ss, int se, int qs, int qe, int index)
{
if (qs <= ss && qe >= se)
return st[index];
if (se < qs || ss > qe)
return 1;
int mid = getMid(ss, se);
return (getProdUtil(st, ss, mid, qs, qe, 2*index+1) %R *
getProdUtil(st, mid+1, se, qs, qe, 2*index+2) % R )%R;
}
ull getProd(ull *st, int n, int qs, int qe)
{
if (qs < 0 || qe > n-1 || qs > qe)
{
return 0;
}
return getProdUtil(st, 0, n-1, qs, qe, 0) % R;
}
ull constructSTUtil(ull arr[], int ss, int se, ull *st, int si)
{
if (ss == se)
{
st[si] = arr[ss];
return arr[ss];
}
int mid = getMid(ss, se);
ull l = (ull)constructSTUtil(arr, ss, mid, st, si*2+1)%R;
ull r = (ull)constructSTUtil(arr, mid+1, se, st, si*2+2)%R;
st[si] = (l * r) % R;
return st[si];
}
void init_array(ull *st, ull size){
for(ull i=0;i< size;i++){
st[i] = 1;
}
}
ull *constructST(ull arr[], int n)
{
int x = (int)(ceil(log2(n))); //Height of segment tree
int max_size = 2*(int)pow(2, x) - 1; //Maximum size of segment tree
ull *st = new ull[max_size];
init_array(st, max_size);
constructSTUtil(arr, 0, n-1, st, 0);
return st;
}
void print_array(ull *array,int size){
printf("\n");
for(int i=0; i< size;i++){
printf("<%d,%llu> ", i+1,array[i]);
}
}
int main()
{
int n;
scanf("%d",&n);
ull arr[n];
for(int i=0;i<n;i++){
scanf("%llu",&arr[i]);
}
ull *st = constructST(arr, n);
int t;
scanf("%d", &t);
while(t--){
int l,m,r;
scanf("%d %d %d", &l,&r,&m);
ull result = getProd(st, n, l-1, r-1);
printf("%lld\n",result % m);
//int sizes = 100;
//printf("%llu\n",st[0]);
//print_array(st, sizes);
}
return 0;
}
The constraints are,
1 ≤ N ≤ 100,000 (size of array)
1 ≤ Ai ≤ 100 (array elements)
1 ≤ T ≤ 100,000 (number of test cases)
1 ≤ Li ≤ Ri ≤ N (Left and right ranges in query)
1 ≤ Mi ≤ 10<sup>9</sup> (Modulus for each test case. Each test case has to be modulu of this number)
Im pretty sure that R , that I have chosen is failing some test case. I tried R with 1018 as well. But still same problem. Dont know why this is happening?
My question is , is it the problem of R I have chosen or is it the problem of different M being passed in each test case.
Note: Truly not expecting a solution, just expecting a clue
Regards

Resources