Here is my implementation of deleting an element from Min Heap if the position of the element to be deleted is known:
void MinHeap::deleteKey(int i)
{
if(heap_size>0 && i<heap_size && i>=0)
{
if(heap_size==1)
heap_size--;
else
{
harr[i] = harr[heap_size-1];
heap_size--;
if(i<heap_size)
MinHeapify(i);
}
}
return ;
}
The function MinHeapify() is as follows:
void MinHeap::MinHeapify(int i)
{
int l = left(i);
int r = right(i);
int smallest = i;
if (l < heap_size && harr[l] < harr[i]) smallest = l;
if (r < heap_size && harr[r] < harr[smallest]) smallest = r;
if (smallest != i) {
swap(harr[i], harr[smallest]);
MinHeapify(smallest);
}
}
The structure of MinHeap is as follows:
struct MinHeap
{
int *harr;
int capacity, heap_size;
MinHeap(int cap) {heap_size = 0; capacity = cap; harr = new int[cap];}
int extractMin();
void deleteKey(int i);
void insertKey(int k);
int parent(int i);
int left(int i);
int right(int i);
};
This implementation of delete follows the logic that we swap the element to be deleted with the last element(I've just over-written the last element onto the element to be deleted as we don't need the element to be deleted), and then decreasing the size of the heap array. We finally Minheapify the heap from the position of the deleted element(which is now occupied by the last element).
This implementation is working for some but not all test cases.
What is the error with this approach?
Consider the following min heap:
0
/ \
4 1
/ \ / \
5 6 2 3
If you were to extract the node 5, with your current algorithm it would simply replace it with 3:
0
/ \
4 1
/ \ /
3 6 2
And since it has no children, nothing else is done. But this is not a min heap anymore, since 3 < 4, but 4 is a parent of 3.
To implement this you first need to sift-up the node, then sift-down (what you've called MinHeapify):
// Swap with parent until parent is less. Returns new index
int MinHeap::siftUp(int i)
{
while (i > 0)
{
int i_parent = parent(i);
if (harr[i_parent] < harr[i]) break;
swap(harr[i_parent], harr[i]);
i = i_parent;
}
return i;
}
// Swap with smallest child until it is smaller than both children. Returns new index
int MinHeap::siftDown(int i) {
while (true)
{
int l = left(i);
int r = right(i);
int smallest = i;
if (l < heap_size && harr[l] < harr[i]) smallest = l;
if (r < heap_size && harr[r] < harr[smallest]) smallest = r;
if (smallest == i) break;
swap(harr[i], harr[smallest]);
i = smallest;
}
return i;
}
void MinHeap::deleteKey(int i)
{
if (i<heap_size && i>=0)
{
if (i == heap_size-1)
heap_size--;
else
{
harr[i] = harr[heap_size-1];
heap_size--;
i = SiftUp(i);
SiftDown(i);
}
}
}
Related
I am trying to build a max heap out of a vector of size 10. It contains numbers 1-10. Yet my program will not set the largest value 10 to the largest variable because when comparing it exceeds my vector's range.
if ((l <= v.size()) && (v.at(l) > v.at(i)))
{largest = l;}
else { largest = i; }
if ((r <= v.size()) && (v.at(r) > v.at(largest))) // r at some point is 10. which exceeds v.
{largest = r;}
I tried setting an if statement around the code above that would catch the error, but then i get this:
INPUT: 1 2 3 4 5 6 7 8 9 10
OUTPUT: 9 8 7 4 5 6 3 2 1 10
Which is almost correct, but the 10 should be first. What can I do to make sure the heap builds correctly? Here is my full code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
vector<string> readFile(string fileName) { /* read in file. Works Fine.*/}
void display(vector<string>& v) {/*displays vector. works fine. */ }
inline int parent(int i){return i / 2; }
inline int left(int i) {return 2*i;}
inline int right(int i) {return 2*i + 1;}
void Max_Heapify(vector<string>& v, int i)
{
int largest;
int l = left(i);
int r = right(i);
i--;
if ((l <= v.size()) && (v.at(l) > v.at(i)))
{largest = l;}
else { largest = i; }
if ((r <= v.size()) && (v.at(r) > v.at(largest)))
{
largest = r;
}
if (largest != i)
{
string temp = v.at(i);
v.at(i) = v.at(largest);
v.at(largest) = temp;
Max_Heapify(v, largest);
}
}
void Build_Max_Heap(vector<string>& v, int length)
{
for (int i = (length / 2); i > 0; i--)
{
Max_Heapify(v, i);
}
}
int main() {
vector<string> vectorReadIn;
vector<string> sortedVector;
int x = 0;
string fileName = "C:/Users/user/Downloads/Algorithims/Perm Words/perm15k.txt";
vectorReadIn = readFile(fileName);
cout << "Unsorted file:" << endl;
display(vectorReadIn);
vectorReadIn.resize(vectorReadIn.size());
Build_Max_Heap(vectorReadIn, vectorReadIn.size());
display(vectorReadIn);
}
In addition to the comment by Igor Tandetnik, your calculations for left and right child are wrong. In a vector with index 0 being the first item, the root of your heap is at index 0. So the calculations for left and right child are:
left child: (2*x) + 1
right child: (2*x) + 2
The calculations you have are for a heap with the root at index 1.
Also, the loop in your Build_Max_Heap function needs to be:
for (int i = (length / 2); i >= 0; i--)
That is, you must check to see if the first item in the vector needs to be rearranged.
I've been asked to make an exercise using Backtracking, or Backtracking + Branch and Bound, where the imput data are n, m and a matrix(n x n). The n, represents a number of people, and the m, some people from the n. In the matrix, there are the distances among them, and the distances between i and j is different from the j and the i.
I am trying to get the maximum distance i can get from m nodes, that distance is the sum of the distance of all of them. For example, if i choose the node 1, 2 and 4, the result is the sums: distance(1, 2) + distance(2,1) + distance(2, 4) + distance(4, 2) + distance(1, 4) + distance(4, 1).
I have used Backtracking with Branch and Bound (iterative, not recursive), storing the nodes (structs where i store the current value and nodes used) that may get me to a solution. This nodes stores de lower and upper bound, i mean, the lower and higher solution I can obtain if i keep on using this node and his sons. From a node x, I generate all the possible nodes (nodes that are not used), and I check if this node may get me to a solution, if not, this node is discarded and erased.
The code i have implemented to make this, works, but it is really slowly. With low values of n and m, it is quick, but if i use higher numbers it is really slowly.
This is the main function and the others functions that are used:
void backtracking(int **matrix, int n, int m){
/////////////////////////////////////////////////////
/*
Part where I try to get the minimum/maximum that I can get from the beginning of the problem
*/
// Lists where I store the values from the matrix, sort from the minimum to the maximum, and from
// the maximum to the minimum. The values are the distances, I mean, the sum of matrix[i][j] and
// matrix[j][i].
list<int> listMinSums; // list of minimum sums
list<int> listMaxSums; // list of maximum sums
int nMinimumSums = floor((m*m - m)/2); // rounding down
int nMaximumSums = ceil((m*m - m)/2); // rounding up
/*
* m*m - m = Given m nodes, there are m*m - m sums.
*
* I count matrix[i][j] + matrix[j][i] as one, so there
* are (m*m - m)/2 sums.
*/
for (int i = 0; i < n; i++){
for (int j = 0; j < i; j++){
int x = (matrix[i][j] + matrix[j][i]);
// to differentiate from the minimum and maximum sums, I use false and true
aLista(listMinSums, x, nMinimumSums, false);
aLista(listMaxSums, x, nMaximumSums, true);
}
}
int min = 0;
int max = 0;
int contador = 0; // counting in every iteration to not surpassing the minimum/maximum sums
list<int>::iterator it = listMinSums.begin();
while (it != listMinSums.end() && contador < nMinimumSums){
min += *it;
it++;
contador++;
}
contador = 0;
list<int>::iterator it2 = listMaxSums.begin();
while (it2 != listMaxSums.end() && contador < nMaximumSums){
max += *it2;
it2++;
contador++;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// LLV = List of Live Nodes. Where I store the nodes that are going to
// guide me to the solution
list<nodo*> llv;
// I do not store the root node, i store the first n nodes, of the first level.
for (int i = 0; i < n; i++){
nodo *nod = new nodo(n);
nod ->level = 0;
//lower bound. It's the lower solution i can get from this node
nod ->ci = min;
// upper bound. The higher solution i can get from this node.
nod ->cs = max;
// estimated benefit. If i have to choose from one node or another, i choose the one with higher
nod ->be = (min+max)/2;
// The node i is used
nod ->used[i] = true;
// Inserting this node to the list of live nodes.
insert(llv, nod);
}
int solution = 0; // Initial solution
int c = min; // c = variable used to not use a node and his "sons", anymore
while (!empty(llv)){
nodo *x = erase(llv, n); // erasing the node with the highest estimated benefit from the llv.
if (x ->cs > c){
for (int i = 0; i < n; i++){ // Creating every son of the x node...
if (!(x ->used[i])){ // ... that has not being used yet
nodo *y = new nodo(n);
y ->level = x ->level + 1;
for (int j = 0; j < n; j++){
y ->used[j] = x ->used[j];
}
y ->used[i] = true;
// Adding the values. For example, if node 1 and 2 were inserted, and this is the node 4,
// adding matrix[1][4]+matrix[4][1]+matrix[2][4] + matrix[4][2]
int acum = 0;
for (int k = 0; k < n; k++){
if (k != i && consult(x ->used, k))
acum += matrix[i][k] + matrix[k][i];
}
y ->bact = x ->bact + acum;
// Getting the lower and upper bound of this node y.
cotas(y, x, i, y ->level, n, matrix);
y ->be = (y ->ci + y ->cs)/2;
// Node where i can get the solution
if (y ->level == (m-1) && y ->bact > solution){
solution = y ->bact;
if (y ->bact > c)
c = y ->bact;
}
// Checking if i can update c
else if (y ->level != (m-1) && y ->cs > c){
insert(llv, y);
if (y ->ci > c)
c = y ->ci;
}
else{
// i cannot use this node anymore, so i delete it.
delete y;
}
}
}
}
}
cout << solution << endl;
liberacionMemoria(matrix, n); // freeing the memory used in the matrix
}
void liberacionMemoria(int **matriz, int n){
for (int i = 0; i < n; i++)
delete[] matriz[i];
delete[] matriz;
}
void insert(list<nodo*> &t, nodo *x){
list<nodo*>::iterator it= t.begin();
t.insert(it, x);
}
/*
* Getting the node with hightest estimated benefit from the list of live nodes
* */
nodo* erase (list<nodo*> &t, int n){
nodo* erased = new nodo(n);
erased ->level = -1;
erased ->be = -1;
list<nodo*>::iterator it= t.begin();
list<nodo*>::iterator it2;
while (it != t.end()){
nodo* aux = *it;
if (aux ->be > erased ->be){
it2 = it;
erased = aux;
}
else if (aux ->be == erased ->be && aux ->level > erased ->level){
it2 = it;
erased = aux;
}
it++;
}
t.erase(it2);
return erased;
}
/*
* Checking if in the array of nodes used, the node in the x position it's used
* */
bool consult(bool *nodesUsed, int x){
if (nodesUsed[x])
return true;
return false;
}
bool empty(list<nodo*> &t){
list<nodo*>::iterator it= t.begin();
return (it==t.end());
}
bool aLista(list<int> &t, int x, int m, bool MayorAMenor){
list<int>::iterator it = t.begin();
int contador = 0;
while (it != t.end() && contador < m){
if (!MayorAMenor){ // lower to upper
if (*it > x){
t.insert(it, x);
return true;
}
}
else{
if (*it < x){
t.insert(it, x);
return true;
}
}
contador++;
it++;
}
if (it == t.end() && contador < m){
t.insert(it, x);
return true;
}
return false;
}
void cotas(nodo *sonNode, nodo *fatherNode, int elegido, int m, int n, int **matriz){
int max = 0;
int min = 999;
// Getting the sums from the chosen node with the already used
for (int i = 0; i < n; i++){
if (consult(sonNode ->used, i)){
if (elegido != i){
int x = matriz[i][elegido] + matriz[elegido][i];
if (x > max)
max = x;
if (x < min)
min = x;
}
}
}
min *= (m-1);
max *= (m-1);
min += fatherNode -> bact;
max += fatherNode -> bact;
sonNode -> ci = fatherNode ->ci - min;
sonNode -> cs = fatherNode ->cs - max;
}
I think, that the reason of going really slow with n and m a bit high, it is really slowly, it is because of the upper and lower bounds of the nodes, that are not accurate, but i don't know how to make it better.
I've been many days thinking how to do it, and trying to, but nothing works.
Here there are some examples:
Given an n = 4 and m = 2 and the following matrix:
0 3 2 4
2 0 4 5
2 1 0 4
2 3 2 0
the result is 8. This works and it is quickly.
But with n = 40 and m = 10 it never ends...
I hope someone may help me. Thanks.
****EDIT******
I may not have explained well. My doubt is, how can i know, from a node x, the less and the maximum I can get.
Because, the length of the solution nodes depends on m, but the solution changes if i choose some nodes or others, and I don't know how to be sure, of obtaining the less and the maximum from a node, but being accurate, to be able to cut the others branchs that do not guide me to a solution
I am trying to solve this question:
http://www.spoj.com/problems/FINDPATH/
Don't know where it's going wrong.
Firstly i am ignoring all the a[i] which are not divisors of destination, i.e., N
I am maintaining a map which maps each number to its parent and distance from root.
Then my idea is that i will be doing a bfs from '1' and then,
I am considering only those (q.top() * a[i]) that are <= N,
Then if queue contains (q.top() * a[i]) update the distance of (q.top() * a[i]) if distance(q.top()) + 1 < distance(q.top() * a[i])
else if the distances are equal then, if (q.top() < parent(q.top() * a[i]))
then update update parent(q.top() * a[i]) = q.top()
else if queue doesn't contain (q.top() * a[i]) then i am simply pushing it in queue.
Finally if a node N is present in the map then i print the distance and then the path using backtracking.
Here is my code:
int main() {
ll int n, m;
ll int x, top;
map<ll int, pair<ll int, ll int> >::iterator it, topit;
while (scanf("%lld %lld", &n, &m) != EOF) {
ve(ll int) v;
lp (i, 0, m) {scanf("%lld", &x); if (n % x == 0) v.pb(x);}
m = v.size();
map<ll int, pair<ll int, ll int> > s;
s.insert(mp(1, mp(1, 0)));
queue<ll int> q;
q.push(1);
while (!q.empty()) {
top = q.front();
q.pop();
topit = s.find(top);
lp (i, 0, m) {
if (top * v[i] <= n) {
it = s.find(top * v[i]);
if (it != s.end()) {
if ((*it).second.second > (*topit).second.second + 1) {
(*it).second.second = (*topit).second.second + 1;
(*it).second.first = top;
} else if ((*it).second.second == (*topit).second.second + 1) {
if (top < (*it).second.first) (*it).second.first = top;
}
} else {
s.insert(mp(top * v[i], mp(top, (*topit).second.second + 1)));
q.push(top * v[i]);
}
}
}
}
it = s.find(n);
ve(ll int) ans;
ans.pb(n);
if (it == s.end()) {
printf("-1\n");
} else {
printf("%lld\n", (*it).second.second);
while ((*it).second.first != 1) {
ans.pb((*it).second.first);
it = s.find((*it).second.first);
}
ans.pb((*it).second.first);
lpd (i, ans.size() - 1, 0) printf("%lld ", ans[i]);
printf("\n");
}
}
return 0;
}
Note: 1) lp (i, 0, m) : for (int i = 0; i < m; i++)
2) pb : push_back
3) ll : long long
4) lpd(i, n, 0) : for (int i = n; i>= 0; i--)
Is there any error in my approach ?
Below is my C++ code for inserting into a heap. The value for k is inserted but it's inserted at the bottom. I expected it to heapify with that while loop.
void Insert(heap1* myHeap, int k)
{
(myHeap->size)++;
int i = myHeap->size;
while (i > 1 && myHeap->H[i/2].key < k)
{
myHeap->H[i].key = myHeap->H[i/2].key;
i = i/2;
}
myHeap->H[i].key = k;
}
I do have a heapify procedure that I tried to use for this before this attempt that I know works within my other heap procedures. I just can't get it to work within Insert so I went with the above route. Below is heapify just in case its useful:
void heapify(heap1* myHeap, int i)
{
int l = 2 * i;
int r = 2 * i + 1;
int largest;
if (l <= myHeap->size && myHeap->H[l].key > myHeap->H[i].key)
largest = l;
else
largest = i;
if (r <= myHeap->size && myHeap->H[r].key > myHeap->H[largest].key)
largest = r;
if (largest != i)
{
myHeap->H[i].key = myHeap->H[i].key + myHeap->H[largest].key;
myHeap->H[largest].key = myHeap->H[i].key - myHeap->H[largest].key;
myHeap->H[i].key = myHeap->H[i].key - myHeap->H[largest].key;
heapify(myHeap, largest);
}
}
If someone could lead me in the right direction on how to get it to restore its heap properties, I would largely appreciate it.
try using this code:
void insert(int heap[], int *n, int item){
(*n)++;
heap[*n] = item;
reheapify_upward(heap, *n);
}
void reheapify_upward(int heap[],int start){
int temp,parent;
if(start>1){
parent=start/2;
if(heap[parent]<heap[start]){
temp=heap[start];
heap[start]=heap[parent];
heap[parent]=temp;
reheapify_upward(heap,parent);
}
}
}
The program compiles and runs properly. A list of integers is read from an input file, but the output displays those numbers without any changes. I expect them to be sorted from least to greatest. For reference, I am trying to implement a version similar to the example on wikipedia.
// arrA contains items to sort; arrB is an array to work in
void mergesort(int *arrA, int *arrB, int first, int last) {
// a 1 element array is already sorted
// make increasingly longer sorted lists
for (int width = 1; width < last; width = 2 * width) {
// arrA is made up of 1 or more sorted lists of size width
for (int i = 0; i < last; i += 2 * width) {
// merge two sorted lists
// or copy arrA to arrB if arrA is full
merge(arrA, i, min(i+width, last), min (i + 2 * width,
last), arrB);
} // end for
// now arrB is full of sorted lists of size 2* width
// copy arrB into arrA for next iteration
copy(arrB, arrA, last);
} // end for
} // end mergesort
void merge(int *arrA, int iLeft, int iRight, int iEnd, int *arrB) {
int i0 = iLeft, i1 = iRight;
// while either list contains integers
for (int j = iLeft; j < iEnd; j++) {
// if 1st integer in left list is <= 1st integer of right list
if (i0 < iRight && (i1 >= iEnd || arrA[i0] <= arrA[i1])) {
arrB[j] = arrA[i0];
i0 += 1;
} // end if
else { // right head > left head
arrB[j] = arrA[i0];
i0 += 1;
} // end else
} // end for
} // end merge
void copy(int *origin, int *destination, int size) {
for (int i = 0; i < size; i++) {
destination[i] = origin[i];
} // end for
} // end copy
int main() {
int size = 0, first = 0, *arrA, *arrB;
// input data
read(&arrA, &arrB, &size);
// sorting
mergesort(arrA, arrB, first, size);
// output
write(arrA, first, size);
// cleanup
delete [] arrA;
delete [] arrB;
}
input
33 9 -2
output
33 9 -2
I haven't looked very deeply at your code, but this if-statement seems a bit off to me:
if (i0 < iRight && (i1 >= iEnd || arrA[i0] <= arrA[i1])) {
arrB[j] = arrA[i0];
i0 += 1;
} // end if
else { // right head > left head
arrB[j] = arrA[i0];
i0 += 1;
} // end else
Surely, the whole point of a pair of if/else clauses is that you do different things in the if vs. the else part. As far as I can tell, it's identical here.