Heap Sort giving wrong output ( Cpp ) - c++

I have written the following code for Heap Sort using Max-Heap logic.
#include<bits/stdc++.h>
#include<algorithm>
#include<vector>
using namespace std;
void max_heapify(vector<int> &a,int i)
{
int left=2*i+1;
int right=2*i+2;
if(i >= (int)a.size()/2 )
{
return;
}
int max=i;
if(a[i]<a[left])
{
max=left;
}
if(a[max]<a[right])
{
max=right;
}
if(max!=i)
{
swap(a[i],a[max]);
max_heapify(a,max);
}
}
void build_maxHeap(vector<int> &a)
{
int l=a.size();
for(int i=l/2-1;i>=0;i--)
{
max_heapify(a,i);
}
}
void heap_sort(vector<int> &a)
{
build_maxHeap(a); // max element at top.
for(int i=a.size()-1;i>=1;i--)
{
swap(a[i],a[0]);
cout<<a[i]<<" ";
a.pop_back();
max_heapify(a,0);
}
cout<<a[0]<<endl;
}
int main()
{
vector<int> a={6,7,8,1,2,9,32};
heap_sort(a);
return 0;
}
Output : 32 9 32 7 32 32
Expected Output: Print elements in descending order.
I don't know why there is a repetition of 32. I am popping the element from the end but can't figure out why such behavior.

in short: you do not handle case when left is inside vector, but right is not.
more in depth explanation:
in heap_sort after a.pop_back() a.size() is 6, calling max_heapify(a, 0), may, in turn call max_heapify(a, 2) , and when you call max_heapify(a, 2), and a.size() is 6, right will be 2*2+2 == 6, so you will attempt to access out of range for vector a (and there seems to be value 32 you popped from vector).

You have a bug in your max_heapify.
void max_heapify(vector<int> &a,int i)
{
int left=2*i+1;
int right=2*i+2;
if(i >= (int)a.size()/2 )
{
return;
}
int max=i;
if(a[i]<a[left])
{
max=left;
}
// Bug is here
if(a[max]<a[right])
{
max=right;
}
if(max!=i)
{
swap(a[i],a[max]);
max_heapify(a,max);
}
}
You always check a[max] < a[right], even if right >= size. So you can have this situation:
size = 2
i = 0
left = 1
right = 2
And the array contains: [0,1,3, ...]
Because you don't check to see if right >= size, the '3' will get re-inserted into your heap.

Related

How to check if a number is in a vector, and if not, then to return -1?

This is pretty easy if I can import <algorithm> or any other things at the top, but I just started using C++ and my professor asked us to use only loops and conditionals for this problem.
The problem itself is to give a vector v and an int seek to a function. A loop runs through the vector to find the index of the first location of the number. If it can be found, then return the index of where the number is, if not then return -1.
I got the first part down, but now I am having an issue with the second part.
#include <iostream>
#include "vectorutils.h"
#include <vector>
using namespace std;
//endl = new line
int main() {
cout << find({1, 2, 3, 4, 5, 6, 7, 8}, 28) << endl;
}
int find(const std::vector<int>& v, int seek) {
int ind = 1;
for (int i = 0; i < v.size(); i++) {
if (seek == v[i]) {
return i;
}
else {
return -1;
}
}
You have the return -1; statement in the wrong place. It needs to be after the loop exits, not inside the loop. For example:
int find(const std::vector<int>& v, int seek) {
for (int i = 0; i < v.size(); i++) {
if (seek == v[i]) {
return i;
}
// else {
// return -1;
// }
}
return -1; // <-- moved down here!
}
In your original code (if it could compile, which it doesn't), the logic is wrong. If the vector is empty then you return nothing at all (which is undefined behavior), and if the 1st element does not match the number then you return -1 immediately without checking the remaining elements at all.
The above change fixes both of those issues.

I am getting garbage values in my Merge Sort code

I am trying to implement merge sort algorithm in C++. This is my code.Logic seems to be fine.
But the output I'm getting is garbage values.I'm not able to get where the problem is in the code.
I think my logic is correct but I'm not sure.
#include <iostream>
using namespace std;
void Merge(int A[],int L[],int nL,int R[],int nR);
void MergeSort(int A[]);
//Function to Merge Arrays L and R into A.
//nL = number of elements in L
//nR = number of elements in R.
void Merge(int A[],int L[],int nL,int R[],int nR)
{
// i - to mark the index of left subarray (L)
// j - to mark the index of right sub-raay (R)
// k - to mark the index of merged subarray (A)
int i=0;
int j=0;
int k=0;
while(i<nL && j<nR)
{
if(L[i]<=R[i])
{ A[k]=L[i];
i=i+1;
}
else
{ A[k]=R[j];
j=j+1;
}
k=k+1;
}
while(i<nL)
{ A[k]=L[i];
i=i+1;
k=k+1;
}
while(j<nR)
{ A[k]=R[j];
j=j+1;
k=k+1;
}
}
// Recursive function to sort an array of integers.
void MergeSort(int A[],int n)
{
if (n<2) return;//base condition.If the array has less than two
//elements, do nothing
int mid=n/2;
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-
//array
// and (n-mid) elements (from mid to n-1) will be part of right sub-
//array
int left[mid];
int right[n-mid];
for(int i=0;i<mid-1;i++) left[i]=A[i];// create left subarray
for(int i=mid;i<n-1;i++) right[i-mid]=A[i];// create right subarray
MergeSort(left,mid);
MergeSort(right,n-mid);
Merge(A,left,mid,right,n-mid);
}
int main()
{ int A[]={2,4,7,1,5,3};
int n=sizeof(A)/sizeof(A[0]);
MergeSort(A,n);
for(int i=0;i<n;i++) cout<<A[i]<<" ";
return 0;
}
Expected output is 1 2 3 4 5 7
But actual is 0 -785903160 1 0(every time it's different)
This has been answered at, how-to-implement-classic-sorting-algorithms-in-modern-c. But I thought I'd post an answer that beginners my find valuable as I've seen this asked many times in the past. It must be a popular homework question.
In my opinion, if this is a modern C++ assignment, there should be a lot less of using indexing.
So in this implementation, I have not used std::merge and wrote the merge so some method could be seen.
Avoid the idiom: using namespace std; Why it is taught is beyond me. Typedef your types, it is much clearer.
using data_vect = std::vector<int>;
Hopefully this is clear enough and completely done with iterators. It is not as efficient as possible, the push_back in Merge could be avoided among other things. I DuckDucked this sort and the first few hits were not that great.
#include <iostream>
#include <vector>
using data_vect = std::vector<int>;
using dv_iter = data_vect::iterator;
data_vect Merge(data_vect& first, data_vect& second)
{
data_vect result;
dv_iter fval = first.begin();
dv_iter sval = second.begin();
for (;fval != first.end() || sval != second.end();)
{
if (fval == first.end())
result.push_back(*sval++);
else if (sval == second.end())
result.push_back(*fval++);
else if (*fval < *sval)
result.push_back(*fval++);
else
result.push_back(*sval++);
}
return result;
}
void MergeSort(data_vect& input)
{
int half = input.size() / 2;
if (! half)
return;
data_vect left(input.begin(), input.begin() + half );
data_vect right(input.begin() + half, input.end());
MergeSort(left);
MergeSort(right);
input = Merge(left, right);
}
int main()
{
data_vect A = { 6,2,7,4,1,5,3 };
MergeSort(A);
for ( auto& val : A )
std::cout << val << " ";
return 0;
}
Although understandable,
it is not possibile in C++ to declare an array with a variable size, e.g. int[mSize].
All arrays must have a constant size, e.g. int[10] or
const int mSize = 10;
int[mSize] mArray...
You want a storage container which has a variable size. as #PaulMcKenzie suggested,
you might want to use a Vector object. Your code would look something like this:
#include <iostream>
#include <vector>
using namespace std;
void Merge(vector<int>& A, vector<int>& L, vector<int>& R);
void MergeSort(vector<int>& A);
//Function to Merge Arrays L and R into A.
void Merge(vector<int>& A, vector<int>& L, vector<int>& R)
{
// i - to mark the index of left subarray (L)
// j - to mark the index of right sub-raay (R)
// k - to mark the index of merged subarray (A)
unsigned int i=0;
unsigned int j=0;
unsigned int k=0;
while(i<L.size() && j<R.size())
{
if(L[i]<=R[i])
{ A[k]=L[i];
i=i+1;
}
else
{ A[k]=R[j];
j=j+1;
}
k=k+1;
}
while(i<L.size())
{ A[k]=L[i];
i=i+1;
k=k+1;
}
while(j<R.size())
{ A[k]=R[j];
j=j+1;
k=k+1;
}
}
// Recursive function to sort an array of integers.
void MergeSort(vector<int>& A)
{
int n = A.size();
if (n<2) return;//base condition.If the array has less than two
//elements, do nothing
int mid=n/2;
// create left and right subarrays
// mid elements (from index 0 till mid-1) should be part of left sub-
//array
// and (n-mid) elements (from mid to n-1) will be part of right sub-
//array
vector<int> left(mid);
vector<int> right(n-mid);
for(int i=0;i<mid;i++) left[i]=A[i];// create left subarray
for(int i=mid;i<n;i++) right[i-mid]=A[i];// create right subarray
MergeSort(left);
MergeSort(right);
Merge(A,left,right);
}
int main()
{ vector<int> A={2,4,7,1,5,3};
MergeSort(A);
for(unsigned int i=0;i<A.size();i++) cout<<A[i]<<" ";
return 0;
}
[Edit]
I noticed I accidentally used comma's instead of dots in vector.size() calls. Also, I noticed 2 arrays stopping one item too early in copying left and right vectors.
Your code did not work. Above code compiles fine, but produces 1 3 5 2 4 7 as output. Also, have you thought of a vector of uneven length, such as 5 4 3 2 1?
At this point, the code will not split properly

C++ QuickSort Algorithm keeps crashing

Trying to implement a Quick Sort algorithm.I think the problem is with the recursion, but I do not know what I should do to fix it. The program continues to crash every time I run it, and I cannot understand why. Here is the code:
#include<iostream>
using namespace std;
int pIndex;
int Partition(int *A,int start,int end){
int pivot;
int pIndex;
if(start<end){
int pivot=A[end];
int pIndex=start;
for(int x=0;x<end;x++){
if(A[x]<A[end]){
swap(A[x],A[pIndex]);
pIndex=pIndex+1;
}
}
swap(A[pIndex],A[end]);
}
//cout<<pIndex<<endl;
swap(A[pIndex],A[end]);
return pIndex;
};
void QuickSort(int *A, int start,int end){
if(start<end)
{
pIndex=Partition(A,start,end);
QuickSort(A,pIndex+1,end);
QuickSort(A,start,pIndex-1);
}
};
int main(){
int A[10]{4,23,1,43,2,10};
//Partition(A,0,9);
QuickSort(A,0,5);
for(int x=0;x<10;x++){
cout<< A[x]<<" ";
}
}
Your partition algorithm is about twice as much code as it needs to be. You seem to be always choosing the last element in the sequence for your pivot, and although not advisable, it will work for academic demonstration.
Your Crash
You're defining two pIndex values, only one of which is actually deterministic. You also declare two pivot variables, but that does NOT cause your crash (the first one is never used). It should be cleaned up none-the-less, but the death knell in your code is duplicate pIndex
int pivot;
int pIndex; // HERE
if(start<end){
int pivot=A[end];
int pIndex=start; // HERE AGAIN
for(int x=0;x<end;x++){
if(A[x]<A[end]){
swap(A[x],A[pIndex]);
pIndex=pIndex+1;
}
}
swap(A[pIndex],A[end]);
}
swap(A[pIndex],A[end]); // uses non-determined pIndex
return pIndex; // returns non-determined pIndex
Changing int pIndex=start; to simply be pIndex=start; will solve your crash, but your partition method still needs... help.
The "Sweep" Partition Method
The "sweep" method of partitioning is generally done like this for a pivot value that is assumed to be right-tailed, and you would be hard pressed to get this simpler (invoking std::partition not withstanding):
size_t Partition(int *A, size_t len)
{
if (len < 2)
return 0;
size_t pvt = 0;
for (size_t i=0; i<end; ++i)
{
if (A[i] < a[len-1])
std::swap(A[i], A[pvt++])
}
std::swap(A[pvt], a[len-1]);
return pvt;
};
The above algorithm includes only the necessities needed for a partition: the sequence iterator (a pointer in your case), and the sequence length. Everything else is deterministic based on those two items. A quick sample program of how this works follows, with a purposely placed 5 for the pivot value:
#include <iostream>
size_t Partition(int *A, size_t len)
{
if (len < 2)
return 0;
size_t pvt = 0;
for (size_t i=0; i<len-1; ++i)
{
if (A[i] < A[len-1])
std::swap(A[i], A[pvt++]);
}
std::swap(A[pvt], A[len-1]);
return pvt;
};
int main()
{
int arr[] = { 4, 8, 7, 3, 9, 2, 1, 6, 5 };
size_t n = Partition(arr, sizeof(arr)/sizeof(*arr));
std::cout << "Partition : " << n << '\n';
for (auto x : arr)
std::cout << x << ' ';
std::cout << '\n';
}
Output
Partition : 4
4 3 2 1 5 7 8 6 9
How To Invoke From QuickSort
Invoking a partition in quicksort sets up the pivot location, which becomes the "end" iteration point of the bottom segment, and the one-BEFORE iteration point of the top segment. It is critical the pivot location returned from an invoke of Partition() should NOT be included in either subsequence when recursing.
void QuickSort(int *A, size_t len)
{
if (len < 2)
return;
size_t pvt = Partition(A, len);
QuickSort(A, pvt++); // NOTE: post increment...
QuickSort(A+pvt, len-pvt); // ...which makes this skip the pivot
}
Yeah, pointer arithmetic rocks, don't you think?
Putting It All Together
The program below incorporates both the Partition and QuickSort :
#include <iostream>
size_t Partition(int *A, size_t len)
{
if (len < 2)
return 0;
size_t pvt = 0;
for (size_t i=0; i<len-1; ++i)
{
if (A[i] < A[len-1])
std::swap(A[i], A[pvt++]);
}
std::swap(A[pvt], A[len-1]);
return pvt;
};
void QuickSort(int *A, size_t len)
{
if (len < 2)
return;
size_t pvt = Partition(A, len);
QuickSort(A, pvt++); // NOTE: post increment
QuickSort(A+pvt, len-pvt);
}
int main()
{
int arr[] = { 4, 8, 7, 3, 9, 2, 1, 6, 5 };
QuickSort(arr, sizeof(arr)/sizeof(*arr));
for (auto x : arr)
std::cout << x << ' ';
std::cout << '\n';
}
Output
1 2 3 4 5 6 7 8 9
I hope it helps.
In this part:
int pivot;
int pIndex;
if(start<end){
int pivot=A[end];
int pIndex=start;
You are defining two pivots, and two pIndex's. You are not using the pivot at all, and with the last swap you are using the uninitialized pIndex. This should work:
int Partition(int *A,int start,int end){
int pIndex = start;
if(start<end){
for(int x=0;x<end;x++){
if(A[x]<A[end]){
swap(A[x],A[pIndex]);
pIndex=pIndex+1;
}
}
swap(A[pIndex],A[end]);
}
swap(A[pIndex],A[end]);
return pIndex;
}
I'm also something of a C++ newbie, but I find myself curious about what happens when start >= end. It looks as though your Partition function will still return a pIndex value, but I don't see where you define it anywhere. If (as I suspect) it returns whatever value happens to reside in memory, then you'll very likely end up referencing some undefined memory locations when you use A[pIndex]

Segregating an array for even and odd numbers

I have implemented an algorithm to change an array so that all the even numbers are moved to the beginning of the array and the old numbers to the end of the array. Here is my program :-
#include <iostream>
using namespace std;
void print(int arr[], int size) {
for(int i=0;i<size;i++) {
cout<<arr[i]<<" ";
}
cout<<endl;
}
void segregate(int arr[], int size) {
int l=0, h=size-1;
while(l<h) {
while(!(arr[l]%2) && l<size) {
l++;
}
while((arr[h]%2) && h >=0) {
h--;
}
swap(arr[l], arr[h]);
}
}
int main() {
int arr[] = {1,2,3,4,5,6,7,8,9};
int size = 9;
print(arr,size);
segregate(arr,size);
print(arr,size);
return 0;
}
I don't get the expected result
1 2 3 4 5 6 7 8 9
8 2 6 5 4 3 7 1 9
What am I missing?
What you're trying to do is also called partitioning. The standard library provides two algorithms to do just that: std::partition and std::stable_partition.
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9};
auto split = std::partition( std::begin(arr), std::end( arr ),
[]( int a ) { return ! a%2; } );
// [ begin, split ) are all even
// [ split, end ) are all odd
}
http://ideone.com/kZI5Zh
If you're still interesting in writing your own, cppreference's description of std::partition includes the equivalent code.
Your version is missing an if statement right before the swap. You should only swap when there is an odd on the left.
Problem 1:
You need to call the swap only if l has not crossed h, you are calling it always.
Consider the array {2,1}, which is already sgeregated.
Now after the two inner while loops l will be 1 and h will be 0. In your case you'll go ahead and swap, but a swap is not really needed since l has crossed h.
And when that happens the array is already segregated.
So change
swap(arr[l], arr[h]);
to
if(l<h) {
swap(arr[l], arr[h]);
}
Problem 2:
Also the order of conditions in your inner while loops must be reversed. You are checking
while(number at index l is even AND l is a valid index) {
l++;
}
which is incorrect. Consider an array {2,4}, now at some point in the above while loop l will be 2 and you go ahead and access arr[2], which does not exist.
What you need is:
while(l is a valid index AND number at index l is even) {
l++;
}
As simple as it gets:
void partitionEvenOdd(int array[], int arrayLength, int &firstOdd)
{
firstOdd = 0;
for (int i = 0; i < arrayLength; i++) {
if (array[i]%2 == 0) {
swap(array[firstOdd], array[i]);
firstOdd++;
}
}
}
Can't you just use standard sort?
Something like:
#include <stdio.h>
#include <stdlib.h>
int values[] = { 40, 10, 100, 90, 20, 25 };
int compare (const void * a, const void * b)
{
// return -1 a-even and b-odd
// 0 both even or both odd
// 1 b-even and a-odd
}
qsort (values, 6, sizeof(int), compare);

Optimizing subset sum implementation

I'm working on a solution to a variant of the subset sum problem, using the below code. The problem entails generating subsets of 11 ints from a larger set (superset) and check if it matches a specific value (endsum).
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int endsum = 0, supersetsize = 0, done = 0;
int superset[] = {1,30,10,7,11,27,3,5,6,50,45,32,25,67,13,37,19,52,18,9};
int combo = 0;
int searchForPlayerInArray(int arr[], int player) {
for (int i=0; i<11; i++) {
if (arr[i] == player) {
return 1;
}
}
return 0;
}
int sumOfArray(int arr[]) {
int res = 0;
for (int i=0; i<11; i++) {
res+=arr[i];
}
return res;
}
void printArray(int arr[], int arrSize) {
for (int j=0; j<arrSize; j++) {
printf("%2d ",arr[j]);
}
printf("= %d\n",endsum);
}
void permute(int subset[], int pos, int sspos) {
if (done) { //when a correct solution has been found, stop recursion
return;
}
if (sspos == supersetsize) { // out of possible additions
return;
}
if (pos == 11) { //is the current subset 11 ints long?
int res = sumOfArray(subset);
combo++;
if (res == endsum) { //if the sum of the array matches the wanted sum, print
printArray(subset,11);
done = 1;
}
return;
}
for (int i=sspos; i<supersetsize; i++) {
//assert(pos < 11);
//assert(i+1 <= supersetsize);
subset[pos] = superset[i];
permute(subset,pos+1,i+1);
}
}
int main(void) {
endsum = 110;
supersetsize = 20;
int *arr;
arr = malloc(supersetsize*sizeof(int));
int i;
for (i=0; i<supersetsize; i++) {
arr[i] = 0;
}
permute(arr,0,0);
printf("Combinations: %d",combo);
return 0;
}
Although this solution works for small supersets (<15) it is slow and inefficient because it generates every possible permutation instead of just the unique ones. How can I optimize it to generate only unique subsets?
Edit: Complete source code added by popular demand.
One way to only generate unique subsets is to add the elements from the superset in order, and use an additional argument to permute (eg. supersetPos) to indicate where you are in the superset. This generates sorted permutations which will be unique.
EDIT: Code that AFAIK runs correctly on your sample:
#include <stdio.h>
int superset[] = {
1, 30, 10, 7, 11,
27, 3, 5, 6, 50,
45, 32, 25, 67, 13,
37, 19, 52, 18, 9
};
int supersetsize = 20;
int endsum = 110;
int done = 0;
int sumOfArray(int array[]) {
int sum = 0;
for(int i = 0; i < 11; i++)
sum += array[i];
return sum;
}
void permute(int subset[], int pos, int sspos) {
if (pos == 11) { //is the current subset 11 ints long?
if (sumOfArray(subset) == endsum) { //if the sum of the array matches the wanted sum, print
for (int j=0; j<11; j++) {
printf("%d ",subset[j]);
}
printf("\n");
done = 1;
}
return;
}
for (int i=sspos; i<supersetsize; i++) {
subset[pos] = superset[i];
permute(subset,pos+1,i+1);
if (done) { //when a correct solution has been found, stop recursion
return;
}
}
}
int main() {
int subset[11] = {0};
permute(subset, 0, 0);
}
I don't think there is a way to generate the unique subsets in better than exponential time.
To solve subset-sum efficiently you want to use dynamic programming. There are some pseudo-polynomial time algorithms for subset-sum that work this way. This Wikipedia article might help.
you can try my code ( I tried to only give a psudo code and not to solve your homework completely):
// array is all the numbers you are looking from them
// length is the number of arrays
// pos is the position of the slot you are going to fill
// max is nomber of slots you have to fill (in your case since you are going for the 11 sets you have to set this value as 11
// sum is the sum of all the values selected until now
// searchbegin is the first element you can pick from your array (I'm using this variable to only generate subarrays of the superset (array))
// target is the targetvalue you are looking for.
void generate_all(int []array, int length, int pos,int max, int sum,int searchbegin,int target)
{
if max = pos
if sum = target
printselectedresults();
for i:searchbegin->length-max+pos
if (sum + array[i] < target)
{
addtoresults(i);
generate_all(array,length,pos+1,max,sum+array[i],i+1,target);
removefromresults(i);
}
}
with all this information I think you can easily Implement this code your target language and use it.
in my function all the permutations generated are subarrays of superset so no permutation can be generated twice, and also every one is generated at least one time.