Stack overflow in merge sort - c++

I have homework assignment to implement merge sort in C++ via recursion. I'm not really good at recursion and what follows is the code I implemented, but it gives a stackoverflow error.
Kindly tell me what I am doing wrong. EDITED VERSION
#include<iostream>
using namespace std;
void divide(int A[], int n);
void sort();
int main(){
int A[4]={2,3,0,5};
divide(A, 4);
for(int i =0 ;i<4;i++)
cout<<A[i]<<endl;
getchar();
}
void divide(int A[], int n){
if(n<=2 && n>=1){
for(int i=0; i<n; i++)
if(A[i]>A[i+1]){
int temp=A[i];
A[i]= A[i+1];
A[i+1]=temp;
}
}
else{
divide(A, n/2);
divide(A,(n/2)+1 );
}
}
In the code above, n is the number of elements to sort and A is the array I'm sorting.

Calling the below code with
divide(A, 1);
Should illustrate the problem
void divide(int A[], int n){
if(n==2){ // first time n==1 so no, further calls are n==0 so also no.
for(int i=0; i<2; i++)
if(A[i]>A[i+1]){
int temp=A[i];
A[i]= A[i+1];
}
} else{
divide(A, n/2); // for both n==1 and n== 0 => n==0, calls divide(A, 0)
divide(A,(n/2)+1 ); // calls divide(A, 1) always
}
}
So the program will forever call divide(A, 0) until you run out of memory.
To stop this eternal recursion you need a correct stop condition
if (n<=2) {
// correct code for swapping 1 or 2 elements
} else
You could also check for incorrect values of n, which is 0, negative and larger than length of A.
Lets say you have A[]= {1,2,3} so you call
divide(A, 3);
Now in the else part of the program you need to split up A in to parts, N/2 elements and the rest.
divide(A, n/2);
in our example this gives n/2 = 3/2 = 1 so
divide(A, 1);
and starting in the element just after the n/2'th element
divide(A+(n/2), n-(n/2));
the first element is at A[0], so the remaining start at A[1] and contains n-(n/2)=3-(3/2)=3-1=2 elements.
And now the first if, it looks like a bubble-sort, but fails as it address an element beyond the end of the array.
if(n<=2 && n>=1){
for(int i=0; i<n; i++)
if(A[i]>A[i+1]) {
A[i+1] is beyond the end of the array for i=1 and n=2, n=2 => 2 elements at address A[0] and A[1] so A[i+1]=A[2] which is not part of the array A with length 2.
for(int i=0; i<n-1; i++)
solves that and also takes care of the case with n=1, which means the array contains only one element, which by definition is already sorted.
Now if the algorithm was called divide-sort you would be finished, but you still are missing the merge part.

You're still missing a merge. Merging is going to need a second temp array, I'll call it T and assume it's passed from main:
void divide(int A[], int T[], int n){
if(n < 2)
return;
if(n==2){
// ... swap A[0], A[1] if needed (the existing code is ok)
return;
}
divide(A, T, n/2); // recursively divide "left" half
divide(A+(n/2), T+(n/2), n-(n/2)); // recursively divide "right" half
merge(A, T, n/2, n) // merge the two halves
}

It might be simpler to assume that a partition 0 or 1 element is already sorted. Thus, it is enough to put as stop condition
if (n < 2)
return;

Related

is it wrong to start an array from 1?

I need to solve a c++ problem but something doesn't work and i don't know why.
N numbers are given, divided in k sequences. I need to find out which sequences are equal, knowing that k divides n.
is the problem with some values as an example:
Here is the problem with some values as an example. (it's in romanian)
I tried something like this:
#include <bits/stdc++.h>
using namespace std;
bool compare(int a[], int b[], int n)
{
for(int i=1;i<=n;i++)
if(a[i]!=b[i])
return false;
return true;
}
int main()
{
int n, k;
int i, j, secv;
cin>>n>>k;
int flag=1, v[n];
for(i=1;i<=n;i++)
cin>>v[i];
secv=n/k;
for(i=1;i<k && flag==1;i++)
for(j=i+1; j<=k && flag==1; j++)
if(compare(v+i*secv, v+j*secv, secv)==true)
{
cout<<i<<" "<<j;
flag=0;
}
if(flag==1) cout<<"NU";
return 0;
}
If your array is of size k and you are iterating the first element at index 1 then there are two problems:
Your array will only be able to save k-1 elements because in memory an array's first element is at index 0.
Some of the default array functions like begin and size will include 0 index so it might produce unexpected results.
How an array is saved in memeory
An array name is just a placeholder to the continuous memory reference. So if you's starting your array with 1 then you're skipping through the first index.
The best practice is to start an array with index 0.

Runtime error: reference binding to null pointer of type 'int' (stl_vector.h) while dealing with leetcode test cases

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1043:9
was the remainder of the error message.
I have been working to solve the Merge 2 sorted arrays problem (https://leetcode.com/explore/learn/card/fun-with-arrays/525/inserting-items-into-an-array/3253/) for the past hour, using the vector insert function as below:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int j=0;
if(nums1.empty() || nums1.size()==1){
nums1.push_back(nums2[0]);
return;
}
if(nums2.empty()){
return;
}
for(int i=0; i<(m+n); i++){
if(j<n){
if(nums1[i]<nums2[j] && nums1[i+1] >= nums2[j]){
nums1.insert(nums1.begin()+i+1, nums2[j]);
j++;
}
if(nums1[i]<nums2[j] && nums1[i+1]==0){
nums1.insert(nums1.begin()+i+1, nums2[j]);
j++;
}
}
cout << j;
}
int size = nums1.size()-1;
if(nums1.size()>1){
int resiz = m+n;
nums1.resize(resiz);
}
return;
}
};
I have got to the right solution using this. I have to resize at the end to get rid of the trailing 0s since the insert() method increases the vector size each time.
The problem lies in the test case
[1] // contents of array 1
1 // size of vct 1
[] // contents of array 2
0 // size of vct 2
Of course there may be better ways to solve the problem (and I'd appreciate those suggestions), but I'd like to understand what's causing this, since I have explicitly tried to deal with these edge cases in code.
Your solution
The only edge case is m=0 which should easily be handled by setting nums1=nums2. Aside from that, there are a few logic bugs presented in your code. I have put comments besides the lines I changed.
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int j=0;
if(m==0){ //edge case
nums1 = nums2;
return;
}
constexpr int IMPOSSIBLE = int(1e9+1);
for (int i=m; i<n+m; i++) {
// initialize it to an "impossible" value instead of 0 which could be a valid value!
nums1[i]=IMPOSSIBLE;
}
for(; j<n; j++){ // handle element in nums2 smaller than nums[0] first
if(nums2[j]<=nums1[j]){
nums1.insert(nums1.begin()+j,nums2[j]);
} else {
break;
}
}
for(int i=0; i<(m+n); i++){
if(j<n){
if(nums1[i]<=nums2[j] && i+1<int(nums1.size()) && nums1[i+1] >= nums2[j]){
// The correct logic should be nums1[i]<=nums2[j](e.g. nums1=[1,0,0],n=1,nums2=[2,2],m=2)
nums1.insert(nums1.begin()+i+1, nums2[j]);
j++;
} else if(nums1[i]<=nums2[j] && i+1<int(nums1.size()) && nums1[i+1]==IMPOSSIBLE){
/*
1. The correct logic should be nums1[i] <=nums2[j],
but since IMPOSSIBLE is initialized to the largest value possible,
either < and <= will work here.
2. You must use elseif here, otherwise j may be incremented!
3. 0 does not mean empty cause it could be the real value in nums1[i+1]
*/
nums1.insert(nums1.begin()+i+1, nums2[j]);
j++;
}
}
}
int size = nums1.size()-1;
if(nums1.size()>1){
int resiz = m+n;
nums1.resize(resiz);
}
return;
}
};
Suggestions
Merging two sorted arrays is a very well-known and standard problem. The canonical way is to use two pointers. It will be much cleaner and I highly advise you to read about it.
An even cleaner approach is to use std::merge provided by C++ STL which achieves exactly the same purpose, although it might be a bit... cheaty for your purpose? (I assume you are learning algorithms)
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
vector<int> nums3;
nums3.reserve(n+m);
std::merge(nums1.begin(), nums1.begin()+m, nums2.begin(), nums2.begin(), std::back_inserter(nums3));
nums1=nums3;
return;
}
};
Both solutions above takes O(n+m) time, while your solution is O((n+m)*m), as std::vector::insert takes O(n+m) time

Using recursion in bubble sort

Hello everyone I am starting to learn Data structures and Algorithms and implemented bubble sort myself after learning the concept. Following is the code I have written with my understanding but the problem is it runs for only one cycle and does not sort recursively.
For example:
{ 5,1,4,2,8} is sorted one time -> {1,4,2,5,8,}
What can be the problem?
vector<int> bubble_sort(vector<int> vec){
int temp = 0;
for(int i = 0; i < vec.size()-1; i++){
temp = vec.at(i+1); // holds the adjacent element.
// the following loop swaps the adjacent elements if the previous one is big
if(vec.at(i) > vec.at(i+1)){
vec.at(i+1) = vec.at(i);
vec.at(i) = temp;
}
temp = 0;
}
for(int i = 0; i < vec.size()-1; i++){
if(vec.at(i) > vec.at(i+1)){
bubble_sort(vec);
}
}
return vec;
}
Your function takes a vector<int> vector by copy, hence after first swaps only this copy is send to recursively sort.
Just add & to your function parameter: vector<int> bubble_sort(vector<int> &vec) and it should work
If you want to implement recursion fully and do not want to use for loop in the code, then follow this example. It will be helpful.
#include <iostream>
using namespace std;
/* Function to print an array */
void printArray(int arr[], int n)
{
for (int i=0; i <= n; i++)
cout<<arr[i];
}
void bubble_sort_recursive(int arr[], int j, int n) {
// base case
if (n==0 || j>n){
return;
}
// single pass has been completed and the higher element moved to right for that subarray
// now call the recursive function by keeping aside the already sorted positioned element
//i.e next pass wil start from this call
if (j == n){
bubble_sort_recursive(arr,0,n-1);
}
// swap consecutive 2 elements - main basic of bubble sort
if (arr[j]>arr[j+1]){
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] =t;
}
// go forward for next element of a single pass
bubble_sort_recursive(arr,j+1,n);
}
int main() {
int arr[] = {5,4,3,2,1};
// get the length of array
int n = sizeof(arr)/sizeof(arr[0]);
// call from 0 to len-1 as index starts from 0
bubble_sort_recursive(arr,0,n-1);
// print the sorted array
cout<<"Sorted array:"<<endl;
printArray(arr, n-1);
}

Sorting array with BubbleSort

l changed my code but still cant figure out why it wont sort array...bubble sort only moves all elements one place to the right in my program instead of sorting array...l tired bsort and ssort and both do same thing shift elements for 1 position
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void bsort(int n,int a[])
{
int i,j,k;
for(i=0;i<n-1;i++)
{
for(j=0;j<n-1;j++)
{
if(a[j]>a[j+1]);
{
k=a[j+1];
a[j+1]=a[j];
a[j]=k;
}
}
}
}
int main()
{
int i,j,k,m,n;
srand(time(0));
printf("Unesi broj clanova niza:");
scanf("%d",&n);
int a[n];
printf("Niz za sortiranje je:\n");
for(int i=0;i<n;i++) //Generisanje niza
{
a[i]=rand()%(81);
}
for(int i=0;i<n;i++)
{
printf("%3d",a[i]);
}
bsort(n,a);
printf("\n\nSortirani niz je:\n");
for(i=0;i<n;i++)
{
printf("%3d",a[i]);
}
}
There are several problems with your bubble sort implementation.
First, this line:
if (a[j] > a[j + 1]); {
is incorrect. The semi-colon terminates the conditional. As a result, the following block executes on every iteration of the inner loop and you end up unconditionally swapping a[j] and a[j+1] for every value of j. This means you're performing a nonsensical rearrangement of the array.
Second, you're not dealing correctly with edge cases in the inner loop. When j == 19, you access a[j+1], which is a[20], which is beyond the end of the array. You thus import garbage data into your array.
Lastly, even after correcting the above, your implementation is needlessly inefficient, in that your inner loop goes through the entire array on each iteration of the outer loop, which it doesn't have to. Hint: Try to think about how the initialization or termination condition of the inner loop could depend on i.
Update (after the OP's rewrite): You only addressed the second issue.
int main() {
int a[20];
srand(time(0));
// array values initialization
for (int i = 0; i < 19; i++) {
a[i] = rand() % (81);
}
// array sorting
bsort(a);
// array printing
for (int i = 0; i < 19; i++) {
printf("%3d", a[i]);
}
}

How to sort an array in C++ in a specific way

I want somehow sort an array, so that it looks like -
a[0]>=a[1]<=a[2]>=a[3]<=a[4]
I don't know where to start.
Any suggestion would be appreciated!
Sort the entire array (Choose any sort algorithm you wish to). Then take each pair from the beginning and swap the elements in the pair
2,4,1,5,6,3,7,9,8,10
Sorted to : 1,2,3,4,5,6,7,8,9,10
Pair and swap : (2,1),(4,3),(6,5),(8,7),(10,9)
result : 2,1,4,3,6,5,8,7,10,9
Here's the code, obviously you can alter the array length and numbers to meet your specifications.
#include <iostream>
#include <algorithm>
using namespace std;
void special_Sort(int *array, int size){
//doesn't return a value, changes the values inside the array
int temp;
//for swapping purposes
sort(array, array+size);
//sorts the array in ascending order
for(int i=0; i<size; i=i+2){
temp=array[i];
array[i]=array[i+1];
array[i+1]=temp;
}
//array is now sorted
}
int main(){
// array declaration, call the function, etc...
int array[10]={2,4,1,5,6,3,7,9,8,10};
int *pointer;
pointer=&array[0];
special_Sort(pointer, 10);
// if you want to print the result
// for(int i =0; i<10; i++)
// cout<<array[i]<<" ";
return 0;
}
I'm assuming here that the relations are inclusive (in the sense that they continue to the end of the line - a[0]>=max(a[1],a[2],...), and a[1]<=min(a[2],a[3],..) and so on). Otherwise this isn't uniquely defined, as {5,4,3,2,1} can get sorted for example into {5,1,4,3,2} or {3,2,5,1,4}.
So, assuming this is the case, it's easily solved by sorting the entire array in descending order, then just interleave them -
a[0], a[n-1], a[1], a[n-2], ...
and so on. Just loop with two indices, one starting from the beginning and one from the end, or use something like this -
for (i=0; i<n/2; i++) {
result[i*2] = sorted[i];
result[i*2+1] = sorted[n-i];
}
if (n%2)
result[n-1] = sorted[n/2]
If you are only sorting it in a way that you want values to rise and fall arbitrarily, you can achieve this by checking values in your array and swapping elements if they do not satisfy the constraints of your sort.
Don't have a compiler on me at the moment and you'd have to implement the swap but something like this could work:
for(i=0; i < a.length(); i++){
//If index is even
if(i%2 == 0){
if(a[i] < a[i+1]){
swap(a[i], a[i+1]);
}
} else { ///If index is odd
if(a[i]>a[i+1]){
swap(a[i], a[i+1];
}
}
}
I don't disagree with the other answers posted here so you will have to find what you need depending on the relation of the even and odd indexed elements.
Steps taken:
1) generate some random array
2) sort array
3) switch elements as needed with alternate <=, >= comparisons
Here's the code that does that: (disregard the random generator, its just an easy way to generate an array)
#define sizeArr 50
int main(void)
{
int array[sizeArr];
int i, temp;
for(i=0;i<sizeArr;i++)
{
array[i]=randomGenerator(1, 1000);
Sleep(2);//force clock tick for new srand() to be effective in rand() generator
}
//sort array
qsort(array, sizeArr, sizeof(int), cmpfunc);
//pick the first non repeat 90th percent and print
for(i=0;i<sizeArr-1;i++)
{
if(i%2==0)//alternate between >= && <=
{
if(array[i+1] >= array[i])
{
temp = array[i+1];
array[i+1]=array[i];
array[i]=temp;
}
}
else
{
if(array[i+1] <= array[i])
{
temp = array[i+1];
array[i+1]=array[i];
array[i]=temp;
}
}
}
getchar();
return 0;
}
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int randomGenerator(int min, int max)
{
int random=0, trying=0;
trying = 1;
srand(clock());
while(trying)
{
random = (rand()/32767.0)*(max+1);
(random >= min) ? (trying = 0) : (trying = 1);
}
return random;
}