I am working on a quicksort algorithm implementation in c++ and I have not been able to get it to work as it should. I have researched several sources and my code looks flawless, but the array is not sorting as it should.
Here is my code:
#include <iostream>
using namespace std;
void quicksort(int[],int, int);
int partition(int[], int, int);
int main()
{
int a[] = {5, 1, 9, 3, 8, 4, 1, 2, 6, 7};
for (int i = 0; i < 10; i++)
{
cout << a[i] << " ";
}
cout << endl;
quicksort(a, 0, 9);
for (int i = 0; i < 10; i++)
{
cout << a[i] << " ";
}
return 0;
}
void quicksort(int a[], int p, int r)
{
if (p < r)
{
int q = partition(a, p, r);
quicksort(a, p, q - 1);
quicksort(a, q + 1, r);
}
}
int partition(int a[], int p, int r)
{
int x = a[r];
int i = (p - 1);
for (int j = p; j <= r-1; j++)
{
if (a[j] <= x)
{
i++;
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
int tmp = a[i+1];
a[i+1] = a[r];
a[r] = a[tmp];
return (i + 1);
}
When I run this code the following is displayed:
5 1 9 3 8 4 1 2 6 7
1 1 2 4 4 4 6 7 7 7
I am not sure what I am doing wrong here. Thanks for your help.
In the second to last line of your partition function you should have:
a[r] = tmp;
instead of:
a[r] = a[tmp];
You are overwriting parts of your array with other members instead of completing the third step of your swap.
Related
I am new to programming, and I have been learning about Merge Sort Algorithm, I wrote the following code:
#include <iostream>
using namespace std;
void Merge(int *arr1, int i, int m, int n, int j)
{
int sizeOfNewArray = j - i + 1;
int sizeOfFirstArray = m - i + 1;
int sizeOfSecondArray = j - n + 1;
int *finalArray = new int[sizeOfNewArray];
int *k = &finalArray[i];
int *ptr1 = &arr1[i];
int *ptr2 = &arr1[n];
while (i < sizeOfFirstArray && j < sizeOfSecondArray)
{
if (*ptr1 >= *ptr2)
{
*k = *ptr1;
i++;
k++;
}
else if (*ptr1 < *ptr2)
{
*k = *ptr2;
j++;
k++;
}
}
while (i < sizeOfFirstArray)
{
*k = *ptr1;
i++;
k++;
}
while (j < sizeOfSecondArray)
{
*k = *ptr2;
j++;
k++;
}
}
void MergeSort(int *arr1, int i, int j)
{
if (i != j)
{ //i represnts first index of array, j represents last index of array
int m = (i + j) / 2;
MergeSort(arr1, i, m);
MergeSort(arr1, m + 1, j);
Merge(arr1, i, m, m + 1, j);
}
if (i == j)
{
return;
}
}
int main()
{
int arr[] = {8, 6, 7, 1, 2, 4, 3, 5};
MergeSort(arr, 0, 7);
for (int i = 0; i < 8; i++)
{
cout << arr[i] << endl;
}
return 0;
}
According to me, this program should return the sorted array 1,2,3,4,5,6,7,8. However,on executing this code, it prints
8
6
7
1
2
4
3
5
I have tried debugging the code, but I am not able to find out what the error is. Can someone please have a look at the code, and tell me where is the error?
Apologies in advance for any silly error and thanks for taking out your time and concern.
Merge merges into the finalArray, which has nothing to do with arr1. Once Merge returns, finalArray ceases to exist (leaking memory), and arr1 remains untouched.
Before return, copy finalArray back to arr1, and delete[] it.
I wrote the below code for merge sort but it's not working, And I am unable to find out problem!
Every time the output becomes same as input, I think that problem may occur due to vector reference.
I think mergeSort is not creating a new vector for sub array. But I am still confused.
input vector: 5, 4, 3, 2, 1
output: 5, 4, 3, 2, 1
Req output: 1, 2, 3, 4, 5
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int> &la, vector<int> &ra, vector<int> &A) {
int i = 0, j = 0, k = 0;
// overwriting A using its solved sub arrays i.e la, ra
while (i < la.size() && j < ra.size()) {
if (la[i] <= ra[j]) {
A[k] = la[i];
i++;
k++;
} else {
A[k] = ra[j];
j++;
k++;
}
}
// if any subarray left then
while (i < la.size()) {
A[k] = la[i];
k++;
i++;
}
while (j < ra.size()) {
A[k] = ra[j];
k++;
j++;
}
}
mergeSort function:
void mergeSort(vector<int> &A) {
if (A.size() < 2)
return;
int len = A.size();
vector<int> la, ra;
for (int i = 0; i < len / 2; i++)
la.push_back(A[i]);
for (int i = len / 2; i < len; i++)
ra.push_back(A[i]);
// dividing the proble into subproblem
mergeSort(la);
mergeSort(ra);
// merging the solved subproblem
merge(la, ra, A);
}
Driver function:
int main(void) {
int arr[] = { 5, 4, 3, 2, 1 };
vector<int> A(arr, arr + 5);
for (int i = 0; i < A.size(); i++)
cout << A[i] << " ";
cout << endl;
mergeSort(A);
for (int i = 0; i < A.size(); i++)
cout << A[i] << " ";
return 0;
}
The code posted does not seem to have a problem.
Executing it produces the expected output: 1 2 3 4 5, so there is something else going on that could cause your observations: you might be running an executable produced by a previous or at least different version of the code.
Having Segmentation Fault on the following code of counting inversions in an array.
#include <iostream>
#include <limits.h>
using namespace std;
int merge(int *a, int p, int q, int r);
int mergesort(int *a, int p, int r) {
if (p < r) {
int q = (p + r) / 2;
//Dividing the array in two.
int l = mergesort(a, p, q);
int r = mergesort(a, q + 1, r);
int cross = merge(a, p, q, r);
return (l + r + cross);
} else
return 0;
}
This was the mergesort function supposed to divide the array. Doesn't seem to have an error here.
int merge(int *a, int p, int q, int r) {
int inv_count =0;
int n1 = q - p + 1, n2 = r - q;
int L[n1 + 1], R[n2 + 1];
//Two subarrays with last elements as inf.
L[n1] = INT_MAX; R[n2] = INT_MAX;
for (int i = p, j = 0; j < n1; i++, j++) L[j] = a[i];//copy left
for (int i = q + 1, j = 0; j < n2; i++, j++) R[j] = a[i];//copy right
int i = 0, j = 0, k = p;//merge and count
while (k <= r) {
if (L[i] <= R[j]) {
a[k++] = L[i];
i++;
} else {
a[k++] = R[j];
inv_count += n2 - j + 1;
j++;
}
}
return inv_count;
}
The problem maybe seems to have in the above function where I have declared the L and the R array.
int main() {
//code
int n; cin >> n;
int a[n];
for (int i = 0; i < n; i++) cin >> a[i];
cout << mergesort(a, 0, n - 1);
return 0;
}
Example input: 5 5 4 3 2 1 shows Seg Fault.
In mergesort, you have a shadowing problem:
int r = mergesort(a,q+1,r);
^
The r argument passed isn't the r declared in the function, it's the r you just declared. That's undefined behavior.
By "print debugging" merge with the code:
int merge(int *a, int p, int q, int r) {
int inv_count = 0;
int n1 = q - p + 1, n2 = r - q;
std::cout << "merge(a, " << p << ", " << q << ", " << r << ')'<< std::endl;
std::cout << "\tsize of L: " << (n1 + 1) << std::endl;
std::cout << "\tsize of R: " << (n2 + 1) << std::endl;
(...)
I got the output:
merge(a, 0, 0, 0)
size of L: 2
size of R: 1
merge(a, 0, 1, 0)
size of L: 3
size of R: 0
merge(a, 0, 2, 0)
size of L: 4
size of R: -1
The segfault happens when you try to create an array with negative size. Notice the r parameter passed to merge, it's because of that first problem.
There are multiple problems in the code:
int r = mergesort(a, q + 1, r); redefines r and passes an uninitialized value to mergesort instead of the argument r. Use a different variable name such as:
int nr = mergesort(a, q + 1, r);
L[n1] = INT_MAX; R[n2] = INT_MAX; using sentinel values to avoid testing the index values in the merge phase is a common but nefarious example in some textbooks. The algorithm will fail if the array contains entries with the value INT_MAX, which is possible with the main() function provided. Don't use this silly approach and test the index values.
cout << mergesort(a, 0, n - 1); Passing the index to the last element of the slice leads to cumbersome code with non-intuitive + 1 and - 1 adjustments. Furthermore it does not allow passing empty slices. Passing the index of the first excluded element is more idiomatic in C and C++ and simplifies the code.
int q = (p + r) / 2; This expression can overflow and produce an incorrect value for q. It should be written: int q = p + (r - p) / 2;
index values should have type size_t.
Here is a modified version for small values of n:
#include <iostream>
using namespace std;
size_t merge(int *a, size_t p, size_t q, size_t r) {
size_t inv_count = 0;
size_t n1 = q - p, n2 = r - q;
int L[n1], R[n2];
for (size_t i = 0; i < n1; i++) L[i] = a[p + i];
for (size_t i = 0; i < n2; i++) R[i] = a[q + i];
size_t i = 0, j = 0, k = p; //merge and count
while (k <= r) {
if (i < n1 && (j == n2 || L[i] <= R[j])) {
a[k++] = L[i];
i++;
} else {
a[k++] = R[j];
inv_count += n2 - j + 1;
j++;
}
}
return inv_count;
}
size_t mergesort(int *a, size_t p, size_t r) {
if (r - p > 1) {
size_t q = p + (r - p) / 2;
// Dividing the array in two.
size_t nl = mergesort(a, p, q);
size_t nr = mergesort(a, q, r);
size_t cross = merge(a, p, q, r);
return nl + nr + cross;
} else {
return 0;
}
}
int main() {
size_t n; cin >> n;
int a[n];
for (size_t i = 0; i < n; i++) cin >> a[i];
cout << mergesort(a, 0, n);
return 0;
}
I made a quicksort in C++ but it doesn't work well. For example, if I have an array of {5, 3, 4, 6, 7}, the outcome will be {0, 3, 4, 5, 6}. I can't find the reason since I used the same method in Pascal before and that worked perfectly.
#include <iostream>
using namespace std;
void qsort(int (&ary)[10000], int l, int r){
int i = l, j = r, mid = ary[(l + r) / 2];
while (i <= j){
while (ary[i] < mid) i ++;
while (ary[j] > mid) j --;
if (i <= j){
int temp = ary[i];
ary[i] = ary[j];
ary[j] = temp;
i ++; j --;
}
}
if (i < r) qsort(ary, i, r);
if (l < j) qsort(ary, l, j);
}
int main(){
int n;
int a[10000];
cin >> n;
for (int i = 0; i < n; i ++){
cin >> a[i];
}
qsort(a, 0, n);
for (int i = 0; i < n; i ++){
cout << a[i] << ' ';
}
return 0;
}
line 27: should be
qsort(a, 0, n-1);
Here is code I have written for inversion count in c++. If you write some other recursion method. Please try to explain it to me.
I am storing inversion count in countI. I am getting 2 as output for array A[] i have declared in main function.
#include<iostream>
#include<math.h>
using namespace std;
int countI = 0;
void merge(int A[], int p, int q, int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int *L;
L = new int[n1];
int *R;
R = new int[n2];
for (int i = 1; i <= n1; i++)
{
L[i] = A[p + i - 1];
// cout << A[p + i - 1]<<endl;
//cout << L[i];
}
for (int j = 1; j <= n2; j++)
R[j] = A[q + j];
int i = 1, j = 1;
// cout << "li " << L[n1]<<"\t"<<R[n2];
for (int k = p; k <= r; k++)
{
if ((L[i] <= R[j] && i <= n1) || j>n2)
{
A[k] = L[i];
//cout << A[k];
i++;
}
else
{
A[k] = R[j];
j++;
if (i<n1)
countI += n1 - i+1; //here I am counting the inversion.
//cout <<endl<<"R"<< R[j];
}
}
}
void mergeSort(int A[], int p, int r)
{
if (p < r)
{
// cout << A[8];
int sum = p + r;
//int q = (sum) / 2 + (sum % 2);
int q = (sum) / 2;
mergeSort(A, p, q);
mergeSort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
//I am considering array from index 1
int A[] = { 0, 1, 3, 5,2,4,6 };
// int arr[100001];
int i = 1;
int n = 0;
//while (scanf("%d", &n) != EOF) { arr[i++] = n; }
mergeSort(A, 1, 6);
for (int i = 1; i <= 6; i++)
{
cout << A[i] << " ";
}
cout << "\n " << countI;
system("pause");
return 0;
}
You should note C++ uses 0 index based arrays.
The first element of L and R are 0, not 1.
The same thing when you call mergeSort in you main.
try mergeSort(A, 0, 5)
While your consistent with your mistake of indexing starting at 1. You run off the end of your arrays by 1. This can cause your program to crash; however, when it doesn't you often get weird answers (which are hard to debug) because you're improperly accessing and writing over memory.
Here is some pseudo code (for 0 indexed based arrays) that will count inversions while performing merge sort.
merge(A, p, m , q){
B = [] // array size of q - p + 1
i = p, j = m+1, k = 0, inv = 0
while (i <= m && j <= q){
if (A[i] < A[j])
B[k++] = A[i++]
else{
B[k++] = A[j++]
inv += m - i + 1
}
}
while (i <= m) // copy rest of left side to temp array
B[k++] = A[i++] // otherwise it may be overwritten
i = 0;
while (i < k){ // copy temp array elements back to A
A[p+i] = B[i]
++i
}
return inv
}
merge_sort(A, p, q){
if (p == q)
return 0;
m = floor((p + q)/2)
inv1 = merge_sort(A, p, m)
inv2 = merge_sort(A, m+1, q)
return inv1 + inv2 + merge(A, p, m, q)
}
// you can call it like this:
A = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} // 10 Elements
inversions = merge_sort(A, 0, 9) // sort and count inversions from index 0 to index 9