I just wrote a code to build a Huffman Tree using MinHeap. When testing I want to output its traversal result.
The algorithm is simple, but my code can't get the right answer. It's strange that the output was different when I set different breakpoints. For instance, it depends on if I set a break point in the loop, such as line 165 input_list.insert(*parent);.
The test input was
4 //number of nodes.
1 1 3 5 //weight of each node.
and the output when debugging it with a breakpoint in the loop is
5
10
1
2
1
5
3
that is correct. But when I just run it without debug, it even didn't have any output. Does anyone know how to explain it?
#include <iostream>
#include <vector>
using namespace std;
#define max_size 100
int sum=0;
class huffman_node
{
public:
int weight;
huffman_node* left_child;
huffman_node* right_child;
huffman_node(){}
huffman_node(int w, huffman_node* l, huffman_node* r):
weight(w),left_child(l),right_child(r) {}
};
vector <huffman_node> node_list;
class minheap
{
public:
minheap()
{
heap=new huffman_node [max_size];
current_size=0;
}
~minheap()
{
delete []heap;
}
void siftdown(int start, int m)
{
int i=start;
int j=2*i+1;
huffman_node temp=heap[i];
while(j<=m)
{
if(j<m && heap[j+1].weight<heap[j].weight)
{
++j;
}
if(temp.weight<=heap[j].weight)
{
break;
}
else
{
heap[i]=heap[j];
i=j;
j=2*i+1;
}
}
heap[i]=temp;
}
void siftup(int start)
{
int j=start;
int i=(j-1)/2;
huffman_node temp=heap[j];
while(j>0)
{
if(heap[i].weight<=temp.weight)
{
break;
}
else
{
heap[j]=heap[i];
j=i;
i=(j-1)/2;
}
heap[j]=temp;
}
}
bool insert(const huffman_node& input)
{
if(current_size==max_size)
{
cout<<"minheap full"<<endl;
return false;
}
heap[current_size]=input;
siftup(current_size);
++current_size;
return true;
}
bool remove_min(huffman_node& output)
{
if(!current_size)
{
cout<<"minheap empty"<<endl;
return false;
}
output=heap[0];
heap[0]=heap[current_size-1];
--current_size;
siftdown(0,current_size-1);
return true;
}
private:
huffman_node* heap;
int current_size;
};
void route_length(huffman_node* &root,int depth)
{
if(root!=NULL)
{
// if(root->left_child==NULL&&root->right_child==NULL)
// {
// sum+=depth*root->weight;
// }
route_length(root->left_child,depth+1);
cout<<root->weight<<endl;
route_length(root->right_child,depth+1);
}
else
{
return;
}
}
int main()
{
minheap input_list;
int n;
cin>>n;
for(int i=0;i<n;++i)
{
int key;
cin>>key;
huffman_node input(key,NULL,NULL);
input_list.insert(input);
cin.get();
}
huffman_node* root;
for(int i=0;i<n-1;++i)
{
huffman_node* parent;
huffman_node out1;
huffman_node out2;
input_list.remove_min(out1);
input_list.remove_min(out2);
node_list.push_back(out1);
node_list.push_back(out2);
parent=new huffman_node(out1.weight+out2.weight,&node_list[node_list.size()-2],&node_list[node_list.size()-1]);
input_list.insert(*parent);
root=parent;
}
route_length(root,0);
// cout<<sum<<endl;
return 0;
}
The problem is that you are using pointers to elements of a vector<huffman_node> and storing these in your data structure (i.e. left and right members of the huffman_node object).
The thing that is randomly killing your program is that std::vector moves values around in memory when you append to it. The contents of the elements of the vectors are preserved, but the location is not. Once it moves the elements, the memory where the vector used to be can be overwritten by whatever (i.e. gdb needs heap memory too) and now the pointers are pointing to garbage.
As a quick sanity check, you can make your code not crash by reserving space in your node_list by calling
node_list.reserve(max_size*2);
in the beginning of main. This is not the right way of developing this piece of code further, but should illustrate the problem.
It would be better if your node_list was a vector<huffman_node*> instead. Or if you changed the left/right members to be vector indices instead of pointers.
Related
I was trying to solve Reduce String on codechef which says
Give a string s of length l, and a set S of n sample string(s). We do reduce the string s using the set S by this way:
Wherever Si appears as a consecutive substring of the string s, you can delete (or not) it.
After each deletion, you will get a new string s by joining the part to the left and to the right of the deleted substring.
I wrote a recursive function as follows:-
Basically what i am doing in my code is either don't delete the character or delete it if it is part of any substring but it is giving wrong answer.
#include <bits/stdc++.h>
using namespace std;
#define mx 255
int dp[mx];
unordered_map<string,int> sol;
void init(int n)
{
for(int i=0;i<n;i++)
{
dp[i]=-1;
}
}
int solve(string str,int low,int high,vector<string> smp)
{
if(low>high)
{
return 0;
}
if(dp[low]!=-1)
{
return dp[low];
}
int ans=1+solve(str,low+1,high,smp);
for(int i=low;i<high;i++)
{
string tem=str.substr(low,i-low+1);
for(int j=0;j<smp.size();j++)
{
cout<<"low i high str"<<low<<" "<<i<<" "<<high<<" "<<smp[j]<<" "<<tem<<endl;
if(tem.compare(smp[j])==0)
{
ans=min(ans,solve(str,i+1,high,smp));
}
}
}
return dp[low]=ans;
}
signed main()
{
sol.clear();
string str;
vector<string> smp;
int n;
cin>>str;
cin>>n;
for(int i=0;i<n;i++)
{
string tem;
cin>>tem;
smp.push_back(tem);
}
int len=str.length();
init(len+1);
cout<<solve(str,0,len-1,smp)<<endl;
return 0;
}
PS:
link to the question
This question is toughest(seen so far) and most beautiful(again seen so far) question based on DP ON INTERVALS.
The initial code would definitely not work since it only considers single pass on the string and would not consider remaining string after deleting the patterns again and again.
There are 3 cases:-
Case 1 Either character is not deleted.
Case 2It is deleted as a part of contiguous substring.
Case 3It is deleted as a part of subsequence that matches any word given in the set of patterns and everything that is not part of that subsequence is deleted first as a substring(which again belongs to set of words).
The third part is the most tricky and requires enough thinking and is even tougher to implement too.
So for every substring we need to check whether this substring can be completely destroyed or not.
The function compute_full_recur() is the function that ensures that whether substring can be deleted either in Case 2 or Case 3.
The function compute_full takes care of Case 1.And finally this code will not run on codechef link since all the function are recursive with memoization but to verify the code is working i Have run it on Problem Reducto of Hackerrank which is exact similar with lower constraints.Download test cases and then run on test cases on your PC for verifying.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
#define mx 252
#define nx 40
bool full[mx][mx],vis[mx][mx],full_recur[mx][mx][nx][nx];
int ans[mx];
void init()
{
for(int i=0;i<mx;i++)
{
for(int j=0;j<mx;j++)
{
full[i][j]=false,vis[i][j]=false;
}
}
for(int i=0;i<mx;i++)
{
ans[i]=-1;
}
for(int i=0;i<mx;i++)
{
for(int j=0;j<mx;j++)
{
for(int k=0;k<nx;k++)
{
for(int l=0;l<nx;l++)
{
full_recur[i][j][k][l]=false;
}
}
}
}
}
bool compute_full_recur(string str,int low,int high,vector<string> pat,int idx,int len)
{
if(low>high&&len==pat[idx].length())
{
return true;
}
if(low>high&&len<pat[idx].length())
{
full_recur[low][high][idx][len]=false;
return false;
}
if(str[low]==pat[idx][len]&&compute_full_recur(str,low+1,high,pat,idx,len+1))
{
return full_recur[low][high][idx][len]=true;
}
for(int i=low+1;i<=high;i++)
{
if(str[low]==pat[idx][len]&&full[low+1][i]&&compute_full_recur(str,i+1,high,pat,idx,len+1))
{
return full_recur[low][high][idx][len]=true;
}
}
full_recur[low][high][idx][len]=false;
return false;
}
void compute_full(string str,int low,int high,vector<string> pats)
{
if(low>high)
{
return;
}
if(vis[low][high])
{
return;
}
vis[low][high]=true;
compute_full(str,low+1,high,pats);
compute_full(str,low,high-1,pats);
for(int i=0;i<pats.size();i++)
{
if(!full[low][high])
full[low][high]=compute_full_recur(str,low,high,pats,i,0);
}
}
int compute_ans(string str,int low,int high)
{
if(low>high)
{
return 0;
}
if(ans[low]!=-1)
{
return ans[low];
}
int sol=1+compute_ans(str,low+1,high);
for(int i=low+1;i<=high;i++)
{
if(full[low][i]==true)
{
sol=min(sol,compute_ans(str,i+1,high));
}
}
return ans[low]=sol;
}
signed main()
{
int t;
cin>>t;
while(t--)
{
string str;
int n;
vector<string> pats;
cin>>n>>str;
for(int i=0;i<n;i++)
{
string tem;
cin>>tem;
pats.push_back(tem);
}
init();
compute_full(str,0,str.length()-1,pats);
cout<<compute_ans(str,0,str.length()-1)<<endl;
}
return 0;
}
#include<iostream>
#include<vector>
using namespace std;
class Stack
{
public:
int top;
vector<int> v;
Stack(int size)
{
top=0;
cout<<"Enter the values"<<endl;
for(int i=0; i<size; i++)
{
int val;
cin>>val;
v.push_back(val);
top++;
}
}
void push(int val)
{
v.push_back(val);
top++;
}
int pop()
{
int x=v[top];
top--;
return x;
}
void disp()
{
for(int j=top; j<=0; j--)
cout<<v[j]<<' ';
}
};
int main()
{
Stack s(3);
int k=s.pop();
cout<<k;
return 0;
}
I am trying to learn the basics of OOP.
Here, my Stack constructor and push function are working fine, but there is a problem with the pop and disp functions.
I'm assuming that I am using an incorrect syntax to access the elements of a vector(maybe?). Can anyone tell me where I am going wrong?
Also, the value of k always comes out to be 0.
You can use the vector functions
int k = s.back();
s.pop_back();
cout << k;
more informationhttp://www.cplusplus.com/reference/vector/vector/back/
You have a off-by-one index error.
The way you have implemented your class, when there are N items in the stack, the value of top is N.
Hence, top is not a valid index to access the elements of v. You can use:
int pop()
{
int x=v[top-1];
top--;
return x;
}
or
int pop()
{
top--;
int x=v[top];
return x;
}
As some of the other answers say, you can use the built-in vector functions to do these things (see pop_back and back.
However, if you want to define your own, I would use the vector.at(index) function. Addressing the values with the index as you have works, but it doesn't do any bounds checking at() does. Which would solve your problem above where your index isn't correct for the zero-based indexing of a vector.
I'm trying to make a 15 puzzle game by swapping an element with the position of a blank element. I've made this code, but it only swaps when the tile is to the right or below for some reason.
void moveTile(int gameBoard[][SIZE], int nextMove, int &blanki, int &blankj)
{
int temp=nextMove;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(gameBoard[i][j]==nextMove)
{
gameBoard[i][j]=gameBoard[blanki][blankj];
gameBoard[blanki][blankj]=temp;
blanki=i;
blankj=j;
}
}
}
}
Walk thru it in a debugger. You'll see that after a swap is made, you keep going and searching. In the case where the tile is above or left, you'll swap a second time.
You need to stop searching once you've made a swap.
I have updated it to include a stop, now the code does not iterate.
void moveTile(int gameBoard[][SIZE], int nextMove, int &blanki, int &blankj)
{ bool stop=false;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
while(!stop)
{if(gameBoard[i][j]==nextMove)
{
int temp=gameBoard[i][j];
gameBoard[i][j]=gameBoard[blanki][blankj];
gameBoard[blanki][blankj]=temp;
blanki=i;
blankj=j;
stop=true;
}
}
}
}
}
#ifndef BINARY_TREE_H
#define BINARY_TREE_H
#include<iostream>
#include<vector>
using namespace std;
class Binary_Tree;
static int levelCount=0;
extern vector<vector<Binary_Tree*>> vec;
extern vector<Binary_Tree*> tempVec;
class Binary_Tree
{
public:
Binary_Tree()
{
childNum=0;
data=0;
level=0;
prev=NULL;
next[0]=NULL;
next[1]=NULL;
};
Binary_Tree(int d)
{
childNum=0;
data=d;
level=0;
prev=NULL;
next[0]=NULL;
next[1]=NULL;
levelCount++;
}
void insert_node(int,int,int);
int get_level();
int get_childCount();
friend int set_childNum(Binary_Tree*);
private:
int childNum;
int data;
int level;
Binary_Tree *prev;
Binary_Tree *next[2];
};
#endif // BINARY_TREE_H
Here is the implementation file
#include<iostream>
#include<cmath>
#include "Binary_Tree.h"
using namespace std;
void Binary_Tree::insert_node(int lev, int d, int sib)
{
if(vec.empty())
{
cout<<"You Have to create Root first";
}
else
{
if(set_childNum(vec[lev][sib-1])==0)
{
cout<<"Child cant be created parent Node already has two childs.";
}
else
{
childNum=set_childNum(vec[lev][sib-1]);
data=d;
level=lev+1;
prev=vec[lev][sib];
next[0]=NULL;
next[1]=NULL;
tempVec.clear();
for(int i=0; i<pow(2,(lev+1)); i++)
{
if(i==childNum-1)
{
tempVec.push_back(this);
}
else
tempVec.push_back(vec[lev][i]);
}
vector<vector<Binary_Tree*>>::iterator itr=vec.begin()+(lev+1);
vec.erase(itr);
vec.insert(itr,tempVec);
}
}
}
int set_childNum(Binary_Tree *lstNdAdr)
{
if(lstNdAdr->get_childCount()==0)
return 1;
else if(lstNdAdr->get_childCount()==1)
return 2;
else
return 0;
}
int Binary_Tree::get_level()
{
return level;
}
int Binary_Tree::get_childCount()
{
if(next[0]==NULL)
{
return 0;
}
else if(next[0]!=NULL && next[1]==NULL)
{
return 1;
}
else
{
return 2;
}
}
MAIN.cpp
#include <iostream>
#include<cmath>
#include"Binary_Tree.h"
using namespace std;
vector<vector<Binary_Tree*>> vec;
vector<Binary_Tree*> tempVec;
int main()
{
Binary_Tree tree;
here:
cout<<"Enter your Choice:1.Create Root Of Tree\n"
<<"2.Insert node\n"<<endl;
int choice;
cin>>choice;
switch(choice)
{
case 1:
{
int d;
cout<<"Enter Data to insert: ";
cin>>d;
Binary_Tree treeDummy(d);
tree=treeDummy;
tempVec.push_back(&tree);
vec.push_back(tempVec);
}
break;
case 2:
{
int lev;
int sibbling;
int d;
cout<<"Enter at which level and data and parent's sibling-no.: ";
cin>>lev;
cin>>d;
cin>>sibbling;
if(sibbling>pow(2,lev))
cout<<"Illegal Sibbling Number."<<endl;
else
tree.insert_node(lev,d,sibbling);
}
break;
}
int x;
cin>>x;
if(x==5)
{
cout<<endl<<endl;
goto here;
}
return 0;
}
in above code i am trying to create a binary tree type structure which can be manipulated and traversed dynamically that is any node can be inserted and can be removed at run time (although its incomplete because i am stuck at a problem). While pushing back the tempVec vector the code produces a segmentation fault and i am also doubtful in passing the object stored in vetcor> vec to the functions in the implementation (I am new to Stl and first time dealing with vector of vectors containing pointer to the class types)
The nested vector's entries are only filled if i is set to 1. But you attempt to access its element [0][0] regardless. You have out of bounds access when i is not 1.
There are numerous problems present in your code, that and combined with the poor style and formatting makes it not so fun to debug.
Binary_Tree treeDummy(d);
tree = treeDummy;
tempVec.push_back(&tree);
I'm not sure what you're trying to do here but the above looks wrong. You are shallow copying treeDummy's data over to tree. You'll lose the link to whatever child node tree points to. Afterwards you're pushing that same tree instance into your temporary vector. That means all the elements in your vector ends up pointing to the local variable tree in main. So even if no segfault occurred you would run into aliasing problems since they all refer to the same tree object and not a separate unique BinaryTree instance.
vector< vector<Binary_Tree*> >::iterator itr=vec.begin()+(lev+1);
vec.erase(itr);
vec.insert(itr,tempVec);
Your BinaryTree::insert_node is using an invalidated iterator after performing erase which is undefined behavior.
childNum = set_childNum(vec[lev][sib-1]);
// ...
prev = vec[lev][sib];
The above can access an out-of-bound index in your vector. eg. You push_back a tempVec with only 1 element in it and then call insert_node with sib = 1.
// ...
if(x == 5)
{
cout<<endl<<endl;
goto here;
}
The use of goto is also completely unnecessary here and should be replaced with a traditional while loop that checks for condition != 5.
The higher level problem in your program, however, is that there's no clear constraints and invariants in its design. What assumptions and preconditions do each of those functions need to work? Why use vectors to hold BinaryTree nodes when the class itself should be dealing with that. You should get the overall design sorted out first, otherwise you'll just play whack-a-mole as other bugs crop up.
I am getting a very strange error in my code. This assignment is for a class I'm taking and essentially we are learning how to implement a hash table. The error i'm getting is when I try and rehash to a larger size. Here's the portion of the code giving me the problem, and I'll explain more fully what the problem is.
if(htable->size>=htable->cap)
{
cout<<htable->cap<<endl;
HashTable tempht=*htable;
delete htable;
htable=new HashTable((tempht.cap * 2) + 1);
for (size_t i=0; i<tempht.cap; i++)
{
Node* n=tempht.table[i];
while (n!=NULL)
{
htable->add(n->item);
n=n->next;
}
}
if (htable->table[0]==NULL)
{
cout<<"HOORAY!"<<endl;
}
}
if (htable->table[0]==NULL)
{
cout<<"HOORAY!"<<endl;
}
else
{
cout<<htable->table[0]->item<<endl;
}
htable is a HashTable variable. In the HashTable class it contains an array Node* (Nodes are just objects I created that contain a string and a pointer to the next item in the chain). This part of the code is simply trying to rehash to a larger table. The issue I'm getting is once I exit the first if statement, my table's first value no longer equals NULL (the test I'm running rehashes a table with nothing in it to a table that still has nothing in it, but has a larger capacity). When I run the code, the first htable->table[0]==NULL passes while the second does not, despite there being no changes other than exiting the if statement (my expected result is that the table[0] should be NULL). My best guess is it's some kind of scoping error, but I honestly can't see where the problem is. Any help would be greatly appreciated.
Edit: Just to clarify, the initial hash table has a capacity of 0 (this is one of the project requirements). So when i try to add an item to the table, this if statement is executed (since the size is 0 and the cap is 0, we have to maintain a load factor of 1). I can confirm that once the table reaches the first and second "Hooray" checks, that htable->cap (which is the total capacity of the array) is 1, which is what it should be. The only thing that is getting messed is bucket 0 (which in this case is the only bucket). For whatever reason, it's null before exiting the if statement but not after.
I'm posting my whole HashTable class, let me know if you find anything.
#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include "Node.h"
using namespace std;
class HashTable
{
public:
Node** table;
int size;
int cap;
HashTable (int c)
{
size=0;
cap=c;
table = new Node*[cap];
if (cap>0)
{
for (size_t i=0; i<cap; ++i)
{
table[i]=NULL;
}
}
}
~HashTable()
{
delete table;
}
size_t hash(string thing)
{
size_t total=0;
int asci;
char c;
size_t index;
for (size_t i=0; i<thing.length(); i++)
{
total=total*31;
c=thing[i];
asci=int(c);
total=asci+total;
}
index=total%cap;
cout<<"index"<<index<<endl;
system("pause");
return index;
}
void add(string thing)
{
size_t index;
index=hash(thing);
cout<<"index "<<index<<endl;
system("pause");
Node* temp=table[index];
if (temp==NULL)
{
cout<<"Here"<<endl;
system("pause");
}
else
{
cout<<"Here2"<<endl;
system("pause");
cout<<"temp"<<temp->item<<endl;
system("pause");
}
Node* n = new Node(thing);
cout<<"n"<<n->item<<endl;
system("pause");
if (temp==NULL)
{
table[index]=n;
}
else
{
while (temp->next!=NULL)
{
temp=temp->next;
}
temp->next=n;
}
size++;
}
Node* find(string search)
{
Node* n= NULL;
size_t index;
if(cap!=0)
{
index=hash(search);
Node* temp=table[index];
while (temp!=NULL)
{
if (temp->item==search)
{
n=temp;
return n;
}
}
}
return n;
}
void remove (string thing)
{
if (find(thing)==NULL)
{
return;
}
else
{
size_t index;
index=hash(thing);
Node* temp=table[index];
if (temp->item==thing)
{
table[index]=temp->next;
delete temp;
}
while (temp->next!=NULL)
{
if (temp->next->item==thing)
{
Node* temp2=temp->next;
temp->next=temp->next->next;
delete temp2;
break;
}
}
}
size--;
}
void print(ofstream &ofile)
{
for (size_t i=0; i<cap; i++)
{
Node* n=table[i];
ofile<<"hash "<<i<<":";
while (n!=NULL)
{
ofile<<" "<<n->item;
n=n->next;
}
}
}
};
Well, this is C++, and I'm more a Java guy, but I'll take a stab at it.
Turns out the problem IS with the
HashTable tempht=*htable;
delete htable;
block after all.
See, the first line there says "copy all of the members from *htable into tempht". So now tempht and htable SHARE their table memory, since table is just a pointer to memory that was allocated at construction, and you just copied the pointer. You wanted it to copy the nodes inside table, but it didn't do that.
So now you have two different HashTable objects with the same pointer value in table. Now, when tempht is freed, the destructor calls free on the table pointer, which effectively frees the table data in both objects htable and tempht.
What you really want to do is write a copy constructor, or do something like:
HashTable *tempht=htable;
htable=new HashTable((tempht->cap * 2) + 1);
for (size_t i=0; i<tempht->cap; i++)
{
Node* n=tempht->table[i];
while (n!=NULL)
{
htable->add(n->item);
n=n->next;
}
}
if (htable->table[0]==NULL)
{
cout<<"HOORAY!"<<endl;
}
delete tempht;
See how all I've really done is change tempht to a pointer, using it to point to the old hashtable while you copy all the nodes from it to the new htable object, then deleting the old Hashtable.