I have studied the theory of the merge sort but don't have any idea of how to implement it in C++. My question is, merge sort creates arrays in recursion. But when implementing, how do we create arrays in runtime? or what is the general approach for this?
Thanks.
To answer the question: Creating dynamically sized arrays at run-time is done using std::vector<T>. Ideally, you'd get your input using one of these. If not, it is easy to convert them. For example, you could create two arrays like this:
template <typename T>
void merge_sort(std::vector<T>& array) {
if (1 < array.size()) {
std::vector<T> array1(array.begin(), array.begin() + array.size() / 2);
merge_sort(array1);
std::vector<T> array2(array.begin() + array.size() / 2, array.end());
merge_sort(array2);
merge(array, array1, array2);
}
}
However, allocating dynamic arrays is relatively slow and generally should be avoided when possible. For merge sort you can just sort subsequences of the original array and in-place merge them. It seems, std::inplace_merge() asks for bidirectional iterators.
Based on the code here: http://cplusplus.happycodings.com/algorithms/code17.html
// Merge Sort
#include <iostream>
using namespace std;
int a[50];
void merge(int,int,int);
void merge_sort(int low,int high)
{
int mid;
if(low<high)
{
mid = low + (high-low)/2; //This avoids overflow when low, high are too large
merge_sort(low,mid);
merge_sort(mid+1,high);
merge(low,mid,high);
}
}
void merge(int low,int mid,int high)
{
int h,i,j,b[50],k;
h=low;
i=low;
j=mid+1;
while((h<=mid)&&(j<=high))
{
if(a[h]<=a[j])
{
b[i]=a[h];
h++;
}
else
{
b[i]=a[j];
j++;
}
i++;
}
if(h>mid)
{
for(k=j;k<=high;k++)
{
b[i]=a[k];
i++;
}
}
else
{
for(k=h;k<=mid;k++)
{
b[i]=a[k];
i++;
}
}
for(k=low;k<=high;k++) a[k]=b[k];
}
int main()
{
int num,i;
cout<<"*******************************************************************
*************"<<endl;
cout<<" MERGE SORT PROGRAM
"<<endl;
cout<<"*******************************************************************
*************"<<endl;
cout<<endl<<endl;
cout<<"Please Enter THE NUMBER OF ELEMENTS you want to sort [THEN
PRESS
ENTER]:"<<endl;
cin>>num;
cout<<endl;
cout<<"Now, Please Enter the ( "<< num <<" ) numbers (ELEMENTS) [THEN
PRESS ENTER]:"<<endl;
for(i=1;i<=num;i++)
{
cin>>a[i] ;
}
merge_sort(1,num);
cout<<endl;
cout<<"So, the sorted list (using MERGE SORT) will be :"<<endl;
cout<<endl<<endl;
for(i=1;i<=num;i++)
cout<<a[i]<<" ";
cout<<endl<<endl<<endl<<endl;
return 1;
}
I have completed #DietmarKühl s way of merge sort. Hope it helps all.
template <typename T>
void merge(vector<T>& array, vector<T>& array1, vector<T>& array2) {
array.clear();
int i, j, k;
for( i = 0, j = 0, k = 0; i < array1.size() && j < array2.size(); k++){
if(array1.at(i) <= array2.at(j)){
array.push_back(array1.at(i));
i++;
}else if(array1.at(i) > array2.at(j)){
array.push_back(array2.at(j));
j++;
}
k++;
}
while(i < array1.size()){
array.push_back(array1.at(i));
i++;
}
while(j < array2.size()){
array.push_back(array2.at(j));
j++;
}
}
template <typename T>
void merge_sort(std::vector<T>& array) {
if (1 < array.size()) {
std::vector<T> array1(array.begin(), array.begin() + array.size() / 2);
merge_sort(array1);
std::vector<T> array2(array.begin() + array.size() / 2, array.end());
merge_sort(array2);
merge(array, array1, array2);
}
}
I've rearranged the selected answer, used pointers for arrays and user input for number count is not pre-defined.
#include <iostream>
using namespace std;
void merge(int*, int*, int, int, int);
void mergesort(int *a, int*b, int start, int end) {
int halfpoint;
if (start < end) {
halfpoint = (start + end) / 2;
mergesort(a, b, start, halfpoint);
mergesort(a, b, halfpoint + 1, end);
merge(a, b, start, halfpoint, end);
}
}
void merge(int *a, int *b, int start, int halfpoint, int end) {
int h, i, j, k;
h = start;
i = start;
j = halfpoint + 1;
while ((h <= halfpoint) && (j <= end)) {
if (a[h] <= a[j]) {
b[i] = a[h];
h++;
} else {
b[i] = a[j];
j++;
}
i++;
}
if (h > halfpoint) {
for (k = j; k <= end; k++) {
b[i] = a[k];
i++;
}
} else {
for (k = h; k <= halfpoint; k++) {
b[i] = a[k];
i++;
}
}
// Write the final sorted array to our original one
for (k = start; k <= end; k++) {
a[k] = b[k];
}
}
int main(int argc, char** argv) {
int num;
cout << "How many numbers do you want to sort: ";
cin >> num;
int a[num];
int b[num];
for (int i = 0; i < num; i++) {
cout << (i + 1) << ": ";
cin >> a[i];
}
// Start merge sort
mergesort(a, b, 0, num - 1);
// Print the sorted array
cout << endl;
for (int i = 0; i < num; i++) {
cout << a[i] << " ";
}
cout << endl;
return 0;
}
#include <iostream>
using namespace std;
template <class T>
void merge_sort(T array[],int beg, int end){
if (beg==end){
return;
}
int mid = (beg+end)/2;
merge_sort(array,beg,mid);
merge_sort(array,mid+1,end);
int i=beg,j=mid+1;
int l=end-beg+1;
T *temp = new T [l];
for (int k=0;k<l;k++){
if (j>end || (i<=mid && array[i]<array[j])){
temp[k]=array[i];
i++;
}
else{
temp[k]=array[j];
j++;
}
}
for (int k=0,i=beg;k<l;k++,i++){
array[i]=temp[k];
}
delete temp;
}
int main() {
float array[] = {1000.5,1.2,3.4,2,9,4,3,2.3,0,-5};
int l = sizeof(array)/sizeof(array[0]);
merge_sort(array,0,l-1);
cout << "Result:\n";
for (int k=0;k<l;k++){
cout << array[k] << endl;
}
return 0;
}
The problem with merge sort is the merge, if you don't actually need to implement the merge, then it is pretty simple (for a vector of ints):
#include <algorithm>
#include <vector>
using namespace std;
typedef vector<int>::iterator iter;
void mergesort(iter b, iter e) {
if (e -b > 1) {
iter m = b + (e -b) / 2;
mergesort(b, m);
mergesort(m, e);
inplace_merge(b, m, e);
}
}
I know this question has already been answered, but I decided to add my two cents. Here is code for a merge sort that only uses additional space in the merge operation (and that additional space is temporary space which will be destroyed when the stack is popped). In fact, you will see in this code that there is not usage of heap operations (no declaring new anywhere).
Hope this helps.
void merge(int *arr, int size1, int size2) {
int temp[size1+size2];
int ptr1=0, ptr2=0;
int *arr1 = arr, *arr2 = arr+size1;
while (ptr1+ptr2 < size1+size2) {
if (ptr1 < size1 && arr1[ptr1] <= arr2[ptr2] || ptr1 < size1 && ptr2 >= size2)
temp[ptr1+ptr2] = arr1[ptr1++];
if (ptr2 < size2 && arr2[ptr2] < arr1[ptr1] || ptr2 < size2 && ptr1 >= size1)
temp[ptr1+ptr2] = arr2[ptr2++];
}
for (int i=0; i < size1+size2; i++)
arr[i] = temp[i];
}
void mergeSort(int *arr, int size) {
if (size == 1)
return;
int size1 = size/2, size2 = size-size1;
mergeSort(arr, size1);
mergeSort(arr+size1, size2);
merge(arr, size1, size2);
}
int main(int argc, char** argv) {
int num;
cout << "How many numbers do you want to sort: ";
cin >> num;
int a[num];
for (int i = 0; i < num; i++) {
cout << (i + 1) << ": ";
cin >> a[i];
}
// Start merge sort
mergeSort(a, num);
// Print the sorted array
cout << endl;
for (int i = 0; i < num; i++) {
cout << a[i] << " ";
}
cout << endl;
return 0;
}
Here's a way to implement it, using just arrays.
#include <iostream>
using namespace std;
//The merge function
void merge(int a[], int startIndex, int endIndex)
{
int size = (endIndex - startIndex) + 1;
int *b = new int [size]();
int i = startIndex;
int mid = (startIndex + endIndex)/2;
int k = 0;
int j = mid + 1;
while (k < size)
{
if((i<=mid) && (a[i] < a[j]))
{
b[k++] = a[i++];
}
else
{
b[k++] = a[j++];
}
}
for(k=0; k < size; k++)
{
a[startIndex+k] = b[k];
}
delete []b;
}
//The recursive merge sort function
void merge_sort(int iArray[], int startIndex, int endIndex)
{
int midIndex;
//Check for base case
if (startIndex >= endIndex)
{
return;
}
//First, divide in half
midIndex = (startIndex + endIndex)/2;
//First recursive call
merge_sort(iArray, startIndex, midIndex);
//Second recursive call
merge_sort(iArray, midIndex+1, endIndex);
merge(iArray, startIndex, endIndex);
}
//The main function
int main(int argc, char *argv[])
{
int iArray[10] = {2,5,6,4,7,2,8,3,9,10};
merge_sort(iArray, 0, 9);
//Print the sorted array
for(int i=0; i < 10; i++)
{
cout << iArray[i] << endl;
}
return 0;
}
This would be easy to understand:
#include <iostream>
using namespace std;
void Merge(int *a, int *L, int *R, int p, int q)
{
int i, j=0, k=0;
for(i=0; i<p+q; i++)
{
if(j==p) //When array L is empty
{
*(a+i) = *(R+k);
k++;
}
else if(k==q) //When array R is empty
{
*(a+i) = *(L+j);
j++;
}
else if(*(L+j) < *(R+k)) //When element in L is smaller than element in R
{
*(a+i) = *(L+j);
j++;
}
else //When element in R is smaller or equal to element in L
{
*(a+i) = *(R+k);
k++;
}
}
}
void MergeSort(int *a, int len)
{
int i, j;
if(len > 1)
{
int p = len/2 + len%2; //length of first array
int q = len/2; //length of second array
int L[p]; //first array
int R[q]; //second array
for(i=0; i<p; i++)
{
L[i] = *(a+i); //inserting elements in first array
}
for(i=0; i<q; i++)
{
R[i] = *(a+p+i); //inserting elements in second array
}
MergeSort(&L[0], p);
MergeSort(&R[0], q);
Merge(a, &L[0], &R[0], p, q); //Merge arrays L and R into A
}
else
{
return; //if array only have one element just return
}
}
int main()
{
int i, n;
int a[100000];
cout<<"Enter numbers to sort. When you are done, enter -1\n";
i=0;
while(true)
{
cin>>n;
if(n==-1)
{
break;
}
else
{
a[i] = n;
i++;
}
}
int len = i;
MergeSort(&a[0], len);
for(i=0; i<len; i++)
{
cout<<a[i]<<" ";
}
return 0;
}
This is my version (simple and easy):
uses memory only twice the size of original array.
[ a is the left array ] [ b is the right array ] [ c used to merge a and b ] [ p is counter for c ]
void MergeSort(int list[], int size)
{
int blockSize = 1, p;
int *a, *b;
int *c = new int[size];
do
{
for (int k = 0; k < size; k += (blockSize * 2))
{
a = &list[k];
b = &list[k + blockSize];
p = 0;
for (int i = 0, j = 0; i < blockSize || j < blockSize;)
{
if ((j < blockSize) && ((k + j + blockSize) >= size))
{
++j;
}
else if ((i < blockSize) && ((k + i) >= size))
{
++i;
}
else if (i >= blockSize)
{
c[p++] = b[j++];
}
else if (j >= blockSize)
{
c[p++] = a[i++];
}
else if (a[i] >= b[j])
{
c[p++] = b[j++];
}
else if (a[i] < b[j])
{
c[p++] = a[i++];
}
}
for (int i = 0; i < p; i++)
{
a[i] = c[i];
}
}
blockSize *= 2;
} while (blockSize < size);
}
Related
I have written code below but I get warning C6001: using uninitialized memory
in merge function before last line at arr[z] = S[z] , I have used dynamic array because VS-2022 don't support VLA.
I have seen different types of merge algorithms but I want this specific code to run because I am using an instruction that I have to follow for my project!
#include <iostream>
void merge(int*, int, int, int);
void merge_sort(int*, int, int);
void printArrey(int*, int);
int main()
{
int arr[9] = { 9,8,7,6,5,4,3,2,1 };
printArrey(arr, 9);
merge_sort(arr, 0, 8);
printArrey(arr, 9);
system("pause");
}
void merge(int* arr, int start, int mid, int end)
{
int i = start, j = mid+1, k = start;
int* S = new int[end+1];
while (i <= mid && j <= end)
{
if (arr[i] < arr[j])
{
S[k] = arr[i];
i++;
}
else
{
S[k] = arr[j];
j++;
}
k++;
}
if (i > mid)
{
for (; j <= end; k++, j++)
{
S[k] = arr[j];
}
}
else if (j > end)
{
for (; i <= mid; k++, i++)
{
S[k] = arr[i];
}
}
for (int z=0; z < k; z++)
{ arr[z] = S[z]; }
delete[] S;
}
void merge_sort(int* arr, int start, int end)
{
if (start < end)
{
int mid = start+ (end - start) / 2;
merge_sort(arr, start, mid);
merge_sort(arr, mid+1, end);
merge(arr, start, mid, end);
}
}
void printArrey(int* arr, int size)
{
for(int i = 0; i < size; i++)
{
std::cout << arr[i] << "\t";
}
std::cout << "\n";
}
I had to use
while(start<=end)
{
arr[start] = S[start];
start++;
}
instead of
for (int z=0; z < k; z++)
{ arr[z] = S[z]; }
tnx to anyone who helped!
I am trying to implement a hybrid of mergesort and insertion sort. When the subarray size reaches below a threshold, it should switch to insertion sort.
However I tried with a bunch of array of different length and different threshold amount, and most of the time there isn't any noticeable difference, other than just a 2-3 lesser comparisons. I was told that switching to insertion sort for smaller sized array would help greatly.
Am I doing it wrong?
#include <iostream>
int comparisons = 0;
int swaps = 0;
void mergesort(int x[], int l, int r);
void insertionSort(int x[],int start, int end);
int main() {
int x[] = {9,5,1,4,3,10,29,69,5,9,11,19,21,69,0,2,3,4,5,11,111,96,25,32,21,2,12,3,52,55,23,32,15,15,14,13,9,5,1,4,3,10,29,69,5,9,11,19,21,69,0,2,3,4,5,11,111,96,25,32,21,2,12,3,52,55,23,32,15,15,14,13,};
// insertionSort(x,10);
int sizeX= sizeof(x)/sizeof(x[0]) ;
mergesort(x, 0, sizeX-1);
for(int i =0;i<sizeX;i++){
std::cout << x[i] << " ";
}
// std::cout << "\nSWAPS: " << swaps;
std::cout << "\nCOMPARISONS: " << comparisons;
}
void insertionSort(int arr[], int start,int end)
{
int i, key, j;
for (i = start +1 ; i < end; i++)
{
key = arr[i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && arr[j] > key)
{
comparisons++;
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
void insertionSort2(int x[],int start, int end){
for(int i =start; i < end;i++){
for (int j= i; j!= 0;j--){
comparisons++;
if(x[j] < x[j-1]){
int temp = x[j-1];
x[j-1] = x[j];
x[j] = temp;
swaps++;
}
else{
break;
}
}
}
}
void mergesort(int x[], int l, int r) {
if (l >= r)
return;
int mid = (l + r) / 2;
if(r - l < 3){
insertionSort(x, l,r+1);
}else{
mergesort(x, l, mid);
mergesort(x, mid + 1, r);
int i = l;
int j = mid + 1;
int k = 0;
int tmp[r - l + 1];
while (i <= mid && j <= r) {
comparisons++;
if (x[i] >= x[j]) {
tmp[k] = x[j];
j++;
} else {
tmp[k] = x[i];
i++;
}
swaps++;
k++;
}
while (i <= mid) {
tmp[k] = x[i];
i++;
k++;
}
while (j <= r) {
tmp[k] = x[j];
j++;
k++;
}
for (i = 0; i < k; i++) x[l + i] = tmp[i];
}
}
I have a 2D vector of doubles, and I need to sort it using quicksort. However, when I print all the steps, it seems it's not working the way it should.
My vector is a global variable, I try to sort each row and print the current vector after each iteration.
vector<vector<double>> vect;
int rows, cols;
void Print2DArray() {
for (int i = 0;i < vect.size();++i) {
for (int j = 0;j < vect[i].size();++j) {
cout << vect[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
int partition(int low, int high, int ind) {
double pivot = vect[ind][high];
int i = low;
double tmp;
for (int j = low;j <= high - 1;++j) {
if (vect[ind][j] <= pivot) {
tmp = vect[ind][j];
vect[ind][j] = vect[ind][i];
vect[ind][i] = tmp;
i++;
}
}
tmp = vect[ind][high];
vect[ind][high] = vect[ind][i];
vect[ind][i] = tmp;
Print2DArray();
return i;
}
void Sort(int low, int high, int ind) {
if (low < high) {
int pi = partition(low, high, ind);
Sort(low, pi - 1, ind);
Sort(pi + 1, high, ind);
}
}
void TwoDimSort() {
for (int i = 0;i < vect.size();++i) {
Sort(0, vect[i].size() - 1, i);
}
Print2DArray();
}
int main() {
rows = 3;
cols = 9;
srand((unsigned)time(NULL));
for (int i = 0;i < rows;++i) {
vector<double> tmp;
for (int j = 0;j < cols;++j) {
double num = (rand() % 100) * 0.9;
if (num > 0.0)
tmp.push_back(num);
}
vect.push_back(tmp);
}
Print2DArray();
TwoDimSort();
Print2DArray();
getchar();
return 0;
}
I think you could just use the following implementation.
void swap(double array[], int i, int j) {
auto h = array[i];
array[i] = array[j];
array[j] = h;
}
int partition(double array[], int low, int high) {
// Assign the last element to the pivot element
int pivot = array[high];
// Index of smaller element
int lowIndex = (low - 1);
// Iterate from lowest to highest element
for (int j = low; j <= high - 1; j++) {
// Swap elements if j-th element is smaller than the pivot element
if (array[j] < pivot || array[j] == pivot) {
lowIndex++;
swap(array, lowIndex, j);
}
}
swap(array, lowIndex + 1, high);
return (lowIndex + 1);
}
double *quickSort(double array[], int lo, int hi) {
if (lo < hi) {
int pi = partition(array, lo, hi);
// Recursively sort smaller half of the list
quickSort(array, lo, pi - 1);
// Recursively sort higher half of the list
quickSort(array, pi + 1, hi);
}
// Return sorted list
return array;
}
Global variables are bad practice in this case!
void Print2DArray(std::vector<std::vector<double>> vect) {
for (int i = 0;i < vect.size();++i) {
for (int j = 0;j < vect.at(i).size();++j) {
std::cout << vecta.at(i).at(j) << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
void TwoDimSort(std::vector<std::vector<double>> vect) {
for (int i = 0; i < vect.size(); ++i) {
// Print the sorted row
print(quickSort(0, vect.at(i).size() - 1, i));
}
}
void print(std::vector<double> v){
for( auto d : v){
std::cout << d << " ";
}
std::cout << std::endl;
}
You should consider using this implementation of the print-function an quickSort. Subsequently I would recommend you to use vector::at instead of [], due to range checking reasons.
I want to compare two int arrays and find if they are the same and if they are not i want to find the min and the max number that exist in one but not in the other. I use this code in c++ but seems to run into a segmentation fault 11. I would be grateful if someone points out the mistake to me.I would like to see better solutions if there are any.
+ I did the mergesort for time limit of 1 second.
#include <iostream>
using namespace std;
void merge(int *a,int s,int e)
{
int mid = (s+e)/2;
int i = s;
int j = mid+1;
int k = s;
int temp[100];
while(i<=mid && j<=e)
{
if(a[i] < a[j])
{
temp[k++] = a[i++];
}
else
{
temp[k++] = a[j++];
}
}
while(i<=mid)
{
temp[k++] = a[i++];
}
while(j<=e)
{
temp[k++] = a[j++];
}
for(int i=s;i<=e;i++)
{
a[i] = temp[i];
}
}
void mergeSort(int a[],int s,int e)
{
if(s>=e)
{
return;
}
int mid = (s+e)/2;
mergeSort(a,s,mid);
mergeSort(a,mid+1,e);
merge(a,s,e);
}
int min_array (int array1[],int n1)
{
int min = array1[0];
for(int i=1;i<n1;i++)
if(array1[i] < min)
min = array1[i];
return min;
}
int max_array (int array2[],int n2)
{
int max = array2[0];
for(int i=1;i<n2;i++)
if(array2[i] > max)
max = array2[i];
return max;
}
void check_same(int a[], int b[], int n)
{
bool check = true;
int check1 = 2, check2 = 2, counter1 = 0, counter2 = 0, i, j;
int pos1[n], pos2[n];
mergeSort(a, 0, n);
mergeSort(b, 0, n);
for(i=0; i<n; i++)
{
if (a[i] != b[i])
check = false;
for(j=0; j<n; j++)
{
if (a[i] != b[j])
check1 = 0;
else if (a[i] == b[j])
check1 = 1;
else if (a[j] != b[i])
check2 = 0;
else if (a[j] == b[i])
check2 = 1;
if (check1 == 1 && check2 == 1)
break;
}
if (check1 == 0)
pos1[counter1++] = i;
else if (check2 == 0)
pos2[counter2++] = i;
}
int differents[counter1 + counter2];
if (counter1 < counter2)
{
for (i=0; i<counter1; i++)
differents[i] = a[pos1[i]];
for (i=counter1; i<counter2; i++)
differents[i] = b[pos2[counter2 - i]];
}
else
{
for (i=0; i<counter2; i++)
differents[i] = b[pos2[i]];
for (i=counter2; i<counter1; i++)
differents[i] = a[pos1[counter1 - i]];
}
if (check)
cout << "yes\n";
else if (check == false)
cout << "no " << min_array(differents, counter1+counter2)<< " " << max_array(differents, counter1+counter2) << endl;
}
int main()
{
int N, i;
cin >> N;
int A[50000], B[50000];
for (i=0;i<N;i++)
cin >> A[i];
for (i=0;i<N;i++)
cin >> B[i];
check_same(A, B, N);
}
Your code is not standard C++, the line int pos1[n], pos2[n]; in check_same is invalid because n is not a compile time constant - VLAs are only allowed in C.
You could make use of the standard library for all of that:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
void check_same(int a[], int b[], int n) {
std::sort(a, a + n);
std::sort(b, b + n);
if(std::equal(a, a + n, b)) {
std::cout << "yes\n";
} else {
std::vector<int> elements_not_in_both;
std::set_symmetric_difference(a, a + n,
b, b + n,
std::back_inserter(elements_not_in_both));
auto [min, max] = std::minmax_element(elements_not_in_both.cbegin(),
elements_not_in_both.cend());
std::cout << "no " << *min << " " << *max << '\n';
}
}
int main()
{
int N;
std::cin >> N;
int A[50000], B[50000];
for (int i=0; i<N; i++)
std::cin >> A[i];
for (int i=0; i<N; i++)
std::cin >> B[i];
check_same(A, B, N);
}
Live demo.
An even better solution is to not use C-style arrays either, then you don't allocate way too much stack space for small input arrays and you can't have too little space when someone decides to run this on more than 50000 elements:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
void check_same(std::vector<int>& a, std::vector<int>& b) {
std::sort(a.begin(), a.end());
std::sort(b.begin(), b.end());
if(a == b) {
std::cout << "yes\n";
} else {
std::vector<int> elements_not_in_both;
std::set_symmetric_difference(a.cbegin(), a.cend(),
b.cbegin(), b.cend(),
std::back_inserter(elements_not_in_both));
auto [min, max] = std::minmax_element(elements_not_in_both.cbegin(),
elements_not_in_both.cend());
std::cout << "no " << *min << " " << *max << '\n';
}
}
int main()
{
int N;
std::cin >> N;
std::vector<int> a, b;
a.reserve(N);
b.reserve(N);
std::copy_n(std::istream_iterator<int>(std::cin), N, std::back_inserter(a));
std::copy_n(std::istream_iterator<int>(std::cin), N, std::back_inserter(b));
check_same(a, b);
}
Please check out for these points for solving segmentation fault issue:
merge function
1) Is this statement int k = s; correct? Shouldn't it be int k = 0;
2) Is this allocation int temp[100]; OK? Or Should it be int temp[e - s + 1];
3) Is this statement a[i] = temp[i]; correct? Shouldn't it be a[i] = temp[i - s];
4) Do you need to have base condition s < e or something? i.e. Handling the case when s == e.
check_same function
1) Is this call mergeSort(a, 0, n); correct? Shouldn't it be mergeSort(a, 0, n - 1);
As far as better approach is concerned, it can be solved in O(n) using hashing.
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
void check_same(int a[], int b[], int n) {
int minNotInA, maxNotInA, minNotInB, maxNotInB;
bool elementMissingInA = false, elementMissingInB = false;
{
unordered_set<int> elementsInB;
for (int i = 0; i < n; i++) {
elementsInB.insert(b[i]);
}
for (int i = 0; i < n; i++) {
if (elementsInB.find(a[i]) == elementsInB.end()) {
if (!elementMissingInA) {
elementMissingInA = true;
minNotInB = maxNotInB = a[i];
} else {
if (minNotInB > a[i]) {
minNotInB = a[i];
} else if (maxNotInB < a[i]) {
maxNotInB = a[i];
}
}
}
}
}
if (elementMissingInA) {
unordered_set<int> elementsInA;
for (int i = 0; i < n; i++) {
elementsInA.insert(a[i]);
}
for (int i = 0; i < n; i++) {
if (elementsInA.find(b[i]) == elementsInA.end()) {
if (!elementMissingInB) {
elementMissingInB = true;
minNotInA = maxNotInA = b[i];
} else {
if (minNotInA > b[i]) {
minNotInA = b[i];
} else if (maxNotInA < b[i]) {
maxNotInA = b[i];
}
}
}
}
}
if (elementMissingInA and elementMissingInB) {
cout << "no " << min(minNotInA, minNotInB) << " " << max(maxNotInA, maxNotInB) << "\n";
} else {
cout << "yes\n";
}
}
int main()
{
int N;
std::cin >> N;
int A[50000], B[50000];
for (int i=0; i<N; i++)
std::cin >> A[i];
for (int i=0; i<N; i++)
std::cin >> B[i];
check_same(A, B, N);
return 0;
}
Thank all of you for your interest and your help.
Because i am not used to those kinds of libraries you use and i dont want to study them at the moment(i am just in the first semester of my ece class) i corrected my code(both improved it and fixed the segmentation fault 11)
You can take a look right here.
#include <iostream>
using namespace std;
void merge(int *a, int s, int e)
{
int mid = (s + e) / 2;
int i = s;
int j = mid + 1;
int k = s;
int temp[50000];
while (i <= mid && j <= e)
{
if (a[i] < a[j])
{
temp[k++] = a[i++];
}
else
{
temp[k++] = a[j++];
}
}
while (i <= mid)
{
temp[k++] = a[i++];
}
while (j <= e)
{
temp[k++] = a[j++];
}
for (int i = s; i <= e; i++)
{
a[i] = temp[i];
}
}
void mergeSort(int a[], int s, int e)
{
if (s >= e)
{
return;
}
int mid = (s + e) / 2;
mergeSort(a, s, mid);
mergeSort(a, mid + 1, e);
merge(a, s, e);
}
int min_array(int array1[], int n1)
{
int min = array1[0];
for (int i = 1; i<n1; i++)
if (array1[i] < min)
min = array1[i];
return min;
}
int max_array(int array2[], int n2)
{
int max = array2[0];
for (int i = 1; i<n2; i++)
if (array2[i] > max)
max = array2[i];
return max;
}
void check_same(int a[], int b[], int n)
{
int differents[50000];
int counter1 = 0, counter2 = 0;
int i = 0, j = 0;
while (i < n && j < n)
{
if (a[i] < b[j])
{
differents[counter1++ + counter2] = a[i];
i++;
}
else if (b[j] < a[i])
{
differents[counter2++ + counter1] = b[j];
j++;
}
else
{
i++;
j++;
}
}
if (counter1 == 0 && counter2 == 0)
cout << "yes\n";
else
cout << "no " << min_array(differents, counter1 + counter2) << " " << max_array(differents, counter1 + counter2) << endl;
}
int main()
{
int A[50000], B[50000];
int N, i;
cin >> N;
for (i = 0; i<N; i++)
cin >> A[i];
for (i = 0; i<N; i++)
cin >> B[i];
mergeSort(A, 0, N-1);
mergeSort(B, 0, N-1);
check_same(A, B, N);
return 0;
}
I try to implement the merge sort algorithm and I get a segmentation fault. Why? The error seems to be in the MergeSort function. The merge sort function (on the 2nd call) when should check only an array of 4 numbers (the length should be 4) shows the length = 27. Why? (tested on an array with 8 elements)
#include<iostream>
using namespace std;
int n, A[1000];
void citire(int lungime) {
for (int i = 0; i < lungime; i++) cin >> A[i];
}
void afisare(int lungime) {
for (int i = 0; i < lungime; i++)
cout << A[i] << " ";
cout << '\n';
}
int lungime(int A[]) {
int i = 0;
while (A[i]) i++;
return i;
}
void Merge(int L[], int R[], int A[]) {
int nL = lungime(L);
int nR = lungime(R);
int i = 0, j = 0, k = 0;
while (i < nL && j < nR) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
k++;
}
while (i < nL) {
A[k] = L[i];
i++;
k++;
}
while (j < nR) {
A[k] = R[j];
j++;
k++;
}
}
void MergeSort(int A[]) {
int n1 = lungime(A);
if (n1 < 2) return;
else
{
int mid = (int)n1 / 2;
int L[mid];
int R[n - mid];
for (int i = 0; i < mid; i++)
L[i] = A[i];
for (int i = mid; i < n; i++)
R[i - mid] = A[i];
MergeSort(L);
MergeSort(R);
Merge(L, R, A);
}
}
int main() {
cin >> n;
citire(n);
MergeSort(A);
afisare(n);
return 0;
}
Changes made in this example. A[], L[], R[] are allocated using new. A[] is passed as a parameter. L[] and R[] are allocated in Merge(). Size and/or indices passed as parameters, and lungime() is no longer used to get size. Other changes noted in comments.
#include<iostream>
using namespace std;
void citire(int A[], int lungime) { // A is parameter
for (int i = 0; i < lungime; i++) cin >> A[i];
}
void afisare(int A[], int lungime) { // A is parameter
for (int i = 0; i < lungime; i++)
cout << A[i] << " ";
cout << '\n';
}
// A, low, mid, end are parameters
// L and R allocated here
void Merge(int A[], int low, int mid, int end) {
int sizeL = mid-low;
int sizeR = end-mid;
int *L = new int[sizeL];
int *R = new int[sizeR];
for(int i = 0; i < sizeL; i++)
L[i] = A[low+i]; // A[low+i]
for(int i = 0; i < sizeR; i++)
R[i] = A[mid+i]; // A[mid+i]
int i = 0, j = 0, k = low; // k = low
while (i < sizeL && j < sizeR) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
k++;
}
while (i < sizeL) {
A[k] = L[i];
i++;
k++;
}
while (j < sizeR) {
A[k] = R[j];
j++;
k++;
}
delete[] R;
delete[] L;
}
// A, low, end are parameters
void MergeSort(int A[], int low, int end) {
int sizeA = end - low;
if(sizeA < 2)
return;
int mid = low + (sizeA / 2); // mid = low + ...
MergeSort(A, low, mid);
MergeSort(A, mid, end);
Merge(A, low, mid, end);
}
int main() {
int n;
cin >> n;
int *A = new int[n]; // A is allocated
citire(A, n); // A, n are parameters
MergeSort(A, 0, n); // A, 0, n are parameters
afisare(A, n); // A, n are parameters
delete[] A;
return 0;
}
"The lungime function is the length of the string and this function works good. I've tested it on different arrays".
Well, this is purely accidental; uninitialized memory can contain zeros, and provide the array terminator by accident.
If you want to keep the current design, you should:
initialize A to zeros
make sure that there are no more than 999 elements in the input stream,
that no element has the value zero, as zero is reserved, and used as terminator, and
define L and R (in MergeSort) one element longer, and initialize the last element to zero.
Unless there are overwhelming reasons for a "roll your own" sort solution, you might have a look at prefab sort support. The vector class in C++ offers just that.