Min heap does not work as intended in C++ - c++

I am having problem with the min heap algorithm.
The code I programmed returned an array that incorrectly arranged, below is my code, can someone help me to find where should I change?
Thank you.
The data was under ELEMENT arr[], where ELEMENT is a struct:
struct ELEMENT{
int key;
};
void constructMinHeap(ELEMENT arr[], int size, int num){
int left = leftNode(num);
int right = rightNode(num);
int min;
if (left < size && arr[left].key < arr[num].key){
min = left;
} else{
min = num;
}
if (right < size && arr[right].key < arr[min].key){
min = right;
}
if(min != num){
swap(&arr[num].key, &arr[min].key);
constructMinHeap(arr, size, num);
}
}
ELEMENT* buildHelper (ELEMENT arr[], int size){
int i = size / 2 - 1;
while (i >= 0){
constructMinHeap(arr, size, i);
i--;
}
return arr;
}
And here is the code for calculating leftNode and rightNode:
int leftNode(int num){
return 2 * num + 1;
}
int rightNode(int num){
return (2 * num) + 2;
}
The following code is for storing data into the ELEMENT arr[]:
ifstream infile("somefilename.txt");
if (infile.good()) {
int i = 0;
int size;
infile >> size;
ELEMENT arr[size];
while (i < size){
infile >> arr[i].key;
i++;
}
BuildHeap(h, arr, size);
infile.close();
} else{
cout << "File \"somefilename.txt\" does not exist in the current directory.";
}
When the file's content is
4 4 3 2 1
The feedback becomes:
1 4 2 3

Your recursive call for num is incorrect, it has no progress since it calls the same num again. In case if the node is swapped with its smallest child, that child should be further pushed down until it takes its proper place. This will guarantee that the binary subtree rooted at num is heapified
The correct recursion is the following (you didn't show the swap so I added my own one):
void swap(ELEMENT* e1, ELEMENT* e2)
{
int tmp = e1->key;
e1->key = e2->key;
e2->key = tmp;
}
void constructMinHeap(ELEMENT arr[], int size, int num){
int left = leftNode(num);
int right = rightNode(num);
int min = num;
if (left < size && arr[left].key < arr[min].key){
min = left;
}
if (right < size && arr[right].key < arr[min].key){
min = right;
}
if(min != num)
{
swap(&arr[num], &arr[min]);
constructMinHeap(arr, size, min);
}
}

Related

Max heapify infinite loop when used on array but not vector

I am trying to convert a max-heapify function that I used for a vector to work with sorting an array of ints, however, when I run it, I am running into an infinite loop.
I believe the logic of my algorithm seems to be right, however, my siftdown function doesnt seem to function properly.
void Sort::heapify(int *array, int size){
for(int i = (size-2)/2;i >= 0;i--){
siftdown(array, i, size);
}
}
void Sort::siftdown(int *array, int i, int size){
if(i >= size || i < 0){
cout << "i is >= size of playerArray or i < 0. i: " << i << endl;
return;
}
cout<< "passed something" <<endl;
while(!isLeaf(array, i, size)){
cout<<"!isLeaf"<<endl;
int max = getLeft(i);
if(max + 1 < size && array[max] < array[max +1]){
max++;
cout << "added to max.";
}
if (array[i] > array[max]){
cout<< "array[i] is > than array[max]"<<endl;
return;
}
swap(i, max);
i = max;
}
cout<<"isLeaf"<<endl;
}
int Sort::getLeft(int index){
//gets the left most leaf
int left = 2*index+1;
return left;
}
bool Sort::isLeaf(int *array, int index, int size){
//A node is a leaf node if both left and right child nodes of it are NULL.
int left = 2*index+1;
int right = left+1;
if(left>size && right>size) return true;
return false;
}
Any help would be greatly appreciated. Thanks!
When you write (in the body of while in Sort::siftdown())
swap(i, max);
i = max;
you're ending with i and max with the old value of i; so you repeat
while(!isLeaf(array, i, size))
with the same values.
Loop!

Inserting value into sorted array without duplicates: C++

For this program I have three data files. The first has a list of numbers, the second is a list of numbers with an add (A) or delete (D) command. I have to put the numbers from the first file into the third file, then update the final file based on the commands and numbers in the second file. The third file cant have duplicates and must be sorted while values are being inserted. Here are the functions I have, I'm having difficulty getting the items stored into the array without duplicates. The array must be statically sized, I did a #define of max size 2000 which is more than enough to handle the numbers I need. Thanks so much! If I should upload the main let me know, but I'm fairly certain the problem lies in one of these functions.
int search(int value, int list[], int n) // returns index, n is logical size of array
{
int index = -1;
for(int i = 0; i < n; i++)
{
if(value == list[i])
{
index = i;
return index;
}
}
return index;
}
void storeValue(int value, int list[], int& n)
{
int i = n;
for(; i > 0 && list[i - 1] < value; i--)
{
list[i] = list[i - 1];
}
list[i] = value;
n++;
}
void deleteValue(int loc, int list[], int n)
{
if(loc >= 0 && loc < n)
{
for(int i = loc; i < n - 1; i++)
list[i] = list[i +1];
n--;
}
}
UPDATE: Now duplicates are being stored, but only for some numbers.
For example: my 3rd file is: 1,2,8,8,9,101,101,104,etc.
The output should be: 1,2,8,9,101,104,etc
value: value to be inserted
list[]: array being modified (must be static)
n: logical size of array
I can't figure out why some numbers are duplicated and others aren't
In my main, I run the search function and if a -1 is returned (the value isn't already found) then I run the storeValue function.
Here are my updated functions:
int search(int value, int list[], int n) // returns index
{
int index = -1;
for(int i = 0; i < n; i++)
{
if(value == list[i])
{
index = i;
return index;
}
}
return index;
}
void storeValue(int value, int list[], int& n)
{
int i = n;
for(; i > 0 && list[i - 1] > value; i--)
{
list[i] = list[i - 1];
}
list[i] = value;
n++;
}
void deleteValue(int loc, int list[], int& n)
{
if(loc >= 0 && loc < n)
{
for(int i = loc; i < n; i++)
{
if (i == loc)
{
list[i] = list[i + 1];
i++;
}
}
n--;
}
}
In your deleteValue function, you are deleting the value, but will end up with a duplicate because you are just reassigning the current index to the next value. For example, if you have the array:
char array[3] = [1, 2, 3];
and you wanted to delete the second integer, your function currently would output this:
[1, 3, 3]
What you want to do is make a new array and loop through your entire list, making sure to leave out the last element like so:
char* deleteValue(int loc, int list[], int n)
{
char* newArray[n - 1];
if (loc >= 0 && loc < n)
{
for (int i = 0; i < n - 1; i++)
{
if (i == loc) // You have arrived at the element that needs to be deleted
{
newArray[i] = list[i + 1];
i++; // So we skip over the deleted element
}
else
newArray[i] = list[i];
}
}
return newArray;
}
And this should take care of the case where the last value is duplicated.

Two sorting algorithms give me two different outputs on the same array (quickSort and heapSort)!

I don't understand why they give me different output when I compile them. For example ... when I compile only one algorithm the answer is good, the same is for the other one, but when I compile them both at the same time they give me some weird output.
My code:
#include <iostream>
using namespace std;
int parent(int i){
return i/2;
}
int leftChild(int i){
return 2*i+1;
}
int rightChild(int i){
return 2*i+2;
}
void maxHeapify(int a[], int i, int n){
int largest;
int temp;
int l = leftChild(i);
int r = rightChild(i);
// p.countOperation("CMPbottomUp",n);
if (l <= n && (a[l] > a[i]))
largest = l;
else
largest = i;
// p.countOperation("CMPbottomUp",n);
if (r <= n && (a[r] > a[largest]))
largest = r;
if (largest != i){
// p.countOperation("ATTbottomUp",n);
temp = a[i];
// p.countOperation("ATTbottomUp",n);
a[i] = a[largest];
//p.countOperation("ATTbottomUp",n);
a[largest] = temp;
maxHeapify(a, largest, n);
}
}
void buildMaxHeap(int a[], int n){
for (int i=n/2; i>=0; i--){
maxHeapify(a, i, n);
}
}
void heapSort(int a[],int n){
buildMaxHeap(a,n);
int n1=n;
int temp;
for(int i=n1;i>0;i--){
temp = a[0];
a[0] = a[i];
a[i] = temp;
n1--;
maxHeapify(a,0,n1);
}
}
int partitionArray(int arr[], int left, int right){
int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
return i;
}
void quickSort(int arr[], int left, int right) {
int index;
index = partitionArray(arr, left, right);
if (left < index - 1)
quickSort(arr, left, index - 1);
if (index < right)
quickSort(arr, index, right);
}
int main(){
int x[8]= {5,87,21,4,12,7,44,3};
int a[8];
for(int i=0;i<8;i++){
a[i] = x[i];
}
heapSort(x,8);
quickSort(a,0,8);
for(int i=0;i<8;i++){
cout<<a[i]<<' ';
}
cout<<endl;
for(int j=0;j<8;j++){
cout<<x[j]<<' ';
}
return 0;
}
Example output:
1) When I compile only one algorithm the output is : 3,4,5,7,12,21,44,87 (which is good)
2) When I compile both of them in the code the output is: 87,4,5,7,12,21,44,87 (quickSort) and 3,3,4,5,7,12,21,44 (heapSort)
I think that should work:
heapSort(x,7);
quickSort(a,0,7);
Arrays a and x are right next to each others in stack. Seeing how you have duplicate value 87 in output, it seems your sort functions access memory outside the array you give to them. This is buffer overrun, a type of Undefined Behaviour. With that, your code could do anything because you have corrupted variable values (or worse, corrupted addresses/pointers).
Double check how you access arrays. Remember that C array indexes for your arrays of length 8 are 0..7!

Strange Segmentation Fault in Heap Implementation

Given below is a driver program I have written for using my own implementation of a heap.
#include<iostream>
#include"Heap.h"
int main(){
Heap h(30);
h.insert(1);
h.insert(3);
h.insert(5);
h.insert(6);
h.insert(5);
h.insert(8);
h.display();
std::cout<<h.extractMin(); // Statement 1
h.display();
}
This gives the desired result as:
========= Heap Contents =========
1 3 5 6 5 8
1
========= Heap Contents =========
3 6 5 8 5
However, if I change the statement 1 to:
std::cout<<"Min: "<<h.extractMin();
the code starts giving a Segmentation fault. Again, if I change the statement 1 to
int z = h.extractMin();
the code still gives a Segmentation fault. This tempted me to see if I am doing something wrong in extractMin(). Below is my definition of extractMin():
int Heap::extractMin()
{
int min = this -> arr[0];
this -> arr[0] = this -> arr[heapSize];
heapSize -= 1;
heapify(0);
return min;
}
And just for completeness's sake below is my definition for heapify():
void Heap::heapify(int index){
if(index > this -> heapSize)
return;
int smallest = index;
int l = leftChild(index);
int r = rightChild(index);
if(l <= heapSize && arr[l] < arr[index])
smallest = l;
if(r <= heapSize && arr[r] < smallest)
smallest = r;
if(smallest != index){
arr[smallest] = arr[smallest] ^ arr[index];
arr[index] = arr[smallest] ^ arr[index];
arr[smallest] = arr[smallest] ^ arr[index];
heapify(smallest);
}
}
Any idea what's going on? I am unable to understand the reason behind segmentation fault. Is there anything obvious I am missing?
Thank you!
Addition 1:
This happens for h.getHeapSize() and h.getArrSize() as well, which makes me think that the problem lies in something else and not in the functions.
Addition 2:
The entire code goes below:
#include<iostream>
#include<cmath>
class Heap{
private:
int* arr;
int size;
int heapSize;
public:
Heap(int = 8);
Heap(int*, int size);
int* initArr(int size);
void setSize(int);
int getSize();
int getHeapSize();
void setHeapSize(int);
int leftChild(int);
int rightChild(int);
int parent(int);
void heapify(int);
void buildHeap();
void insert(int);
int extractMin();
void display() const;
};
Heap::Heap(int size){
initArr(size);
this -> size = size;
this -> heapSize = -1;
}
Heap::Heap(int* arr, int size){
this -> arr = arr;
this -> size = size;
this -> heapSize = size - 1;
buildHeap();
}
int* Heap::initArr(int size){
int* arr = new int[size];
return arr;
}
void Heap::setSize(int size){
if(size > this -> heapSize)
this -> size = size;
}
int Heap::getSize(){
return this -> size;
}
void Heap::setHeapSize(int heapSize){
this -> heapSize = heapSize;
}
int Heap::getHeapSize(){
return this -> heapSize;
}
int Heap::leftChild(int index){
return 2*index + 1;
}
int Heap::rightChild(int index){
return 2*index + 2;
}
int Heap::parent(int index){
return ceil(index >> 1) - 1;
}
void Heap::heapify(int index){
if(index > this -> heapSize)
return;
int smallest = index;
int l = leftChild(index);
int r = rightChild(index);
if(l <= heapSize && arr[l] < arr[index])
smallest = l;
if(r <= heapSize && arr[r] < smallest)
smallest = r;
if(smallest != index){
arr[smallest] = arr[smallest] ^ arr[index];
arr[index] = arr[smallest] ^ arr[index];
arr[smallest] = arr[smallest] ^ arr[index];
heapify(smallest);
}
}
void Heap::buildHeap(){
for(int i = heapSize/2 - 1; i >= 0; i-- )
heapify(i);
}
void Heap::insert(int val){
heapSize += 1;
int loc = heapSize;
arr[heapSize] = val;
int p;
while((p = arr[parent(heapSize)]) > val){
arr[loc] = arr[p] ^ arr[loc];
arr[p] = arr[p] ^ arr[loc];
arr[loc] = arr[p] ^ arr[loc];
}
}
int Heap::extractMin(){
//int temp = arr[0];
//arr[0] = arr[heapSize];
//arr[heapSize] = temp;
int min = arr[0];
arr[0] = arr[heapSize];
heapSize -= 1;
heapify(0);
//return arr[heapSize + 1];
return min;
}
void Heap::display() const{
std::cout<<"\n========= Heap Contents =========\n";
for(int i = 0; i <= heapSize; i++)
std::cout<<arr[i]<<'\t';
std::cout<<'\n';
}
There are numerous problems.
First, your constructor that takes an int parameter doesn't initialize the arr member, it allocates memory and assigns it to a local pointer variable, which it returns but you just ignore the return value.
You have to store it in the member variable (it's usually a very bad idea to name local variables the same as members.)
Once you fix that: during the first insertion, h.insert(1);, parent(heapSize) is -1.
Since you use that to index in the array, the program has undefined behaviour and all bets are off; the program isn't a valid C++ program.
There might be other problems as well, but those are the most obvious.
From what you posted here, improper handling of the heap size is to blame. All test involving heapSize do not seem to account for zero based accessing. You should really change this, as it leads to a lot of unlogical consequences: Does heapSize get initialized to -1?
As for debugging:
Leisurely add more null and boundary checks (not only to heapSize but also to 0)
Try reducing the test set (does it crash with one item?) and try to trace the control flow by hand or by using gdb
EDIT
The bug is in parent(). Try the debugging tips.

Heap Sort in C++

Okay, so after struggling with trying to debug this, I have finally given up. I'm a beginner in C++ & Data Structures and I'm trying to implement Heap Sort in C++. The code that follows gives correct output on positive integers, but seems to fail when I try to enter a few negative integers.
Please point out ANY errors/discrepancies in the following code. Also, any other suggestions/criticism pertaining to the subject will be gladly appreciated.
//Heap Sort
#include <iostream.h>
#include <conio.h>
int a[50],n,hs;
void swap(int &x,int &y)
{
int temp=x;
x=y;
y=temp;
}
void heapify(int x)
{
int left=(2*x);
int right=(2*x)+1;
int large;
if((left<=hs)&&(a[left]>a[x]))
{
large=left;
}
else
{
large=x;
}
if((right<=hs)&&(a[right]>a[large]))
{
large=right;
}
if(x!=large)
{
swap(a[x],a[large]);
heapify(large);
}
}
void BuildMaxHeap()
{
for(int i=n/2;i>0;i--)
{
heapify(i);
}
}
void HeapSort()
{
BuildMaxHeap();
hs=n;
for(int i=hs;i>1;i--)
{
swap(a[1],a[i]);
hs--;
heapify(1);
}
}
void main()
{
int i;
clrscr();
cout<<"Enter length:\t";
cin>>n;
cout<<endl<<"Enter elements:\n";
for(i=1;i<=n;i++) //Read Array
{
cin>>a[i];
}
HeapSort();
cout<<endl<<"Sorted elements:\n";
for(i=1;i<=n;i++) //Print Sorted Array
{
cout<<a[i];
if(i!=n)
{
cout<<"\t";
}
}
getch();
}
I've been reading up on Heap Sort but I'm not able to grasp most of the concept, and without that I'm not quite able to fix the logical error(s) above.
You set hs after calling BuildMaxHeap. Switch those two lines.
hs=n;
BuildMaxHeap();
When I implemented my own heapsort, I had to be extra careful about the indices; if you index from 0, children are 2x+1 and 2x+2, when you index from 1, children are 2x and 2x+1. There were a lot of silent problems because of that. Also, every operation needs a single well-written siftDown function, that is vital.
Open up Wikipedia at the Heapsort and Binary heap articles and try to rewrite it more cleanly, following terminology and notation where possible. Here is my implementation as well, perhaps it can help.
Hmmm now that I checked your code better, are you sure your siftDown/heapify function restricts sifting to the current size of the heap?
Edit: Found the problem! You do not initialize hs to n before calling BuildMaxHeap().
I suspect it's because you're 1-basing the array. There's probably a case where you're accidentally 0-basing it but I can't spot it in the code offhand.
Here's an example if it helps.
#include <iostream>
#include <vector>
using namespace std;
void max_heapify(std::vector<int>& arr, int index, int N) {
// get the left and right index
int left_index = 2*index + 1;
int right_index = 2*index + 2;
int largest = 0;
if (left_index < N && arr[left_index] > arr[index]) {
// the value at the left_index is larger than the
// value at the index of the array
largest = left_index;
} else {
largest = index;
}
if (right_index < N && arr[right_index] > arr[largest]) {
// the value at the right_index is larger than the
// value at the index of the array
largest = right_index;
}
// check if largest is still the index, if not swap
if (index != largest) {
// swap the value at index with value at largest
int temp = arr[largest];
arr[largest] = arr[index];
arr[index] = temp;
// once swap is done, do max_heapify on the index
max_heapify(arr, largest, N);
}
}
void build_max_heap(std::vector<int>& arr, int N) {
// select all the non-leaf except the root and max_heapify them
for (int i = N/2 - 1; i >= 0; --i) {
max_heapify(arr, i, N);
}
}
void heap_sort(std::vector<int>& arr) {
int N = arr.size();
int heap_size = N;
// build the max heap
build_max_heap(arr, N);
// once max heap is built,
// to sort swap the value at root and last index
for (int i = N - 1; i > 0; --i) {
// swap the elements
int root = arr[0];
arr[0] = arr[i];
arr[i] = root;
// remove the last node
--heap_size;
// perform max_heapify on updated heap with the index of the root
max_heapify(arr, 0, heap_size);
}
}
int main() {
std::vector<int> data = {5,1,8,3,4,9,10};
// create max heap from the array
heap_sort(data);
for (int i : data) {
cout << i << " ";
}
return 0;
}
# include <iostream> //Desouky//
using namespace std;
void reheapify(int *arr, int n, int i)
{
int parent = i; // initilaize largest as parent/root
int child1 = 2 * i + 1; // to get first chid
int child2 = 2 * i + 2; // to get second child
if (child1 < n && arr[child1] > arr[parent]) // if child2 > parent
{
parent = child1;
}
//if child > the parent
if (child2 < n && arr[child2] > arr[parent])
{
parent = child2;
}
// if the largest not the parent
if (parent != i)
{
swap(arr[i], arr[parent]);
// Recursively heapify the affected sub-tree
reheapify(arr, n, parent);
}
}
void heapsort(int *arr, int n)
{
// build a heap
for (int i = n - 1; i >= 0; i--)
{
reheapify(arr, n, i);
}
// One by one extract an element from heap
for (int i = n - 1; i >= 0; i--)
{
// Move current root to end
swap(arr[0], arr[i]);
// call max heapify on the reduced heap
reheapify(arr, i, 0);
}
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
int* arr = new int[n];
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
heapsort(arr, n);
for (int i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
}