Problems calling my methods with a pointer - c++

I'm basically meant to create a min heap and a couple of methods such as remove min and insert.
The methods work fine when I call the methods with an object of the class. However, when I decide to use a pointer, the whole program crashes at the beginning.
class TreeNode {
private:
TreeNode *left;
TreeNode *right;
unsigned frequency;
unsigned char val;
public:
TreeNode *getLeft() { return left; }
TreeNode *getRight() { return right; }
TreeNode(unsigned char val, unsigned int frequency) {
left = NULL;
right = NULL;
this->frequency = frequency;
this->val = val;
}
unsigned getFrequency() { return frequency; }
signed int setFrequency(int i) { this->frequency = i; }
unsigned char getVal() { return val; }
};
class MinHeap {
private:
int n;
vector<TreeNode *> holder;
public:
MinHeap() {
n = 0;
TreeNode *sentinel;
sentinel->setFrequency(-100);
holder.push_back(sentinel);
}
void insert(TreeNode *val) {
n++;
holder.push_back(val);
restoreUp(n);
}
int getSize(); // returns size of heap
~MinHeap() {}
void restoreUp(int b) {
int k = holder.at(b)->getFrequency();
TreeNode *newVal = holder.at(b);
int iParent = floor(b / 2);
while (holder.at(iParent)->getFrequency() > k && iParent > 0) {
// std::swap(holder.at(b), holder.at(iParent));
// cout<<iParent<<endl;
holder.at(b) = holder.at(iParent);
b = iParent;
iParent = floor(b / 2);
}
holder.at(b) = newVal;
}
TreeNode *removeMin() {
if (n == 0) {
cout << "empty heap" << endl;
return 0;
} else if (n == 1) {
// cout<<n<<endl;
return holder.at(1);
} else if (n == 2) {
if (holder.at(1)->getFrequency() > holder.at(2)->getFrequency()) {
return holder.at(2);
}
return holder.at(1);
} else {
TreeNode *minValue = holder.at(1);
holder.at(0) = holder.at(n - 1);
n--;
restoreDown(1);
return minValue;
}
}
void restoreDown(int i) {
TreeNode *node = holder.at(1);
// int i = 1;
int k = node->getFrequency();
int leftIndex = 2 * i, rightIndex = (2 * i) + 1;
while (rightIndex >= n) {
if (k <= holder.at(leftIndex)->getFrequency() &&
k <= holder.at(rightIndex)->getFrequency()) {
holder.at(1) = node;
return;
}
}
}
};
int main(int argc, char **argv) {
TreeNode *ttn = new TreeNode('t', frequency_table[uint8_t('t')]);
/*MinHeap mh;
mh.insert(ttn); This one works fine*/
// but the next line crashes my code
MinHeap *mh = new MinHeap();
mh->insert(ttn);
}
This is particularly a problem because the test cases use pointers instead of objects. Is there an easy rectification for this?

The crash has nothing to do with using the class as a plain object or via a pointer. The program has undefined behaviour in either case.
When using a debugger, the first thing you will see, is that the call to setFrequency inside the constructor is on an uninitialized pointer named sentinel
MinHeap() {
n = 0;
TreeNode *sentinel; // not initialized
sentinel->setFrequency(-100); // used
holder.push_back(sentinel);
}

Related

Is there a better way to do a self-reference pointer in the base class that also works in derived classes?

I am writing some code on Splay Tree nodes. Without being too technical, I want to implement one base tree and one derived tree that supports reversion of the left and right sub-trees. The current excerpt looks like this:
struct node {
node *f, *c[2];
int size;
void push_down() {}
};
struct reversable_node : node {
int r;
void push_down() {
if (r) {
std::swap(c[0], c[1]);
c[0]->r ^= 1, c[1]->r ^= 1, r = 0;
}
}
};
This obviously does not work, because c[0] are of type node and does not have member r. Still, I know that c[0] of node only points to node and c[0] of reversable_node only points to reversable_node. So I can do some cast:
((reversable_node *)c[0])->r ^= 1, ((reversable_node *)c[1])->r ^= 1, r = 0;
But this looks super clumsy. Is there a better way to do a self-reference pointer in the base class that also works in derived classes?
P.S. The whole code looks like this:
struct node {
node *f, *c[2];
int size;
node() {
f = c[0] = c[1] = nullptr;
size = 1;
}
void push_down() {}
void update() {
size = 1;
for (int t = 0; t < 2; ++t)
if (c[t]) size += c[t]->size;
}
};
struct reversable_node : node {
int r;
reversable_node() : node() { r = 0; }
void push_down() {
if (r) {
std::swap(c[0], c[1]);
((reversable_node *)c[0])->r ^= 1, ((reversable_node *)c[1])->r ^= 1, r = 0;
}
}
};
template <typename T = node, int MAXSIZE = 500000>
struct tree {
T pool[MAXSIZE + 2];
node *root;
int size;
tree() {
size = 2;
root = pool[0], root->c[1] = pool[1], root->size = 2;
pool[1]->f = root;
}
void rotate(T *n) {
int v = n->f->c[0] == n;
node *p = n->f, *m = n->c[v];
p->push_down(), n->push_down();
n->c[v] = p, p->f = n, p->c[v ^ 1] = m;
if (m) m->f = p;
p->update(), n->update();
}
void splay(T *n, T *s = nullptr) {
while (n->f != s) {
T *m = n->f, *l = m->f;
if (l == s)
rotate(n);
else if ((l->c[0] == m) == (m->c[0] == n))
rotate(m), rotate(n);
else
rotate(n), rotate(n);
}
if (!s) root = n;
}
node *new_node() { return pool[size++]; }
void walk(node *n, int &v, int &pos) {
n->push_down();
int s = n->c[0] ? n->c[0]->size : 0;
(v = s > pos) && (pos -= s + 1);
}
void add_node(node *n, int pos) {
node *c = root;
int v;
++pos;
do {
walk(c, v, pos);
} while (c->c[v] && (c = c->c[v]));
c->c[v] = n, n->f = cur, splay(n);
}
node *find(int pos, int splay = true) {
node *c = root;
int v;
++pos;
do {
walk(c, v, pos);
} while (pos && (c = c->c[v]));
if (splay) splay(c);
return c;
}
node *find_range(int posl, int posr) {
node *l = find(posl - 1), *r = find(posr, false);
splay(r, l);
if (r->c[0]) r->c[0]->push_down();
return r->c[0];
}
};
So basically we have a flag of whether a node is reversed, and when we try to rotate the tree, we push down the flag from the node to its children. This may require some understanding of the Splay Tree.
P.S.2 It is supposed to be a library, but some use cases would be like this:
#include "../template.h"
splay::tree<splay::reversable_node> s;
void dfs(splay::reversable_node *n) {
if (n) {
// Push down the flag.
n->push_down();
dfs(n->c[0]);
// Do something about n...
dfs(n->c[1]);
}
}
int main() {
// Insert 5 nodes to the Splay Tree.
for (int i = 0; i < 5; ++i) s.add_node(s.new_node(), 0);
// Find a range of the tree.
splay::reversable_node *n = s.find_range(0, 3);
// Reverse it.
n->r = 1;
std::swap(n->c[0], n->c[1]);
// Traverse it in inorder.
dfs(s.root);
}
Anyway thanks to CRTP I got it to work.
namespace splay {
/**
* Abstract node struct.
*/
template <typename T>
struct node {
T *f, *c[2];
int size;
node() {
f = c[0] = c[1] = nullptr;
size = 1;
}
void push_down() {}
void update() {
size = 1;
for (int t = 0; t < 2; ++t)
if (c[t]) size += c[t]->size;
}
};
/**
* Abstract reversible node struct.
*/
template <typename T>
struct reversible_node : node<T> {
int r;
reversible_node() : node<T>() { r = 0; }
void push_down() {
node<T>::push_down();
if (r) {
for (int t = 0; t < 2; ++t)
if (node<T>::c[t]) node<T>::c[t]->reverse();
r = 0;
}
}
void update() { node<T>::update(); }
/**
* Reverse the range of this node.
*/
void reverse() {
std::swap(node<T>::c[0], node<T>::c[1]);
r = r ^ 1;
}
};
template <typename T, int MAXSIZE = 500000>
struct tree {
T pool[MAXSIZE + 2];
T *root;
int size;
tree() {
size = 2;
root = pool, root->c[1] = pool + 1, root->size = 2;
pool[1].f = root;
}
/**
* Helper function to rotate node.
*/
void rotate(T *n) {
int v = n->f->c[0] == n;
T *p = n->f, *m = n->c[v];
if (p->f) p->f->c[p->f->c[1] == p] = n;
n->f = p->f, n->c[v] = p;
p->f = n, p->c[v ^ 1] = m;
if (m) m->f = p;
p->update(), n->update();
}
/**
* Splay n so that it is under s (or to root if s is null).
*/
void splay(T *n, T *s = nullptr) {
while (n->f != s) {
T *m = n->f, *l = m->f;
if (l == s)
rotate(n);
else if ((l->c[0] == m) == (m->c[0] == n))
rotate(m), rotate(n);
else
rotate(n), rotate(n);
}
if (!s) root = n;
}
/**
* Get a new node from the pool.
*/
T *new_node() { return pool + size++; }
/**
* Helper function to walk down the tree.
*/
int walk(T *n, int &v, int &pos) {
n->push_down();
int s = n->c[0] ? n->c[0]->size : 0;
(v = s < pos) && (pos -= s + 1);
return s;
}
/**
* Insert node n to position pos.
*/
void insert(T *n, int pos) {
T *c = root;
int v;
++pos;
while (walk(c, v, pos), c->c[v] && (c = c->c[v]))
;
c->c[v] = n, n->f = c, splay(n);
}
/**
* Find the node at position pos. If sp is true, splay it.
*/
T *find(int pos, int sp = true) {
T *c = root;
int v;
++pos;
while ((pos < walk(c, v, pos) || v) && (c = c->c[v]))
;
if (sp) splay(c);
return c;
}
/**
* Find the range [posl, posr) on the splay tree.
*/
T *find_range(int posl, int posr) {
T *l = find(posl - 1), *r = find(posr, false);
splay(r, l);
if (r->c[0]) r->c[0]->push_down();
return r->c[0];
}
};
} // namespace splay
Some use case:
struct node : splay::reversible_node<node> {
int val;
void push_down() { splay::reversible_node<node>::push_down(); }
void update() { splay::reversible_node<node>::update(); }
};
splay::tree<node> t;
int N, M;
void inorder(node *n) {
static int f = 0;
if (!n) return;
n->push_down();
inorder(n->c[0]);
if (n->val) {
if (f) printf(" ");
f = 1;
printf("%d", n->val);
}
inorder(n->c[1]);
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 0; i < N; ++i) {
node *n = t.new_node();
n->val = i + 1;
t.insert(n, i);
}
for (int i = 0, u, v; i < M; ++i) {
scanf("%d%d", &u, &v);
node *n = t.find_range(u - 1, v);
n->reverse();
}
inorder(t.root);
}
Hopefully this allows me to write Splay faster in CP.

why i'm getting zero instead of 1?

This is a program of searching a number from linked list using recursion.
#include <iostream>
using namespace std;
class node {
public:
int data;
node *next;
void create(int *,int);
int max(node*,int);
};
node *first;
void node::create(int a[],int n) {
first = new node;
first->data = a[0];
first->next = NULL;
node *last = first;
for (int i = 1; i < n; i++) {
node *t = new node;
t->data = a[i];
t->next = NULL;
last->next = t;
last = t;
}
}
int node::max(node *l, int p) {
if (l->data == p) {
return 1;
}
if (l == 0)
return 0;
else {
max(l->next, p);
return 0;
}
}
int main() {
int a[5] = {1,2,3,4,5};
node m;
m.create(a,5);
cout << m.max(first, 3);
return 0;
}
Hunch. Instead of this:
else {
max(l->next, p);
return 0;
}
This:
else {
return max(l->next, p);
}
Or better yet, let's fix the whole max function to check for null before dereferencing l as well.
int node::max(node *l, int p) {
int result = 0;
if (l != nullptr) {
if (l->data == p) {
result = 1;
}
else {
result = max(l->next, p);
}
}
return result;
}

Skip List implementation in cpp

I am trying to implement a skiplist in cpp . There are many versions of skiplist available but I particularly want to implement a version where each node has a right and down pointer to form a connected list at various levels . Also at each higher level there is a replica of node rather than just a pointer.
I am giving my code that I have implemented uptill now. There is only one function that I have implemented till now i.e insertion. But I am getting segmentation fault. I know I am messing somewhere with pointers somewhere either in constructor, update or insert functions. Can somebody please help.
class SkipList
{
private:
struct node {
int key;
int data;
int level;
struct node* rgt = nullptr;
struct node* dwn = nullptr ;
node(int k, int value, int l):
key(k), data(value), level(l)
{}
};
//generates the ndde level in tha range [1,maxLevel).
int randomLevel() const;
//returns a set of pointers to the location at each node where new links are to be created
std::vector<node*> update(int searchKey) const ;
//creates a new node and returns a pointer to it
static node* makeNode(int key, int val, int level);
const float probability;
const int maxLevel;
// head and tail vectors
vector<node*> head;
vector<node*> nil;
public:
SkipList();
~SkipList();
void insert(int searchKey, int val);
void print() const;
};
SkipList::SkipList() :
probability(0.5), maxLevel(16)
{
int headkey = std::numeric_limits<int>::min();
int nilkey = std::numeric_limits<int>::max();
for(int i = 0; i < maxLevel;i++)
{
head[i] = new node(headkey,0,maxLevel-1);
nil[i] = new node(nilkey,0,maxLevel-1);
if(i > 0)
{
head[i]-> dwn = nil[i-1];
nil[i] -> dwn = nil[i-1];
}
head[i]->rgt = nil[i];
}
}
void SkipList::insert(int searchKey, int val)
{
vector <node*> preds = update(searchKey);
node* temp;
const int newLevel = randomLevel();
for(int i = 0; i< newLevel; i++)
{
node* ptr = makeNode(searchKey,val, newLevel-1);
temp = preds[i]->rgt;
preds[i]->rgt = ptr;
ptr->rgt = temp;
}
}
void SkipList::print() const{
node* list = head[0]->rgt;
int lineLength = 0;
std::cout<<"{";
while (list->rgt != nil[list->level])
{
std::cout<<"value: "<<list->data
<<", key: "<<list->key
<<", level: "<<list->level;
list = list->rgt;
if(list->rgt != nil[list->level]) std::cout<<" : ";
if (++lineLength % 2 == 0) std::cout << "\n";
}
std::cout << "}\n";
}
int SkipList::randomLevel() const{
int v = 1;
while (((double)std::rand() / RAND_MAX) < probability
&& v < maxLevel)
{
v++;
}
return v;
}
SkipList::node* SkipList::makeNode(int key, int value, int level){
return new node(key, value, level);
}
std::vector<SkipList::node*>SkipList::update(int searchKey) const{
int level = head[0]->level;
std::vector<node*> result(level,nullptr);
node* x ;
for(unsigned int i = level;i-- >0;)
{
x = head[i];
while(x->rgt->key < searchKey)
{
x = x->rgt;
}
result[i]= x;
}
return result;
}
int main()
{
SkipList s;
s.insert(5,22);
s.insert(2,33);
s.print();
return 0;
}
You should use push_back method in ctor of SkipList. Now you are creating objects
head[i] = new node(headkey,0,maxLevel-1);
and you are trying to assign the created node object to object returned by vector::operator[] which doesn't exist.
Or you can invoke vector::resize(maxlevel) method before entering into for loop.

Segmentation fault in skip list

I am implementing a skip list. The insertion function works fine and is able to print the list. But now I am trying to implement the "find" function and in this function I am getting a segmentation fault at the condition of while loop . When I debug the code , it works fine for all iterations except the last one. In the last iteration during condition check to enter in while loop it shows segmentation fault at this line precisely
while(x->rgt->key < searchKey)
I am not able to understand the reason because when I do handrun of the code everything seems fine. Please have a look and tell me what am I doing wrong ?
Also find function works fine if i search 1 and 2 but at 3 and 4 the fault occurs.
class SkipList
{
private:
struct node{
int key;
int data;
int level;
struct node* rgt = nullptr;
struct node* dwn = nullptr ;
node(int k, int value, int l):
key(k), data(value), level(l)
{}
};
//generates the ndde level in tha range [1,maxLevel).
int randomLevel() const;
//returns a set of pointers to the location at each node where new links are to be created
std::vector<node*> update(int searchKey) const ;
//creates a new node and returns a pointer to it
static node* makeNode(int key, int val, int level);
// Returns the first node for which node->key < searchKey is false
node* lower_bound(int searchKey) const;
const float probability;
const int maxLevel;
// head and tail vectors
vector<node*> head;
vector<node*> nil;
public:
SkipList();
// ~SkipList();
void insert(int searchKey, int val);
void find(int searchKey) const;
void erase(int searchKey);
void print() const;
};
SkipList::SkipList() :
probability(0.5), maxLevel(4)
{
head.resize(maxLevel, nullptr);
nil.resize(maxLevel,nullptr);
int headkey = std::numeric_limits<int>::min();
int nilkey = std::numeric_limits<int>::max();
for(int i = 0; i < maxLevel ;i++)
{
head[i] = new node(headkey,0,maxLevel-1);
nil[i] = new node(nilkey,0,maxLevel-1);
if(i>0)
{
head[i]->dwn = head[i-1];
nil[i] ->dwn = nil[i-1];
}
head[i]->rgt = nil[i];
}
}
void SkipList::find(int searchKey) const
{
node* x = head[maxLevel-1];
for(int i = maxLevel-1 ; i>= 0 ;i--)
{
while(x->rgt->key < searchKey)
{
x = x->rgt;
}
if(i != 0){x = x->dwn;}
}
if ((x->rgt->key == searchKey))
cout<<"Found"<<endl;
}
void SkipList::insert(int searchKey, int val)
{
vector <node*> preds = update(searchKey);
node* temp;
const int newLevel = randomLevel();
for(int i = 0; i< newLevel; i++)
{
node* ptr = makeNode(searchKey,val, newLevel-1);
temp = preds[i]->rgt;
preds[i]->rgt = ptr;
ptr->rgt = temp;
}
}
void SkipList::print() const
{
node *ptr = head[0]->rgt;
while(ptr->rgt != nullptr)
{
cout<<"Key: "<<ptr->key<<" Data: "<<ptr->data<<" Level: "<<ptr->level<<endl;
ptr = ptr->rgt;
}
}
int SkipList::randomLevel() const
{
int v = 1;
while (((double)std::rand() / RAND_MAX) < probability &&
v < maxLevel)
{
v++;
}
return v;
}
SkipList::node* SkipList::makeNode(int key, int value, int level)
{
return new node(key, value, level);
}
std::vector<SkipList::node*>SkipList::update(int searchKey) const
{
int level = head[0]->level;
std::vector<node*> result(level,nullptr);
node* x ;
for(unsigned int i = level;i-- >0;)
{
x = head[i];
while(x->rgt->key < searchKey)
{
x = x->rgt;
}
result[i]= x;
}
return result;
}
int main()
{
SkipList s;
int x,y;
for(int i = 1;i< 5;i++)
{
s.insert(i,i);
}
s.print();
cout<<endl;
s.find(3);
return 0;
}
A simple debug shows this in this loop:
while(x->rgt->key < searchKey)
{
x = x->rgt;
}
The value of x becomes NULL.
I am guessing that this is a case where you try to add an element at the end of the list.
If so, then you should come up with a different solution for this case.
For example:
while(x->rgt && x->rgt->key < searchKey)
{
x = x->rgt;
}
if (x->rgt)
{
// Use your original code
}
else
{
// Handle this special case
}

C++ Priority Queue crashes when I insert elements

I made up a priority-queue through a Min Heap.
This is a PriorityQueue of pointers to the class Node.
When I try to create a PriorityQueue object trough the vector it works great. The problem is inserting the pointers to Node individually through Insert method. It also works and prints the priority-queue but sometimes it crashes at the end of the execution! It returns an error despite works good.
Output:
a 1
b 2
c 3
Process returned -1073741819 (0xC0000005) execution time : 3.000 s
Press any key to continue.
Main:
int main()
{
NODE a = new Node('a',1);
NODE b = new Node('b',2);
NODE c = new Node('c',3);
Q.Insert(a);
Q.Insert(b);
Q.Insert(c);
Q.Print();
return 0;
}
Node code:
typedef class Node *NODE;
class Node {
private:
unsigned char Ch;
int Key;
NODE L;
NODE R;
public:
Node() { L = NULL; R = NULL; };
Node(int, unsigned char, NODE, NODE);
Node(unsigned char, int);
~Node() { delete L; delete R; };
NODE Left();
NODE Right();
int GetKey();
unsigned char GetChar();
void SetKey(int);
void SetChar(unsigned char);
};
Node::Node(unsigned char c, int k)
{
Ch = c; Key = k; R = NULL; L = NULL;
}
NODE Node::Left()
{
return L;
}
NODE Node::Right()
{
return R;
}
unsigned char Node::GetChar()
{
return Ch;
}
int Node::GetKey()
{
return Key;
}
void Node::SetKey(int k)
{
Key = k;
}
PriorityQueue code:
class PriorityQueue {
private:
vector<NODE> A;
int Heap_Size;
int Parent(int);
int Left(int);
int Right(int);
void Swap(NODE &, NODE &);
void MinHeapify(int);
public:
PriorityQueue();
PriorityQueue(vector<NODE>);
~PriorityQueue() {};
NODE Minimum();
NODE ExtractMin();
void DecreaseKey(int, int);
void Insert(NODE);
bool IsEmpty();
void Print();
};
PriorityQueue::PriorityQueue()
{
// I need to push back an empty node to use the vector from the index 1.
// This is important to move in the min-heap trough the indices.
NODE Default = new Node;
A.push_back(Default);
Heap_Size = 0;
}
PriorityQueue::PriorityQueue(vector<NODE> vett)
{
A = vett; Heap_Size = A.size()-1;
for (int i=Heap_Size/2; i>=1; i--)
{
MinHeapify(i);
}
}
void PriorityQueue::Swap(NODE &a, NODE &b)
{
NODE temp = a;
a = b;
b = temp;
}
void PriorityQueue::DecreaseKey(int i, int key)
{
if (key > A[i]->GetKey())
{
cout << "How can I decrease the key?" << endl;
return;
}
A[i]->SetKey(key);
while (i>1 && A[Parent(i)]->GetKey() > A[i]->GetKey())
{
Swap(A[i],A[Parent(i)]);
i = Parent(i);
}
}
void PriorityQueue::Insert(NODE Nodo)
{
Heap_Size++;
A[Heap_Size] = Nodo;
DecreaseKey(Heap_Size,Nodo->GetKey());
}
void PriorityQueue::Print()
{
for (int i=1; i<=Heap_Size; i++)
cout << A[i]->GetChar() << " " << A[i]->GetKey() << endl;
}
Thank you very much!!!!
I solved it! The problem was:
Heap_Size++;
A[Heap_Size] = Nodo;
A is a vector, so I had to edit in this way:
A.push_back(Nodo);