I am trying to make a random number generator for a uni project.
I am trying to implement a function to get the period of this list of numbers generated (how long before the numbers start to repeat).
When I compile this and run it it returns 507 (which is the correct period).
Yet about 50% of the time it returns a Segmentation Fault.
Any idea what is happening:
#include<iostream>
#include<fstream>
#include<vector>
#include<math.h>
#include<ctime>
using namespace std;
class Random
{
public:
// Constructor
Random(int a, int b, int m)
{
this->setMagicNumbers(a,b,m);
}
// Function to set the magic numbers of the random number generator
void setMagicNumbers(int a, int b, int m)
{
this->A = a;
this->B = b;
this->M = m;
}
// Function that returns a list of uniformly distributed random numbers
vector<double> GetUniform(int N, double initialValue = time(0))
{
double currentNumber = initialValue;
vector<double> RandomNumbers;
for(int i = 0; i <= N; i++)
{
currentNumber = fmod((this->A*currentNumber) + this->B, this->M);
RandomNumbers.push_back(currentNumber / this->M); // The number is normalised here
}
return RandomNumbers;
}
private:
int A, B, M;
};
class NumberList
{
public:
// Function to add an element to the list
void push(double x)
{
this->v.push_back(x);
}
// Function to pop an element off the list
double pop()
{
if(v.size() > 0)
{
int popped = v.back();
v.pop_back();
return popped;
}
else
{
cout << "Cannot pop element off empty list." << endl;
return 0;
}
return 0;
}
// Function to get the value at a given location on the list
double getAt(int i)
{
return this->v[i];
}
// Function to set the value at a given location on the list
void setAt(int i, double value)
{
this->v[i] = value;
}
// Function to find the size of the list
unsigned int size()
{
return this->v.size();
}
// Function to get the vector itself
vector<double> getvector()
{
return this->v;
}
// Function to set the value of the vector itself
void setVector(vector<double> vec)
{
this->v = vec;
}
// Function to print the list of numbers as coordinates to a data file
void printCoordinates()
{
ofstream data("coordinates.dat");
for(unsigned int i = 0; i <= this->v.size(); i++)
{
data << this->v[i] << " " << this->v[i + 1] << "\n";
}
data.close();
}
// Function to print the list of numbers to the terminal
void print()
{
for(unsigned int i = 0; i <= this->v.size(); i++)
{
cout << this->v[i] << endl;
}
}
// Function to get the period of the list of numbers
int getPeriod()
{
int i = 2;
while(true)
{
if(isPeriod(i) == true)
{
return i;
}
else
{
i = i + 1;
}
}
}
private:
// Vector to hold the values for the list
vector<double> v;
// Function to test if 'i' is the period of the list
bool isPeriod(int i)
{
for(int j = 0; j != (i-1); j++)
{
if(this->getAt(j) != this->getAt(i + j))
{
return false;
}
}
return true;
}
};
int main()
{
Random RandNumGenerator(100,104001,714025); // Create a new random number generator with given magic numbers
NumberList numbers; // Create a blank list of numbers
numbers.setVector(RandNumGenerator.GetUniform(10000)); // Add 10000 random numbers to the list
numbers.printCoordinates(); // Print out the random numbers as coordinates to a data file
cout << numbers.getPeriod() << endl; // Print out the period of the random number list
return 0;
}
Thanks in advance.
This line could cause a problem
for(unsigned int i = 0; i <= this->v.size(); i++)
With it you are using size as the last index, which is overflow, try changing it for this:
EDIT: change for this actually
for(unsigned int i = 0; i < this->v.size()-1; i++)
On the loop you are accessing the i+1 th element of the vector.
EDIT:
This probably wouldn't cause a crash but instead of creating N elements you are creating N+1
for(int i = 0; i <= N; i++)
Change if for this:
for(int i = 0; i < N; i++)
EDIT:
With fixes
#include<iostream>
#include<fstream>
#include<vector>
#include<math.h>
#include<ctime>
using namespace std;
class Random
{
public:
// Constructor
Random(long a, long b, long m)
{
this->setMagicNumbers(a,b,m);
}
// Function to set the magic numbers of the random number generator
void setMagicNumbers(long a, long b, long m)
{
this->A = a;
this->B = b;
this->M = m;
}
// Function that returns a list of uniformly distributed random numbers
vector<double> GetUniform(int N, double initialValue = time(0))
{
double currentNumber = initialValue;
vector<double> RandomNumbers;
for(int i = 0; i < N; i++)
{
currentNumber = fmod((this->A*currentNumber) + this->B, this->M);
RandomNumbers.push_back(currentNumber / this->M); // The number is normalised here
}
return RandomNumbers;
}
private:
long A, B, M;
};
class NumberList
{
public:
// Function to add an element to the list
void push(double x)
{
this->v.push_back(x);
}
// Function to pop an element off the list
double pop()
{
if(v.size() > 0)
{
int popped = v.back();
v.pop_back();
return popped;
}
else
{
cout << "Cannot pop element off empty list." << endl;
return 0;
}
return 0;
}
// Function to get the value at a given location on the list
double getAt(int i)
{
return this->v[i];
}
// Function to set the value at a given location on the list
void setAt(int i, double value)
{
this->v[i] = value;
}
// Function to find the size of the list
unsigned int size()
{
return this->v.size();
}
// Function to get the vector itself
vector<double> getvector()
{
return this->v;
}
// Function to set the value of the vector itself
void setVector(vector<double> vec)
{
this->v = vec;
}
// Function to print the list of numbers as coordinates to a data file
void printCoordinates()
{
ofstream data("coordinates.dat");
for(unsigned int i = 0; i < this->v.size()-1; i++)
{
data << this->v[i] << " " << this->v[i + 1] << "\n";
}
data.close();
}
// Function to print the list of numbers to the terminal
void print()
{
for(unsigned int i = 0; i < this->v.size(); i++)
{
cout << this->v[i] << endl;
}
}
// Function to get the period of the list of numbers
int getPeriod()
{
int i = 2;
while(true)
{
if(isPeriod(i) == true)
{
return i;
}
else
{
i = i + 1;
}
}
}
private:
// Vector to hold the values for the list
vector<double> v;
// Function to test if 'i' is the period of the list
bool isPeriod(int i)
{
std::cout << "trying period " << i << endl;
if (i >= v.size()) return true;
for(int j = 0; j < v.size()-1; j++)
{
if(this->getAt(j) == this->getAt(i + j))
{
std::cout << "value at j " << this->getAt(j) << "value at i+j " << this->getAt(i+j) <<endl;
return true;
}
}
return false;
}
};
int main()
{
Random RandNumGenerator(100,104001,714025); // Create a new random number generator with given magic numbers
NumberList numbers; // Create a blank list of numbers
numbers.setVector(RandNumGenerator.GetUniform(10000)); // Add 10000 random numbers to the list
numbers.printCoordinates(); // Print out the random numbers as coordinates to a data file
cout << numbers.getPeriod() << endl; // Print out the period of the random number list
return 0;
}
Played around with this a bit and I initially thought that your vector of doubles was somehow getting corrupted. I found that if you size it to the exact value that you want - which is a known value - the seg faults stop:
vector<double> RandomNumbers(N); // In GetUniform()
Running it through gdb was inconclusive as it looked as if the stack was getting corrupted. I also found that when I changed the push_back() just to take 0:
RandomNumbers.push_back(0.0);
instead of the normalised number, even without the initial size for the vector (above) it worked fine, suggesting an issue with one of the variables being used.
I also found that if I set currentNumber to 1, say, instead of calling fmod() - even with everything as it originally was, I got no seg faults:
currentNumber = 1;
This kind of suggests that it might be something to do with the use of fmod()
Interestingly, I then took out the call to push_back completely and found that it still had segfaults. Sorry I can't be much more help than that, but it certainly looks as if some kind of corruption is happening somewhere in this area.
In C++ index of array and vector will be from 0..size - 1, and you misused it all over your code(inside GetUniform, inside printCoordinates, ...) and beside that in printCoordinates you written this->v[i + 1] at last it will be converted to this->v[this->v.size() + 1] that is 2 index after last valid index.
But I think source of your error is in getPeriod and isPeriod, look at it you start from 0 to i - 1 and check if that index match item at index i + j, so if i become size() - 1 and size be 500, then in worse case you are accessing v[499 + 498] that is really large than last valid index and you certainly get a segmentation fault. Now to solve it check your index and never go beyond end of the vector size, that mean you should never use index > v.size() - 1
Related
I have a problem with my C++ code. I need to make the sum of the vectors component by component. For example, if I have A(2,1) and B(3,3) the result should be (5,4). I tried to do something but apparently I have a problem and I don't know what to do. The error is: ,,No member called push in std::_1vector" My code is:
#include <iostream>
#include "stack_base.h"
#include <vector>
using namespace std;
template<typename T>
class App {
public:
Stack<T> * stack;
App(Stack<T> &stack) {
this->stack = &stack;
}
T sum(){
Stack<T> *tempStack = stack;
T sum=0;
int size = stack->getTopLevel();
for(int i=0; i<=size; i++) {
sum+=tempStack->peek();
tempStack->pop();
}
return sum;
}
T substract(){
Stack<T> tempStack = *stack;
T substr=0;
for(int i=0; i<=stack->getTopLevel(); i++) {
substr-=tempStack.peek();
tempStack.pop();
}
return substr;
}
};
void display(vector<int> &v)
{
for(int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << "\n" << endl;
}
int main(){
using namespace std;
Stack<int> myStack;
App<int> a(myStack);
unsigned int i = 0;
std::vector<int> v1;
std::vector<int> v2;
// Populate v1 and v2 here
// Check that v1 and v2 have the same length
if (v1.size() != v2.size())
{
// error here
}
std::vector<int> v3; // This will hold the resulting vector
// Preallocate the necessary memory if you like here, but it
// isn't necessary and doesn't gain you much.
for (auto i = 0ul; i < v1.size(); ++i)
{
v3.push_back(v1[i] + v2[i]);
}
int x;
cout << "Enter five integer values for v1" << endl;
for(int i; i<5; i++)
{
cin >> x;
v1.push_back(x);
}
cout << "Enter five integer values for v2" << endl;
for(int i; i<5; i++)
{
cin >> x;
v2.push_back(x);
}
cout << "Size of Vector= " << v2.size() << endl;
display(v3);
return 0;
}
This is Stack:
#include <iostream>
using namespace std;
#define NMAX 30 // pre-processing directive
template<typename T>
class Stack {
private:
// an array of NMAX dimension
T stackArray[NMAX];
/* the top of the stack, representing the INDEX of last element of the
stackArray:0, 1, 2,....*/
int topLevel;
public:
void push(T x) {
//puts an element in the stack array
//check if the stack array has the maximum dimension
if (topLevel >= NMAX - 1)
{
cout<<"The stack is full: we have already NMAX elements!\n";
//exit the function without making anything
return;
}
/*add an element=> the index of the last element of the stack Array
increases and put the value of the new element in the stack array*/
stackArray[++topLevel] = x;
}
int isEmpty() {
//returns 1, if topLevel>=0, meaning the stack array has elements
// returns 0, otherwise
return (topLevel < 0);
}
T pop() {
// extracts and element from the stack array and returns the new top
if (isEmpty()) {
// the extraction is made only if the array is not empty
cout<<"The stack is empty! \n";
T x;
return x;
}
// the topLevel decreases and the new top is changed
return stackArray[--topLevel];
}
T peek() {
// returns the top of the stack
if (isEmpty()) {
// the extraction is made only if the array is not empty
cout<<"The stack is empty! \n";
T x;
return x;
}
return stackArray[topLevel];
}
void display(){
for(int i=0;i<=topLevel;i++)
cout<<stackArray[i];
}
bool search(T num){
for(int i=0; i<=topLevel;i++)
if(num==stackArray[i])
return true;
return false;
}
int getTopLevel(){
return topLevel;
}
Stack() { // constructor
topLevel = -1; // the stack is empty in the beginning
}
void sort(T s){
if (!isEmpty()) {
T x = Pop(s);
sort(s);
push(s, x);
}
}
~Stack() { // destructor
}
};
You are never adding any elements to your vector. In the preceding three lines, you attempt to access elements that do not exist, but the vectors only do bounds checking if you call the 'at' method instead of using the bracket notation. What are you trying to accomplish in that for-loop?
To add two vectors of the same length pair-wise, which is what I think you want, you can do this:
std::vector<int> v1;
std::vector<int> v2;
// Populate v1 and v2 here
// Check that v1 and v2 have the same length
if (v1.size() != v2.size())
{
// error here
}
std::vector<int> v3; // This will hold the resulting vector
// Preallocate the necessary memory if you like here, but it
// isn't necessary and doesn't gain you much.
for (auto i = 0ul; i < v1.size(); ++i)
{
v3.push_back(v1[i] + v2[i]);
// Debugging statement
std::cout << "Added " << v1[i] << " and " << v2[i] << " to get " << v3[i] << " for index " << i << std::endl;
}
I am writing a program that displays integer arrays. I set the size of the array, but I am wondering how I can ask the user the index of the array that they want listed. Say the const SIZE = 10, and the user wants to see the first three in the array. I want to also write an exception that catches the error if the user input is over the size of the array. If you need to see some code, let me know. Any help is appreciated!
intergerarray.h
class IntArray
{
private:
int *aptr; // Pointer to the array
int arraySize; // Holds the array size
void subscriptError(); // Handles invalid subscripts
public:
class OutOfBoundException
{
public:
int index;
OutOfBoundException(){};
int getInde() { return index; }
};
IntArray(int); // Constructor
IntArray(const IntArray &); // Copy constructor
~IntArray(); // Destructor
int size() const // Returns the array size
{
return arraySize;
}
int &operator[](const int &); // Overloaded [] operator
};
IntergerArray.cpp
IntArray::IntArray(int s)
{
arraySize = s;
aptr = new int[s];
for (int count = 0; count < arraySize; count++)
*(aptr + count) = 0;
}
IntArray::IntArray(const IntArray &obj)
{
arraySize = obj.arraySize;
aptr = new int[arraySize];
for (int count = 0; count < arraySize; count++)
*(aptr + count) = *(obj.aptr + count);
}
IntArray::~IntArray()
{
if (arraySize > 0)
delete[] aptr;
}
void IntArray::subscriptError()
{
cout << "ERROR: Subscript out of range.\n";
exit(0);
}
int &IntArray::operator[](const int &sub)
{
if (sub < 0 || sub >= arraySize)
subscriptError();
return aptr[sub];
}
driver file.cpp
int main()
{
int SIZE = 10;
//int index;
//cout << "enter an index";
//cin >> index;
IntArray table(SIZE);
for (int x = 0; x < SIZE; x++)
table[x] = x;
for (int x = 0; x < SIZE; x++)
cout << table[x] << " ";
cout << endl;
//table[SIZE + 1] = 0;
return 0;
}
Isn't this what you are trying to do? why so much code for such a simple problem?
const int arraySize = 10;
int array[arraySize];
int elementToDis;
do
{
std::cout << "Number of array elements to display: ";
std::cin >> elementToDis;
} while (elementToDis > arraySize || elementToDis < 0); // this is your exeption
for (int ccc(0); ccc < elementToDis; ++ccc)
std::cout << "Index " << ccc << ": " << array[ccc] << '\n';
I think you want to display all elements lower than an index value entered by the user :
Let array[] be the array name of size=10,you can get an index value (say l) from the user and use that value inside a for loop for printing all elements in index lower than l
int array[size]
void disp_in(int l)
{
if(l>=size) // if l greater than or equal to size (as index start at 0)
throw l;
else
{
cout<<"Elements : ";
for(int i=0;i<=l;i++) //if we have say l=2 ,array values in indexes 0,1and 2 will be displayed
cout<<array[i];
}
}
int main ()
{
int l;
cout<<"Enter index : ";
cin>>l; //till this index value, the array value will be displayed
try
{
disp_in(l);
}
catch(int e)
{
cout<<"Index value greater than max index";
}
return 0;
}
You could try something like this:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
void print_numbers( const std::vector<int>& array, int nNumbers, const char* pszSeparator )
{
if ( nNumbers > static_cast<int>(array.size()) )
{
throw std::exception();
}
std::copy( array.begin(), array.begin() + nNumbers, std::ostream_iterator<int>( std::cout, pszSeparator ) );
}
int main()
{
std::vector<int> array( 10 );
//Just for testing
{
int n = 0;
auto generator = [n]() mutable
{
return n++;
};
std::generate_n( array.begin(), array.size(), generator );
}
try
{
print_numbers(array, 11, "\n");
}
catch ( std::exception e )
{
std::cout << "Error message..." << std::endl;
}
return 0;
}
The assignment was to build a function to check if numbers in a range are armstrong numbers, and to add them in a vector. There are some problems when I call main, it won't execute the for loop part. I kinda think that the function is alright, because when I just call the function, there are no errors. The code is below, and I hope that you can help me.
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
std::vector<int> ArmstrongoviBrojevi (int , int );
std::vector<int> ArmstrongoviBrojevi (int p, int q) {
//function start
int z=0;
if (p<0){
std::vector<int> dodajVrijednost;
for (int i=1;i<=q;i++){
std :: string a = std:: to_string(i);
//check for length
int duzina = a.length();
int sum=0;
//check if number if armstrong
while (i>0){
int cifra=i%10;
i/=10;
sum+=pow(cifra,duzina);
}
//add to the vector
if (sum==i){
dodajVrijednost[z];
z++;
}
return dodajVrijednost;
}
}
}
//main
int main() {
std::cout << "Zadaća 1, Zadatak 1";
int a,b;
std::cout << "Molim vas unesite 2 broja" << std::endl;
std::cin >> a>>b;
std::vector<int>kopija ;
for (int g=0;g<ArmstrongoviBrojevi(a,b).size();g++){
if (g!=int(ArmstrongoviBrojevi(a,b).size())-1){
std::cout << ArmstrongoviBrojevi(a,b)[g] <<","<< std::endl;
}
else
std::cout << ArmstrongoviBrojevi(a,b)[g] << std::endl;
}
return 0;
}
There are at least two error in the ArmstrongoviBrojevi function. I guess the main one is that when condition p < 0 return false you don't return any value, but in main still trying to access it. To fix it you could declare dodajVrijednost outside of the if block and return value after it
std::vector<int> dodajVrijednost;
if (p < 0) {
...
}
return dodajVrijednost;
Another one is that dodajVrijednost[z]; should be dodajVrijednost.push_back(z);. Because you don't allocate memory for the vector somewhere before there is no element on index z. And statement dodajVrijednost[z]; alone does not make any sense.
I would also modify the main function, because now you recalculate your vector each time, it would be better to calculate result once.
std::vector<int> armstrongoviBrojevi = ArmstrongoviBrojevi(a,b);
for (int g=0;g<armstrongoviBrojevi.size();g++){
if (g!=armstrongoviBrojevi.size()-1){
std::cout << armstrongoviBrojevi[g] <<","<< std::endl;
}
else
std::cout << armstrongoviBrojevi[g] << std::endl;
}
/* Java program to find Armstrong numbers in a range */
class A{
public static void main(String[] args) {
int starting_number = 1;
int ending_number = 99999;
int c = 0;
for (int i = starting_number; i <= ending_number; i++) {
if (isArmstrong(i)) {
c++;
if(c==1)
{
System.out.print(i);
}
else{
System.out.print(", "+i);
}
} else {
}
}
}
public static boolean isArmstrong(int n) {
int no_of_digits = String.valueOf(n).length();
int sum = 0,s=0;
int value = n;
for (int i = 1; i <= no_of_digits; i++) {
int digit = value % 10;
value = value / 10;
sum = sum + (int) Math.pow(digit, no_of_digits);
}
if (sum == n) {
s=s+sum;
return true;
} else {
return false;
}
}
}
I want sum of it
I've got a bigint class that uses an array called SafeArray that I created in a different class. I couldn't use vectors. The set and get function calls are from the SafeArray class. Get takes an int parameter for array position and set takes 2 int parameters (one for position and one for value). All methods in this bigint class work fine (we don't have to account for negative integers) except my compare method needs work. I want it to be able to compare two bigints and if the (const bigint and &A) number is larger than the other (cout 1) if it is smaller (cout 2) if they are the same (cout 0). Any help with this method would be greatly appreciated. Thanks
int size = 35; //will get bigger, small now just for testing
class bigint
{
SafeArray<int> *arr;
public:
bigint() //initializes to zero
{
arr = new SafeArray<int>;
for(int i =0;i < size; i++)
arr->set(i,0);
}
void print() //prints numbers without zeroes in front
{
bool start_num=false;
for(int i = 0;i <arr->get_size() ;i++)
{
if(arr->get(i)!=0 && start_num==false )
{start_num=true;
cout << arr->get(i);}
else if(start_num==true)
cout<<arr->get(i);
}
cout<<endl;
}
void assign(const bigint &A) //
{
for(int i=0;i<arr->get_size();i++)
{ //Ways to initialize stuff
arr->set(i,A.arr->get(i));
}
}
void assign(int num) //
{
for(int i = arr->get_size()- 1; i >= 0; i--)
{
arr->set(i,num%10);
num /=10;
}
}
void assign(string num) //
{
long len = num.length();
int j=arr->get_size()-1;
for(long i=len-1;i>=0;i--)
{
arr->set(j,num[i]-48);
j--;
}
}
void add(const bigint &A) //add big ints
{
int carry=0;
for(int i=size-1;i>=0;i--)
{
int result = arr->get(i)+A.arr->get(i)+carry;
arr->set(i,result%10);
carry=result/10;
}
}
void subtract(const bigint &A) //subtract big ints
{
int borrow = 0;
for(int i=size-1; i >= 0; --i)
{
int result=((arr->get(i) - A.arr->get(i) - borrow));
if(result < 0)
{
arr->set(i, result + 10);
borrow = 1;
}
else
{
arr->set(i, result);
borrow = 0;
}
}
}
//int compare(const bigint &A) //compare big ints
// {
//
// for(int i<size;i>0;i--)
// {
// if(A.arr->get(i) > arr->get(i))
// {
// return 1;
// }
// else if(A.arr->get(i) < arr->get(i))
// {
// return -1;
// }
// else
// {
// return 0;
// }
// }
//
// }
};
int main()
{
bigint a, b, c;
a.assign("12345678"); //for testing
b.assign("12345678");
//a.compare(b);
a.print();
c.assign(24691357); // 696969 is small enough to be an int.
a.add(b); // a += b;
a.subtract(c); // a -= b;
a.print();
return 0;
}
The logical problem with comparison is that you're returning two numbers as equal at the first digit that is equal.
You need instead to keep comparing next digit in that case and return 0 only if all of them are equal.
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] << " ";
}
}