Strange bug in my splay tree implementation - c++

I am attempting to write a C++ template struct for a splay tree, but when I try to test the code, I am getting very strange results.
This is my code for the template:
template <class T>
struct splaytree {
struct node {
splaytree<T> *tree;
node *p, *c[2];
T v;
int w;
node(T t, splaytree<T> *st) {
v = t;
p = 0;
c[0] = 0;
c[1] = 0;
w = 1;
tree = st;
}
int side() {
return (p->c[1] == this) ? 1:0;
}
void r() {
node *x = this;
int b = x->side();
node *p = x->p;
x->w = p->w;
p->w = x->c[1^b]->w + 1 + p->c[1^b]->w;
x->p = p->p;
p->p = x;
p->c[0^b] = x->c[1^b];
x->c[1^b] = p;
}
void splay() {
node *x = this;
while (x->p) {
node *p = x->p;
if (p == tree->root) x->r();
else if (((x->side())^(p->side()))) {
x->r();
x->r();
}
else {
p->r();
x->r();
}
}
tree->root = this;
}
int index() {
this->splay();
return this->c[0]->w;
}
};
node *root;
splaytree() {
root = 0;
}
void add(T k) {
node x0(k,this);
node *x = &x0;
if (root == 0) {
root = x;
return;
}
node *i = root;
while (i != x) {
int b = (k < i->v) ? 0:1;
if (i->c[b] == 0) {
i->c[b] = x;
i->w++;
x->p = i;
}
i = i->c[b];
}
x->splay();
}
};
I am using this to test it:
int main() {
splaytree<int> st;
st.add(2);
cout << st.root->v << endl;
cout << st.root->v << endl;
st.add(3);
cout << st.root->c[0] << endl;
}
I inserted the element 2 and then printed the value of the root node twice. Somehow the two prints gave me two different values (2 and 10 in Ideone at http://ideone.com/RxZMyA). When I ran the program on my computer, it gave me 2 and 1875691072 instead. In both cases, when inserting a 3 after the 2, the root node's left child was a null pointer when it should be a node object containing 2.
Can someone please tell me why I am getting two different values when printing the same thing twice, and what I can do to make my splaytree.add() function work as intended? Thanks!

After
node x0(k,this);
node *x = &x0;
if (root == 0) {
root = x;
return;
}
root is an address of a local variable. By the time you print root->v, x0 is gone out of scope. All bets as to what the root really points to are off.

Related

Function couldn't been resolved

I have a problem with my C++ code. It says that the all the functions starting with isPerfectRec() couldn't be resolved...Why? I tried a lot of things but apparently they don't work. I have a lot of assigments like to verify if the binary search tree is perfect, to find the second largest element in a binary search tree and so on..
#include <stdio.h>
#include<iostream>
#include<stack>
template<typename T> class BinarySearchTree {
public:
BinarySearchTree<T> *root, *left_son, *right_son, *parent;
T *pinfo;
BinarySearchTree() {
left_son = right_son = NULL;
root = this;
pinfo = NULL;
}
void setInfo(T info) {
pinfo = new T;
*pinfo = info;
}
void insert(T x) {
if (pinfo == NULL)
setInfo(x);
else
insert_rec(x);
}
bool isPerfectRec(BinarySearchTree *root, int d, int level = 0)
{
// An empty tree is perfect
if (*root == NULL)
return true;
// If leaf node, then its depth must be same as
// depth of all other leaves.
if (*root->left_son == NULL && root->*right_son == NULL)
return (d == level+1);
// If internal node and one child is empty
if (root->*left_son == NULL || root->*right_son == NULL)
return false;
// Left and right subtrees must be perfect.
return isPerfectRec(root->*left_son, d, level+1) &&
isPerfectRec(root->*right_son, d, level+1);
}
// Wrapper over isPerfectRec()
bool isPerfect(BinarySearchTree *root)
{
int d = findADepth(root);
return isPerfectRec(root, d);
}
int findADepth(BinarySearchTree *node)
{
int d = 0;
while (node != NULL)
{
d++;
node = node->left_son;
}
return d;
}
// A function to find 2nd largest element in a given tree.
void secondLargestUtil(BinarySearchTree *root, int &c)
{
// Base cases, the second condition is important to
// avoid unnecessary recursive calls
if (root == NULL || c >= 2)
return;
// Follow reverse inorder traversal so that the
// largest element is visited first
secondLargestUtil(root->right_son, c);
// Increment count of visited nodes
c++;
// If c becomes k now, then this is the 2nd largest
if (c == 2)
{
std::cout << "2nd largest element is "
<< root->pinfo;
printf("\n___\n");
return;
}
// Recur for left subtree
secondLargestUtil(root->left_son, c);
}
void secondLargest(BinarySearchTree *root)
{
// Initialize count of nodes visited as 0
int c = 0;
// Note that c is passed by reference
secondLargestUtil(root, c);
}
bool hasOnlyOneChild(int pre[], int size)
{
int nextDiff, lastDiff;
for (int i=0; i<size-1; i++)
{
nextDiff = pre[i] - pre[i+1];
lastDiff = pre[i] - pre[size-1];
if (nextDiff*lastDiff < 0)
return false;;
}
return true;
}
BinarySearchTree * readListInter(){
BinarySearchTree* root = NULL;//returning object
BinarySearchTree* temp;
BinarySearchTree* input;//new node to add
int x;
std::cout << "enter number (>0 to stop): ";
std::cin >> x;
while(x>=0){
input = BinarySearchTree(x);
if(root == NULL){//if root is empty
root = input;
temp = root;//temp is use to store value for compare
}
else{
temp = root; //for each new addition, must start at root to find correct spot
while(input != NULL){
if( x < temp->pinfo){//if smaller x to add to left
if(temp->left_son == NULL){//left is empty
temp->left_son = input;
input = NULL;//new node added, exit the loop
}
else{//if not empty set temp to subtree
temp = temp->left_son;//need to move left from the current position
}
}
else{//otherwise x add to right
if(temp->right_son == NULL){//right is empty
temp->right_son = input;
input = NULL;//new node added, exit the loop
}
else{
temp = temp->right_son;//need to move right from the current position
}
}
}
}
std::cin >> x;
}
return root;
}
};
int main() {
BinarySearchTree<int> *r = new BinarySearchTree<int>;
BinarySearchTree<int> *r1 = new BinarySearchTree<int>;
BinarySearchTree<int> *p = new BinarySearchTree<int>;
p = readListInter();
r->insert(6);
r->insert(8);
r->insert(1);
r->insert(9);
r->insert(10);
r->insert(4);
r->insert(13);
r->insert(12);
printf("\n___\n");
r1->insert(6);
r1->insert(8);
r1->insert(1);
r1->insert(9);
r1->insert(10);
r1->insert(4);
r1->insert(13);
r1->insert(12);
printf("\n___\n");
r->isPerfect(r);
int pre[] = {8, 3, 5, 7, 6};
int size = sizeof(pre)/sizeof(pre[0]);
if (hasOnlyOneChild(pre, size) == true )
printf("Yes");
else
printf("No");
s
return 0;
}
I think you need to write BinarySearchTree<T> instead of BinarySearchTree as a datatype in those functions.

Runtime error when using struct as value in std::map?

I am using a map with int value -> trie, trie is the struct. So why am I getting runtime error when I print all keys value in my map? But if I don't print anything then there is no error(the insert() part don't cause any error).
struct trie{
node *root;
trie(){
root = new node();
}
void insert(int x){
node *cur = root;
for(int i = 31; i >= 0; i--){
int b = (x >> i) & 1;
if (cur->child[b] == NULL) cur->child[b] = new node();
cur = cur->child[b];
}
cur->isleaf = true;
}
int maxxor(int x){
node *cur = root;
int res = 0;
for(int i = 31; i >= 0; i--){
int b = (x >> i) & 1;
if (cur->child[b ^ 1] != NULL){
res |= (1ll << i);
cur = cur->child[b ^ 1];
}
else cur = cur->child[b];
}
return res;
}
int minxor(int x){
node *cur = root;
int res = 0;
for(int i = 31; i >= 0; i--){
int b = (x >> i) & 1;
if (cur->child[b] != NULL) cur = cur->child[b];
else{
res |= (1ll << i);
cur = cur->child[b ^ 1];
}
}
return res;
}
~trie(){
delete root;
}
};
map<int, trie> tr;
int32_t main(){
ios::sync_with_stdio(false);
tr[3].insert(1);// no error
for(auto x: tr) cout << x.first << ' '; //RUNTIME ERROR?
}
I have tried to debug and read various questions/answers but I still not be able to debug this code. Any help are appreciated.
You have implemented a "complex" tree if i may say, using linked list. And in order to avoid trouble, you need to make sure that your destructors do their work propoerly and are coherent i.e destroy all allocated memory and don't "try" to "destroy" unallocated space or already destroyed space.
That said, your trie destructor destroys root data member, which calls node destructor. And node destructor destroys both two child which were not necessarily allocated. This is the origin of your Segmentation Error.
To correct this you should only destroy allocated child.
Here is a simplified version of your code
#include <bits/stdc++.h>
#define int int64_t
using namespace std;
struct node{
node* child[2];
bool isleaf;
node(){
child[0] = child[1] = NULL;
isleaf = false;
}
~node(){
}
};
struct trie{
node *root;
trie(){
cout << " in trie ctor" << endl;
root = new node();
}
void insert(int x){
cout << "in insert trie methode " << endl;
node *cur = root;
cur->child[0] = new node();
cur->child[1] = new node();
}
~trie(){
delete root->child[0]; // i'm sure it has been allocated
delete root->child[1]; // i'm sure it has been allocated
// delete root, would be like doing int *p; delete p;
}
};
map<int, trie> tr;
int32_t main(){
ios::sync_with_stdio(false);
tr[3].insert(1);
for(auto x: tr)
cout << x.first << endl << endl;
}

C++ Exception thrown: read access violation. this was nullptr

For one of my programming classes, we are required to design a program that can be ran through the provided "stress tests" that our instructor wrote himself.
We are working with nodes and linked lists but in a way that is different than any of the YouTube videos I have looked at on the subject.
I've been tearing my hair out for the past couple of days trying to figure out what is wrong with my program but I'm having no luck.
Here is the code for my Node.cpp file (didn't include Node.h)
#include "Node.h"
Node::Node() {
m_value = 0;
m_next = nullptr;
}
void Node::setValue(int val) {
m_value = val;
}
int Node::getValue() const {
return m_value;
}
void Node::setNext(Node* prev) {
m_next = prev;
}
Node* Node::getNext() const {
return m_next;
}
Here is my LinkedList.cpp
#include <iostream>
#include <vector>
#include "LinkedList.h"
LinkedList::LinkedList() {
m_front = nullptr;
m_size = 0;
}
LinkedList::~LinkedList() {
// Deconstructor
m_size = 0;
Node* a = m_front;
Node* b = a->getNext();
while (a->getNext() != NULL) {
delete a;
a = b;
b = b->getNext();
}
delete a;
a = NULL;
}
bool LinkedList::isEmpty() const{
if (m_size == 0) {
return true;
}
else {
return false;
}
}
int LinkedList::size() const {
return m_size;
}
bool LinkedList::search(int value) const {
if (m_size == 0) {
return false;
}
else if (m_size == 1) {
if (m_front->getValue() == value) {
return true;
}
else {
return false;
}
}
else {
Node* a = m_front;
for (int i = 0; i < m_size; i++) {
if (a->getValue() == value) {
return true;
}
else {
a = a->getNext();
}
}
return false;
}
}
void LinkedList::printList() const {
std::cout << "List: ";
if (m_size == 0) {
// Print Nothing
}
else if (m_size == 1) {
std::cout << m_front->getValue();
}
else {
Node* a = new Node();
a = m_front;
int b = m_front->getValue();
std::cout << b << ", ";
while (a->getNext() != NULL) {
a = a->getNext();
if (a->getNext() == NULL) {
std::cout << a->getValue();
}
else {
std::cout << a->getValue() << ", ";
}
}
}
std::cout << std::endl;
}
void LinkedList::addBack(int value) {
Node* a = new Node();
a->setValue(value);
if (m_size == 0) {
m_front = a;
}
else {
Node* b = new Node();
b = m_front;
while (b->getNext() != NULL) {
b = b->getNext();
}
b->setNext(a);
}
m_size++;
}
void LinkedList::addFront(int value) {
Node* a = new Node(); // Check later
a->setNext(m_front);
a->setValue(value);
m_front = a;
m_size++;
}
bool LinkedList::removeBack() {
if (m_size == 0) {
return false;
}
else {
Node* a = new Node();
Node* b = new Node();
a = m_front;
while (a->getNext() != NULL) {
b = a;
a = a->getNext();
}
b->setNext(nullptr);
delete a;
a = NULL;
m_size--;
return true;
}
}
bool LinkedList::removeFront() {
if (m_size == 0) {
return false;
}
else {
Node* a = new Node();
a = m_front;
m_front = m_front->getNext();
delete a;
a = NULL;
m_size--;
return true;
}
}
std::vector<int> LinkedList::toVector() const {
if (m_size == 0) {
std::vector<int> b;
return b;
}
else {
std::vector<int> a(m_size);
Node* b = new Node();
b = m_front;
for (int i = 0; i < m_size; i++) {
a[i] = b->getValue();
b = b->getNext();
}
return a;
}
}
Basically, I've tested my program on my own and I've been able to make a linked list and run all my add and remove functions and print out the lists just fine. My problem is I run the test that our instructor gave us and it looks like this at the point where I'm having problems (Those print messages are in another file but all they seem to do is print the string arguments that are passed)
int score = 0;
const int MAX_SCORE = 90;
std::cerr << "\n\n=========================\n";
std::cerr << " RUNNING TEST SUITE \n";
std::cerr << "=========================\n\n";
//Run test and award points where appropriate
score += test1() ? 2 : 0;
score += test2() ? 2 : 0;
score += test3() ? 3 : 0;
This goes on for 18 tests, but my program never "makes" it past the first one. It passes the first test then all of a sudden throws an error.
bool Test_LinkedList::test1()
{
LinkedList list;
bool isPassed = false;
printTestMessage("size of empty list is zero");
isPassed = list.size() == 0;
printPassFail(isPassed);
return (isPassed);
}
I actually get this output before it crashes
=========================
RUNNING TEST SUITE
=========================
Test 1: size of empty list is zero: PASSED
So it passes the first test but never makes it out of there. What I mean is that I have tried throwing in a cout message around
score += test1() ? 2 : 0;
std::cout << "Done with test 1"
score += test2() ? 2 : 0;
score += test3() ? 3 : 0;
But that is never outputted. Instead my program breaks and Visual Studio pops up with a message saying
Exception thrown: read access violation.
this was nullptr.
If there is a handler for this exception, the program may be safely continued.
Then it points me to my method in Node.cpp that is
Node* Node::getNext() const {
return m_next;
}
Sorry, I know this is a lot of text to read through but right now I'm beyond stumped and there is no time for me to go into office hours as it is due early tomorrow morning.
edit: i tried omitting the first test and running it. It gets through the next 6 tests but then fails on the 7th (8th) with the same exact error.
bool Test_LinkedList::test8()
{
LinkedList list;
bool isPassed = false;
printTestMessage("search returns false on empty list");
isPassed = !list.search(42);
printPassFail(isPassed);
return (isPassed);
}
The LinkedList destructor has a couple of problems. First, it's pointless to set m_size to 0 and a to NULL since they will both go away at the end of the destructor. More important, the code will attempt to dereference a null pointer when the list is empty:
Node* a = m_front; // okay, gets that head pointer
Node* b = a->getNext(); // bang!!
Here's a cleaner way to write it:
Node* a = m_front;
while (a != NULL) {
Node *temp = a->getNext();
delete a;
a = temp;
}

C++ Singly Linked List Find Nodes value x spaces from beginning

float get(int x) {
if(x == 0) {return head->x;}
else {
Node *current = head;
for(int a=0; a<x; a++) {
current = current->next;
}
return current->x;
}
}
This is my code, but when I run it with a test case, it says "Lab3.exe has stopped working". I'm still really new to C++ and our teacher hasn't been helpful in the slightest, can anyone give me advice on my implementation?
EDIT:
Here's the test case...
#include <iostream>
#include <string>
using namespace std;
// including _my copy_ of SLList
#include "./SLList.h"
using namespace ods;
template <class FloatList>
bool listTest(){
FloatList L;
L.add(0, 3.14);
L.remove(0);
L.add(0, 1.62);
L.add(1, 2.23);
L.set(1, 2.72);
/*float x = L.get(1);*/
return ( 2.72f == L.get(1) and 2 == L.size() );
}
int main() {
if ( listTest<SLList<float> >() )
cout << "SLList passes basic list interface test" << endl;
else
cout << "SLList FAILS basic list interface test" << endl;
}
And here's how the SLL is set up:
template<class T>
class SLList {
T null;
protected:
class Node {
public:
T x;
Node *next;
Node(T x0) {
x = 0;
next = NULL;
}
};
Node *head;
Node *tail;
int n;
public:
SLList() {
null = (T)NULL;
n = 0;
head = tail = NULL;
}
virtual ~SLList() {
Node *u = head;
while (u != NULL) {
Node *w = u;
u = u->next;
delete w;
}
}

Cycle start node of Cycle linked list

I'm trying to implement a program for finding a starting node of circular linked list. My code is-
struct node
{
char data;
struct node *link;
} ;
char FindStartNode(struct node **q)
{
struct node *r,*t;
r = *q;
t = *q;
while(t->link != NULL)
{
r = r->link;
t = t->link->link;
if(r == t)
{
break;
}
}
if(t == NULL )
return NULL;
r = *q;
while(r != t)
{
t = t->link;
r = r->link;
}
return t->data;
}
int main()
{
struct node *p;
p = NULL;
char num;
Append(&p,'A');
Append(&p,'B');
Append(&p,'C');
Append(&p,'D');
Append(&p,'E');
Append(&p,'C');
Display(p);
num = FindStartNode(&p);
printf("\nStarting node of the cycle linked list is:- %c",num);
_getch();
return 0;
}
int Append(struct node **q, char data)
{
struct node *r,*t;
r = (struct node *)malloc(sizeof(struct node));
r->data = data;
r->link = NULL;
if(*q == NULL)
*q = r;
else
{
t = *q;
while(t->link != NULL)
{
t = t->link;
}
t->link = r;
}
return 0;
}
int Display(struct node *q)
{
while(q != NULL)
{
printf("%c\t",q->data);
q = q->link;
}
return 0;
}
ths is my code. I'm not getting any value in return t->data part or I'm unable to find the start node of cycle ink list.Any help?
t = t->link->link; // t->link can be null
//so t = t->link->link can be a crash or illegal reference
Change the loop to:
while(t != NULL)
{
r = r->link;
t = t->link;
if(t == NULL)
break; // or return no circle
else t = t->link;
if(r == t)
{
break;
}
}
I have gone through your code. Comparing with the algorithm discussion here it seems to be OK. But you are returning a char why dont you return a pointer so that you can check if it is NULL or not. In case it is not null then issue pt->tada. This makes more sense.
I checked you code it seems you are not implementing circular linked list correctly in Append(). I am providing you with a working implementation below. See how I modified Append()
#include <stdio.h>
#include <stdlib.h>
struct node
{
char data;
struct node *link;
} ;
char FindStartNode(struct node **q)
{
struct node *r,*t;
r = *q;
t = *q;
while(t->link != NULL)
{
r = r->link;
t = t->link->link;
if(r == t)
{
break;
}
}
if(t == NULL )
return NULL;
r = *q;
while(r != t)
{
t = t->link;
r = r->link;
}
return t->data;
}
int Append(struct node **q, char data);
int main()
{
struct node *p;
p = NULL;
char num;
Append(&p,'A');
Append(&p,'B');
Append(&p,'C');
Append(&p,'D');
Append(&p,'E');
Append(&p,'C');
//Display(p);
num = FindStartNode(&p);
printf("\nStarting node of the cycle linked list is:- %c\n",num);
//_getch();
return 0;
}
int Append(struct node **q, char data)
{
struct node *r,*t, *startOfcycle=NULL;
r = (struct node *)malloc(sizeof(struct node));
r->data = data;
r->link = NULL;
if(*q == NULL)
*q = r;
else
{
t = *q;
while(t->link != NULL)
{
if(t->data == data)
startOfcycle = t;
t = t->link;
}
if(startOfcycle == NULL)
t->link = r;
else {// there is a cycle point to the start of cycle
t->link = startOfcycle;
free(r);
}
}
return 0;
}
int Display(struct node *q)
{
while(q != NULL)
{
printf("%c\t",q->data);
q = q->link;
}
Please note that Display function is also wrong as runs an infinite loop of the linked list is circular. I have not modified it since it is not relevant to you question. Thanks.
...
p = NULL;
char num;
Append(&p,'A');
...
You are trying to assign to NULL, which Append handles, but you are doing it repeatedly, which means you won't make a list, just a bunch of dangling nodes.
You need to make one node to start, outside of append, as your seed node, and pass that in.