Null Pointer Error after generating huffman code using recursive call to a function but it is not keeping the NULL value - c++

I was trying to generate huffman code for the input:
testcases=1
string s=abcdef
frequency={5 , 9 ,12 ,13 , 16, 45}
I was trying to traverse through pointers.
I am not sure if there is some error in copying the struct containing pointers because on printing the string it works fine for the nodes containing {12 and 13}
But it does not go back to the next node once it gets to node 5
// { Driver Code Starts
#include<bits/stdc++.h>
using namespace std;
// } Driver Code Ends
struct Node{
int index,frequency;
Node *left,*right;
};
struct comp{
bool operator()(Node const &a,Node const &b){
if(a.frequency == b.frequency)
return a.index > b.index;
return a.frequency > b.frequency;
}
};
class Solution
{
vector<Node> tree;
public:
void give_me_codes(Node *root,vector<string> &ans,string s,int &size){
cout<<"Printing s to show call: "<<s<<'\n';
/*while(root!=NULL){
cout<<root->index<<" "<<root->frequency<<"\n";
root=root->right;
root=root->left;
}*/
if(root==NULL){
return;
}
if(root->index<size)
ans.push_back(s);
if(root->left!=NULL)give_me_codes(root->left, ans,s+"0",size);
if(root->right!=NULL)give_me_codes(root->right,ans,s+"1",size);
}
vector<string> huffmanCodes(string S,vector<int> f,int N)
{
// Code here
priority_queue<Node, vector<Node>, comp> heap;
for(int i=0;i<N;++i){
Node element={.index=i,.frequency=f[i],.left=NULL,.right=NULL};
heap.push(element);
}
int sz = heap.size();
/*for(int i=0;i<sz;++i){
Node ele = heap.top();
heap.pop();
cout<<ele.index<<" "<<ele.frequency<<"\n";
}*/
Node *root;
int i=0;
while(heap.size()>1){
Node l = heap.top();heap.pop();
Node r =heap.top();heap.pop();
tree.push_back(l);
tree.push_back(r);
Node _new = {.index=sz++,.frequency=l.frequency+r.frequency,.left=&tree[i++],.right=&tree[i++]};
root =&_new;
heap.push(_new);
}
//cout<<tree[4].left<<" "<<tree[4].frequency<<'\n';
//cout<<tree[2].left<<" "<<tree[2].frequency<<'\n';
//tree[0].left=tree[0].right=NULL;
//tree[1].left=tree[1].left=NULL;
tree.push_back(*root);
vector<string> ans;
give_me_codes(root,ans,"",N);
cout<<'\n';
vector<string> v(N,"A");
return ans;
}
};
// { Driver Code Starts.
int main(){
int T;
cin >> T;
while(T--)
{
string S;
cin >> S;
int N = S.length();
vector<int> f(N);
for(int i=0;i<N;i++){
cin>>f[i];
}
Solution ob;
vector<string> ans = ob.huffmanCodes(S,f,N);
for(auto i: ans)
cout << i << " ";
cout << "\n";
}
return 0;
} // } Driver Code Ends
I tried assiging the left and right pointers of node 5 to NULL but it doesn't makes any difference and the output (when I print string s) stops after printing 110000 although I am expecting it to print 1100 and then probably move to the next node.
I shared the whole code and you can see what the output is showing. Can anyone please explain what is wrong here and what could be the possible fix?

Related

SIGSEGV error occurs in implementation of a hash table in C++

I am trying to implement a hash table data structure in C++, but every time i run the program i get a run time error(SIGSEGV, segmentation fault) in line number 86 like here.
i.e.: putInHash(str,hashTable,m); in main().
This is my code:
#include <iostream>
#include<string.h>
#include<math.h>
#include<stdlib.h>
using namespace std;
typedef struct node
{
struct node *next,*prev;
string data;
}node;
int hashCode(string str)
{
char arr[str.size()+1];
strcpy(arr,str.c_str());
int code=0;
for(int i=0;i<str.size();i++)
{
code+=((i+1)*((int)arr[i]));
}
return code;
}
int compress(int k,int m)
{
double a=(sqrt(5.0)-1)/2;
return floor(m*(fmod(k*a,1)));
}
void display(node* hashTable[],int m)
{
for(int i=0;i<m;i++)
{
cout<<i<<":\n";
node* p=hashTable[i];
while(p!=NULL)
{
cout<<p->data<<" , ";
}
cout<<"\n";
}
}
void putInHash(string str,node* hashTable[],int m)
{
int k=hashCode(str);
int bucket=compress(k,m);
if(hashTable[bucket]==NULL)
{
hashTable[bucket]=(node*)malloc(sizeof(node));
hashTable[bucket]->prev=NULL;
hashTable[bucket]->next=NULL;
hashTable[bucket]->data=str;
}
else
{
node* temp=(node*)malloc(sizeof(node));
temp->data=str;
temp->next=hashTable[bucket];
hashTable[bucket]->prev=temp;
temp->prev=NULL;
hashTable[bucket]=temp;
}
}
int main()
{
cout<<"Enter number of strings to add in hash table: ";
long int n;
cin>>n;
cout<<"\n";
int m=13;
node* hashTable[m];
for(int i=0;i<m;i++)
{
hashTable[i]=NULL;
}
string str;
cout<<"Enter the strings:\n";
for(int i=0;i<n;i++)
{
cin>>str;
putInHash(str,hashTable,m);
}
display(hashTable,m);
return 0;
}
I thought it might be due to passing the string, but it turned out this wasn't the case.
Can somebody please guide me through it.
I think the error may be in passing the hashTable[] as an argument.
I can't reproduce your problem (I'm using clang++ in a Linux platform and I suppose that your problem is platform dependent) but I see something that can explain it.
You use malloc() to allocate memory for a struct with a std::string in it.
This is bad.
Really, really bad.
Because malloc() can allocate the memory but can't construct the data member in it.
In C++ you should use new; at least, allocating not trivial objects (std::string isn't trivial).
// node* temp=(node*)malloc(sizeof(node)); // DANGEROUS
node * temp = new node;
This is the problem that cause the sigsegv (I suppose) but your code has a lot of other problem.
Example: the while in display() goes in loop because p remain unchanged; you should change display() in this way
void display (node * hashTable[], int m)
{
node * p;
for(int i=0;i<m;i++)
{
cout << i << ":\n";
for ( p = hashTable[i] ; p ; p = p->next )
cout << p->data << " , ";
cout << "\n";
}
}
Another important point: variable length arrays isn't C++; it's C (C99). So this lines are wrong
char arr[str.size()+1];
node* hashTable[m];
You don't need the first (absolutely useless) and you can simplify hashcode() in this way (and please, pass the strings by const reference, when possible)
int hashCode (const string & str)
{
int code = 0;
for ( int i = 0 ; i < str.size() ; ++i )
code += (i+1) * int(str[i]);
return code;
}
About hashTable, you can substitute it with a std::vector
// node* hashTable[m]; no C++
//for(int i=0;i<m;i++) // useless
//{ // useless
// hashTable[i]=NULL; // useless
//} // useless
std::vector<node *> hashTable(m, NULL); // m NULL node pointers
Obviously, putInHash() should be
void putInHash (string str, std::vector<node*> & hashTable, int m)
and display()
void display (const std::vector<node*> & hashTable, int m)
And remember to free the allocated memory.
p.s.: sorry for my bad English.
--- EDIT ---
phonetagger is right: deleting the memory (a vector o linked nodes) isn't trivial.
I suggest a function like the following
void recursiveFreeNode (node * & nd)
{
if ( nd )
{
recursiveFreeNode(nd->next);
delete nd; // added with EDIT 2; sorry
nd = NULL; // useless, in this, case, but good practice
}
}
and call it (for every node of the vector) in main(), after display() calling
for ( unsigned ui = 0U ; ui < hashTable.size() ; ++ui )
recursiveFreeNode(hashTable[ui]);
--- EDIT 2 ---
Sorry: I've forgot the more important line: delete node (thanks phonetagger).
Following the other suggestion of phonetagger, I propose a not-recursive function for deleting the hashtable's node
void loopFreeNode (node * & nd)
{
node * tmp;
for ( ; nd ; nd = tmp )
{
tmp = nd->next;
delete nd;
}
nd = NULL;
}
Obviously the for loop, to use loopFreeNode(), should be
for ( unsigned ui = 0U ; ui < hashTable.size() ; ++ui )
loopFreeNode(hashTable[ui]);

Different output when set different breakpoints

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.

Hash table implementation in C++

I am trying the following code for Hash table implementation in C++. The program compiles and accepts input and then a popup appears saying " the project has stopped working and windows is checking for a solution to the problem. I feel the program is going in the infinite loop somewhere. Can anyone spot the mistake?? Please help!
#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
/* Definitions as shown */
typedef struct CellType* Position;
typedef int ElementType;
struct CellType{
ElementType value;
Position next;
};
/* *** Implements a List ADT with necessary functions.
You may make use of these functions (need not use all) to implement your HashTable ADT */
class List{
private:
Position listHead;
int count;
public:
//Initializes the number of nodes in the list
void setCount(int num){
count = num;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
//Inserts an element after Position p
int insertList(ElementType data, Position p){
Position temp;
temp = p->next;
p->next = new CellType;
p->next->next = temp;
p->next->value = data;
return ++count;
}
//Returns pointer to the last node
Position end(){
Position p;
p = listHead;
while (p->next != NULL){
p = p->next;
}
return p;
}
//Returns number of elements in the list
int getCount(){
return count;
}
};
class HashTable{
private:
List bucket[10];
int bucketIndex;
int numElemBucket;
Position posInsert;
string collision;
bool reportCol; //Helps to print a NO for no collisions
public:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
}
collision = "";
reportCol = false;
}
int insert(int data){
bucketIndex=data%10;
int col;
if(posInsert->next==NULL)
bucket[bucketIndex].insertList(data,posInsert);
else { while(posInsert->next != NULL){
posInsert=posInsert->next;
}
bucket[bucketIndex].insertList(data,posInsert);
reportCol=true;}
if (reportCol==true) col=1;
else col=0;
numElemBucket++;
return col ;
/*code to insert data into
hash table and report collision*/
}
void listCollision(int pos){
cout<< "("<< pos<< "," << bucketIndex << "," << numElemBucket << ")"; /*codeto generate a properly formatted
string to report multiple collisions*/
}
void printCollision();
};
int main(){
HashTable ht;
int i, data;
for (i=0;i<10;i++){
cin>>data;
int abc= ht.insert(data);
if(abc==1){
ht.listCollision(i);/* code to call insert function of HashTable ADT and if there is a collision, use listCollision to generate the list of collisions*/
}
//Prints the concatenated collision list
ht.printCollision();
}}
void HashTable::printCollision(){
if (reportCol == false)
cout <<"NO";
else
cout<<collision;
}
The output of the program is the point where there is a collision in the hash table, thecorresponding bucket number and the number of elements in that bucket.
After trying dubbuging, I come to know that, while calling a constructor you are not emptying the bucket[bucketIndex].
So your Hash Table constructor should be as follow:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
bucket[i].makeEmptyList(); //here we clear for first use
}
collision = "";
reportCol = false;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
what you can do is you can get posInsert using
bucket[bucketIndex].end()
so that posInsert-> is defined
and there is no need to
while(posInsert->next != NULL){
posInsert=posInsert->next;
because end() function is doing just that so use end() function

Why this code failed to run

i want to generate a tree of siblings as under
ABCD
/ | \ \
A B C D
ABCD has four nodes i have taken a array for this *next[]. but this code does not run successfully but it produces the sequence. i have written code in main() which provide characters to the enque function. e.g. str.at(x) where x is variable in for loop.
struct node
{
string info;
struct node *next[];
}*root,*child;
string str, goal;
int dept=0,bnod=0,cl,z=0;
void enqueue(string n);
void enqueue(string n)
{
node *p, *temp;
p=new node[sizeof(str.length())];
p->info=n;
for (int x=0;x<str.length();x++)
p->next[x]=NULL;
if(root==NULL)
{
root=p;
child=p;
}
else
{
cout<<" cl="<<cl<<endl;
if(cl<str.length())
{
child->next[cl]=p;
temp=child->next[cl];
cout<<"chile-info "<<temp->info<<endl;
}
else
cout<<" clif="<<cl<<endl;
}
}
OUTPUT
Enter String: sham
cl=0
chile-info s
cl=1
chile-info h
cl=2
chile-info a
cl=3
chile-info m
RUN FAILED (exit value 1, total time: 2s)
Firstly, where does "RUN FAILED" come from? Is that specific to your compiler?
Secondly, about the line p=new node[sizeof(str.length())];, it probably won't give you what you wanted because you're taking the sizeof of an unsigned integer ( which, depending on your platform is likely to give you 4 regardless of the string length. Which is not what you're after - you want the actual length of the string ).
So - since you're already using std::string, why not use std::vector? Your code would look a lot friendlier :-)
If I take the first couple of lines as your desired output ( sorry, the code you posted is very hard to decipher, and I don't think it compiles either, so I'm ignoring it ;-) )
Would something like this work better for you?
#include <iostream>
#include <vector>
#include <string>
typedef struct node
{
std::string info;
std::vector<struct node*> children;
}Node;
Node * enqueue(std::string str)
{
Node * root;
root = new Node();
root->info = str;
for (int x = 0; x < str.length(); x++)
{
Node * temp = new Node();
temp->info = str[x];
root->children.push_back(temp);
}
return root;
}
int main()
{
Node * myRoot = enqueue("ABCD");
std::cout << myRoot->info << "\n";
for( int i = 0; i < myRoot->children.size(); i++)
{
std::cout << myRoot->children[i]->info << ", ";
}
char c;
std::cin >> c;
return 0;
}
Your code seems not full.
At least the line
p=new node[sizeof(str.length())];
seems wrong.
I guess enqueue should be something similar to the following:
struct node
{
string info;
struct node *next; // [] - is not necessary here
}*root,*child;
string str, goal;
int dept=0,bnod=0,cl,z=0;
void enqueue(string n)
{
node *p, *temp;
p = new node;
p->next = new node[str.length()];
p->info=n;
for (int x=0;x<str.length();x++)
{
p->next[x] = new node;
p->next[x]->next = 0;
p->next[x]->info = str[x];
}
if(root==NULL)
{
root=p;
child=p;
}
}
Please provide more info to give a more correct answer

Confusion in creating a directed graph in C++

I am trying to create a directed graph by reading a text file where each line has two columns, first column is a tail vertex and second column is the head vertex. Presently just to test if my code works I am trying to populate the graph and print it out.
I am printing my graph after every node insertion. Graph print works as fine until I insert the third node "4" after which first node changes to 0 from 1. I do not have any clue why. I wonder if storing node pointers in edge is a good idea. I am doing it because I already have node information in the "nodes" vector hence do not want to duplicate it.
Input test file:
1 2
4 5
My data structures are:
node: which holds node id and and boolean variable node dirty
edge: which holds pointers to tail node and head node
graph: Holds vectors of all nodes and edges
Output:
Pushing :1
print called
Nodes are:
1
Pushing :2
print called
Nodes are:
1
2
Pushing :4
print called
0(0) --> 2(0) // Problem this should have been 1(0) --> 2(0)
Nodes are:
1
2
4
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
class node {
public:
node() {}
node(int _nodeId, bool dirty);
int nodeId;
bool dirty;
void operator=(node rhs);
bool operator==(node rhs);
};
class edge {
public:
edge(node *_startNode, node *_endNode): startNode(_startNode), endNode(_endNode) {}
node *startNode, *endNode;
};
node :: node(int _nodeId, bool _dirty) {
nodeId = _nodeId;
dirty = _dirty;
}
void node :: operator=(node rhs) {
this->dirty = rhs.dirty;
this->nodeId = rhs.nodeId;
}
bool node :: operator==(node rhs) {
if (this->nodeId == rhs.nodeId) {
return true;
}
return false;
}
class graph {
public:
void print();
void addEdge(node startNode, node endNode);
void addNode(node n);
void dfs(node s);
private:
vector<edge> edges;
vector<node> nodes;
};
void graph :: addNode(node n) {
// only add this node if it does not exist in the graph
if (find(nodes.begin(), nodes.end(), n) == nodes.end()) {
//print();
cout << "Pushing :"<<n.nodeId<<endl;
nodes.push_back(n);
}
print();
cout << endl;
}
void graph :: dfs(node s) {
// Search node s and mark it as dirty
}
void graph :: print() {
cout << "print called\n";
vector<edge>::iterator itr = edges.begin();
while (itr != edges.end()) {
cout << itr->startNode->nodeId << "("<< itr->startNode->dirty<<") --> ";
cout << itr->endNode->nodeId << "("<< itr->endNode->dirty<<")"<<endl;
++itr;
}
cout << "Nodes are:\n";
for (int i=0; i< nodes.size(); ++i) {
cout << nodes.at(i).nodeId << endl;
}
}
void graph :: addEdge(node startNode, node endNode) {
vector<node>::iterator itrStartNode;
itrStartNode = find(nodes.begin(), nodes.end(), startNode);
vector<node>::iterator itrEndNode;
itrEndNode = find(nodes.begin(), nodes.end(), endNode);
edge e(&(*itrStartNode), &(*itrEndNode));
edges.push_back(e);
}
int main(int argc, char *argv[]) {
graph g;
// Read the file here
ifstream file;
file.open("test.txt", ios::in);
string line;
while (getline(file, line)) {
int startNodeId, endNodeId;
istringstream is(line);
is >> startNodeId >> endNodeId;
node startNode(startNodeId, false);
node endNode(endNodeId, false);
g.addNode(startNode);
g.addNode(endNode);
g.addEdge(startNode, endNode);
}
file.close();
g.print();
return 0;
}
You're creating temporary variables, e.g.
node startNode(startNodeId, false);
node endNode(endNodeId, false);
and
edge e(&(*itrStartNode), &(*itrEndNode));
and storing pointers to temporary instances into your containers, e.g.
edge e(&(*itrStartNode), &(*itrEndNode));
edges.push_back(e);
Once you exit the local scope in which those instances were created (the while loop or the addEdge method), the stack memory storing those instances are taken back by the program for use elsewhere. However, your pointers still point to valid memory addresses (taken back by the program or not), and so, may still point to valid-seeming data. That's probably what's going on, i.e. why you're seeing valid-seeming but incorrect vertices.
Use the new operator to create instances that persist beyond the local scopes of loops and functions, and clean them up (via delete) appropriately.