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.
Related
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);
}
}
So I am trying to figure out how to create a function that Returns an Array of all integers that are in common with self and ary and returns an empty Array if there are no intersections. This is what I have so far:
IntArray* findIntersections(IntArray &ary) {
int length1 = ary.getLength(); // Getting the length of &ary.
int length2 = getLength([//Right here, there's something to do with "this" because I've created a mArray already and defined it, but I'm not sure how to re-call it here.]); // Getting the length of self.
int length4 = 0; // Because anarchy
if (length1 > length2){ // An if statement to match length4 with the longest array.
length4 = length2;
} else {
length4 = length1;
}
IntArray* newArray; // New IntArray on the heap.
newArray = new* int[length4];
int k = 0;
for (int j = 0; j < length1; j++){ // Two for loops getting the iterator on the same page.
for (int i = 0; i < length2; i++){
if (ary.get(j) == [//The this from earlier, whatever it is][i]){ // Checking to see if digits match each other.
newArray[k] = (ary[j]); // Writing the digit into the NewArray.
k++; // Adding one to the k count to progress the the iterator.
}
}
}
return newArray;
}
In the end, there I know there's gonna be three arrays. The one being passed in, the one being created and passing out, and then that this reference which I honestly don't even know what it is. I'm thinking it's an mArray I created earlier, but I'm not exactly sure. Any help on this would be absolutely fantastic!
Also, here's my .hpp file:
class IntArray {
private:
int *mArray;
int mSize;
public:
IntArray(int *array, int size);
int get(int index);
int getLength();
int indexOf(int value);
bool remove(int index);
IntArray* findIntersections(IntArray &ary);
bool isSubsequence(IntArray &ary);
~IntArray();
};
And my .cpp file:
#include "IntArray.hpp"
IntArray::IntArray(int *array, int size) {
int *newArray = new int [size];
for (int i = 0; i < size; i++){
newArray[i] = array[i];
}
}
int IntArray::get(int index) {
return mArray[index];
}
IntArray::~IntArray() {
delete[] mArray;
}
int IntArray::getLength() {
return mSize;
}
int getLength(int *array){
int length = (sizeof(array)/sizeof(array[0]));
return length;
}
int indexOf(int *array, int value){
int length = getLength(array);
for (int i = 0; i < length; i++){
if (value == array[i]){
return i;
}
}
return -1;
}
bool remove(int *array, int index){
int length = getLength(array);
if (0 <= index && index < length){
for (int i = index + 1; i < length; ++i){
array[i - 1] = array[i];
}
for (int i = 0; i < length; i++)
return true;
} else {
return false;
}
}
IntArray* findIntersections(IntArray &ary) {
int length1 = ary.getLength(); // Getting the length of &ary.
int length2 = getLength([//Right here, there's something to do with "this" because I've created a mArray already and defined it, but I'm not sure how to re-call it here.]); // Getting the length of self.
int length4 = 0; // Because anarchy
if (length1 > length2){ // An if statement to match length4 with the longest array.
length4 = length2;
} else {
length4 = length1;
}
IntArray* newArray; // New IntArray on the heap.
newArray = new* int[length4];
int k = 0;
for (int j = 0; j < length1; j++){ // Two for loops getting the iterator on the same page.
for (int i = 0; i < length2; i++){
if (ary.get(j) == [//The this from earlier, whatever it is][i]){ // Checking to see if digits match each other.
newArray[k] = (ary[j]); // Writing the digit into the NewArray.
k++; // Adding one to the k count to progress the the iterator.
}
}
}
return newArray;
}
bool isSubsequence(int *array) {
int length = getLength(array);
for (int i = 0; i < length - 1; i++) {
if (array[i] != array[i + 1])
return false;
}
return true;
}
Your implementation of findIntersection is not defined as a member function, you have defined it as a global function. The member function declaration named findIntersection is not defined. In short: you forgot IntArray:: before the function name
I've been trying to make a dynamic array. My main method calls push_back() to add ints to an array 50 times. The push_back() method calls the grow_if_needed() method if the size of the array needs to be doubled. The size() method returns the current capacity of the array. And the toString method is for printing the array as a string. I keep getting this error at the end of the grow_if_needed() method.
#include <string>
class ArrayList
{
private:
static int capacity;
static int count;
public:
int& operator [](int i);
int *arrayPtr = new int[1];
ArrayList();
int * push_back(int m);
int * grow_if_needed();
int * erase(int m);
int size();
std::string toString();
};
#include "ArrayList.h"
using namespace std;
int ArrayList::capacity = 1;
int ArrayList::count = 0;
int & ArrayList::operator[](int i)
{
return arrayPtr[i];
}
ArrayList::ArrayList()
{
arrayPtr[0] = 0;
}
int * ArrayList::push_back(int m)
{
if (count == size()) {
grow_if_needed();
}
for (int i = size() - 1; i >= 0; i--) {
arrayPtr[i + 1] = arrayPtr[i];
}
arrayPtr[0] = m;
count++;
return arrayPtr;
}
int * ArrayList::grow_if_needed() {
int k;
capacity = size() * 2;
int * tempArray = new int[capacity];
for (k = 0; k < count; k++) {
tempArray[k] = arrayPtr[k];
}
while (k != capacity) {
tempArray[k] = 0;
k++;
}
delete [] arrayPtr;
arrayPtr = tempArray;
return arrayPtr;
}
int ArrayList::size()
{
return capacity;
}
string ArrayList::toString()
{
string num = "";
for (int i = 0; i <= size() - 1; i++) {
num += std::to_string(arrayPtr[i]) + " ";
}
return num;
}
In your push_back function you have this loop:
for (int i = size() - 1; i >= 0; i--) {
arrayPtr[i + 1] = arrayPtr[i];
}
Here size() - 1 is the top index, so in the first iteration when you do i + 1 you are out of bounds.
Also, this function is called push_back, but it attempts to add to the front? If it added to the end (the "back") you would not need the loop, and your problem would "magically" disappear.
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!
Im implementing HeapSort for an assignment in my algorithms class, and Im finally done, but for some reason, the sort is skipping over the first element in my array.
Original array:
int heapArray[SIZE] = { 5 ,99, 32, 4, 1, 12, 15 , 8, 13, 55 };
Output after HeapSort()
5 99 32 15 13 12 8 4 1
Iv gone through all the functions and cant figure out why its skipping the first element. Can anyone help me out? Iv included all the HeapSort functions below. I know its alot to look at, but im sooooo close.
int main()
{
int heapArray[SIZE] = { 5 ,99, 32, 4, 1, 12, 15 , 8, 13, 55 };
HeapSort(heapArray);
return 0;
}
.........................................................................................
void HeapSort(int heapArray[])
{
int heap_size = SIZE;
int n = SIZE;
int temp;
Build_Max_Heap(heapArray);
for(int i = n-1; i >= 2; i--)
{
temp = heapArray[1];
heapArray[1] = heapArray[i];
heapArray[i] = temp;
heap_size = heap_size-1;
Max_Heapify(heapArray,1);
}
return;
}
...........................................................................................
void Build_Max_Heap(int heapArray[])
{
double n = SIZE;
for(double i = floor((n-1)/2); i >= 1; i--)
{
Max_Heapify(heapArray,i);
}
return;
}
...........................................................................................
void Max_Heapify(int heapArray[],int i)
{
int n = SIZE;
int largest = 0;
int l = Left(i);
int r = Right(i);
if(( l <= n) && (heapArray[l] > heapArray[i]))
{
largest = l;
}
else
{
largest = i;
}
if( (r <= n) && ( heapArray[r] > heapArray[largest]))
{
largest = r;
}
int temp;
if(largest != i)
{
temp = heapArray[i];
heapArray[i] = heapArray[largest];
heapArray[largest] = temp;
Max_Heapify(heapArray,largest);
}
return;
}
...........................................................................................
int Parent(int i)
{
return (i/2);
}
int Left(int i)
{
return (2*i);
}
int Right(int i)
{
return ((2*i)+1);
}
You have several issues in your code:
Firstly: array indices start from 0 not 1, therefore, there are many places with index errors listed as follows:
In HeapSort function:
for(int i = n-1; i >= 2; i--) {
//should be 1 not 2
temp = heapArray[1]; //should be 0 not 1 in those 2 statements
heapArray[1] = heapArray[i];
heapArray[i] = temp;
}
Max_Heapify(heapArray,1);
//should start from 0 not 1
Besides:
for(double i = floor((n-1)/2); i >= 1; i--)
{ //should start from 0 not 1
Max_Heapify(heapArray,i);
}
You Parent, Left and Right have similar errors, you can see the above two posts.
Meanwhile, You have logical errors in you HeapSort and Max_Heapfiy function.
You define heap_size and update it, but you never really used it. You have to pass it into the Max_Heapify function. Since each time when you put the current largest element to the end of the array, you only need to heapify the remaining elements not the whole heap anymore. This also means that your heapify function has errors since you never really used heap_size. The correct HeapSort and Max_Heapify as well as Build_Max_Heap function should be:
HeapSort:
void HeapSort(int heapArray[])
{
//do what you did before this sentence
Build_Max_Heap(heapArray,heap_size);
//need to pass heap_size since Max_Heapify use heap_size
for(int i = n-1; i >= 1; i--)
{
//...same as you did but pay attention to index
heap_size = heap_size-1;
Max_Heapify(heapArray,0,heap_size); //remember to use heap_size
}
//you declared void, no need to return anything
}
Build_Max_Heap function:
void Build_Max_Heap(int heapArray[], int heapSize) //should use heapSize
{
int n = SIZE;
for(int i = floor((n-1)/2); i >= 0; i--) //here should be 0 not 1
{
Max_Heapify(heapArray,i,heapSize); //should use heapSize
}
}
Max_Heapify function:
void Max_Heapify(int heapArray[],int i, int heap_size) //should use heap_size
{
//....here similar to what you did
if(( l < heap_size) && (heapArray[l] > heapArray[i]))
{ //^^compare with heap_size not SIZE
//skip identical part
}
if( (r < heaps_ize) && ( heapArray[r] > heapArray[largest]))
{
//same error as above
}
//skip identical part again
Max_Heapify(heapArray,largest, heap_size); //have to use heap_size
}
}
You may need to get a better understanding of the HeapSort algorithm from the pseudocode.
here
Build_Max_Heap(heapArray);
for(int i = n-1; i >= 2; i--)
{ ^^^^^
temp = heapArray[1];
heapArray[1] = heapArray[i];
heapArray[i] = temp;
heap_size = heap_size-1;
Max_Heapify(heapArray,1);
}
return;
}
you stop looping on i=2, decrease it to 1, don't take first element of heapArray which is indexed by 0
The Parent, Left and Right functions are fit for 1-based arrays. For 0-based you need to use:
int Parent(int i)
{
return (i - 1) / 2;
}
int Left(int i)
{
return (2 * i) + 1;
}
int Right(int i)
{
return 2 * (i + 1);
}
As you can check on example heap:
0
/ \
1 2
/ \ / \
3 4 5 6