Related
I am trying to implement a double linked list in C++. I get an error which I do not understand. It is a runtime error in else branch at line:
list->tail->next = new_node;
It says that list->tail was at a different memory address. Unfortunately, I have the German version of Visual Studio, so I can not translate it that good. The error is marked as a "write access violation".
Could someone explain me what is going on here?
#include <iostream>
typedef struct dlist_node dlist_node;
struct dlist_node { // represents one node with its data and with pointers to the next and
dlist_node* next; // previous node
dlist_node* prev;
int data;
};
typedef struct { // represents nodes of the list that one can access
dlist_node* head;
dlist_node* tail;
} dlist;
void dlist_append(dlist* list, int data) { // to append the list with new data/node
dlist_node* new_node = new dlist_node;
new_node->data = data;
new_node->next = new_node->prev = NULL;
if (list->tail == NULL) { // if list is empty
list->head = list->tail = new_node;
}
else {
list->tail->next = new_node; // error appears here
new_node->prev = list->tail;
list->tail = new_node;
}
}
int main() {
dlist* double_linked_list = new dlist;
std::cout << double_linked_list->head;
dlist_append(double_linked_list, 42);
std::cout << double_linked_list->head;
}
If you are still stuck, then let's see if we can get you unstuck. While C++ already provides doubly linked-list in std::list which should be the preferred list implementation over writing your own. That said, we understand that many of the linked-list self-implementation are exercises for educational purposes, either for self-study or as part of a class. That is fine, you need to fully understand them, there is a lot of legacy-code out there that makes use of all types of self-invented lists.
As noted in the comments, among other issues, your biggest issue is you do not allocate and initialize your dlist_node nodes when adding nodes to your list. Your list has two separate struct, dlist that holds the head and tail pointers (which with a more encapsulated approach can be made members of the same struct or class where your prev and next and payload (data) pointers are declared, and the functions that operate on the list would be member functions)
Using the separate struct is fine, and using both head and tail pointers within the struct ensures your list additions can be done in-order in O(1) time. While your code has been edited, there is no reason to allocate for dlist double_linked_list. You have a struct, you can simply create an instance. The pointers head and tail will point to a dlist_node that you allocate and initialize with each node you add to your list.
The key is that head will always point to the first node in your list and tail will always point to the last. This provides the starting points for iterating over each node in your list in the forward, and reverse directions. When you add (or append) a node to your list, after setting the prev and next pointers correctly for each node involved, you simply update the head (if inserting a new first node), or tail (if adding to the end of the list) pointers accordingly.
When using a simple int as the list payload, you can easily allocate for and initialize your new node in your add (append) node function. However, as your payloads become more complicated, it is often convenient to write a createnode() function that takes the values needed to fully initialize the node as parameters and then allocates for and fully initializes the node, returning a pointer to the new node on success, or nullptr in the case of allocation failure. This allows you to reuse your add() function and only customize your createnode() for each new list.
Before looking at your add and create node functions, let's look at your structs themselves. While in C, it is convenient to use typedef to create an alias for struct dlist or struct dlist_node, in C++ that is completely unnecessary and often causes more problems than it solves. When you declare a struct in C++, you simply create an instance of the struct and can refer directly to the struct name as a type, e.g.
struct dlist_node { /* list node */
int data;
struct dlist_node *prev, *next;
};
struct dlist { /* list wrapper with head & tail pointers */
dlist_node *head, *tail;
};
Now for an add() (your append) and a createnode() function, you could do the following:
/** create new node initialize all members */
dlist_node *createnode (int v)
{
dlist_node *node = new dlist_node; /* allocate node */
if (!node) /* validate allocation (and use try/catch) */
return nullptr;
node->data = v; /* initialize members values */
node->prev = node->next = nullptr;
return node; /* return new node */
}
/** add node at end of list, update tail to end */
dlist_node *add (dlist *l, int v)
{
dlist_node *node = createnode (v); /* allocate node, initialize data */
if (!node) /* validate allocation */
return nullptr;
if (!l->head) /* if 1st node, node is head/tail */
l->head = l->tail = node;
else { /* otherwise */
node->prev = l->tail; /* set prev to tail */
l->tail->next = node; /* add at end, update tail pointer */
l->tail = node;
}
return node; /* return new node */
}
Always validate that your allocation has succeeded and handle the error if it fails.
Now to create a list in main() (or any other scope where the list is needed) you simply declare an instance of the struct and initialize both head and tail to nullptr (which can be moved to the constructor so it happens automatically), you can do:
dlist list = { nullptr, nullptr }; /* initialize list pointers nullptr */
To create a list named list. To test the list, add a few nodes to the list, check the list both forward and backwards, and then remove all the nodes in a random order checking all pointers after the removal of each node, e.g.
#define NNODES 16
...
dlist list = { nullptr, nullptr }; /* initialize list pointers nullptr */
int a[NNODES]; /* array to shuffle */
for (int i = 0; i < NNODES; i++) { /* fill array with NNODES int */
add (&list, i+1);
a[i] = i+1;
}
(the array is used to hold the node values, so you can shuffle the array and then iterate over the shuffled array removing the nodes in a random order)
You generally will want a function to allow you to delete a specific node, and then all nodes when the list is no longer needed, freeing the memory for a given, or all nodes. You need a function to print the list in forward and reverse directions. If you modify the example I linked to to use new and delete instead of malloc and free and use iostream instead of stdio.h, you would have:
#include <iostream>
#include <random>
#ifndef NNODES
#define NNODES 16
#endif
/*
* non-list misc functions
*/
/** shuffle integer array of size 'n'
* (using fisher-yates method)
*/
void shuffle (int *a, int n)
{
std::random_device rd; /* random seed */
std::mt19937 gen(rd()); /* standard mersenne_twister_engine */
std::uniform_int_distribution<> dist(0, NNODES - 1); /* distribution 0, 15 */
int i, tmp;
while (n-- > 1) {
i = dist(gen);
tmp = a[i];
a[i] = a[n];
a[n] = tmp;
}
}
/*
* list structs and functions
*/
struct dlist_node { /* list node */
int data;
struct dlist_node *prev, *next;
};
struct dlist { /* list wrapper with head & tail pointers */
dlist_node *head, *tail;
};
/** create new node initialize all members */
dlist_node *createnode (int v)
{
dlist_node *node = new dlist_node; /* allocate node */
if (!node) /* validate allocation (and use try/catch) */
return nullptr;
node->data = v; /* initialize members values */
node->prev = node->next = nullptr;
return node; /* return new node */
}
/** add node at end of list, update tail to end */
dlist_node *add (dlist *l, int v)
{
dlist_node *node = createnode (v); /* allocate node, initialize data */
if (!node) /* validate allocation */
return nullptr;
if (!l->head) /* if 1st node, node is head/tail */
l->head = l->tail = node;
else { /* otherwise */
node->prev = l->tail; /* set prev to tail */
l->tail->next = node; /* add at end, update tail pointer */
l->tail = node;
}
return node; /* return new node */
}
/** print all nodes in list */
bool prn (dlist *l)
{
if (!l->head) {
std::cout << "list-empty\n";
return false;
}
for (dlist_node *n = l->head; n; n = n->next)
std::cout << ' ' << n->data;
std::cout.put('\n');
return true;
}
/** print all nodes in list in reverse */
bool prnrev (dlist *l)
{
if (!l->tail) {
std::cout << "list-empty\n";
return true;
}
for (dlist_node *n = l->tail; n; n = n->prev)
std::cout << ' ' << n->data;
std::cout.put('\n');
return false;
}
/** delete node with value v from list (for loop) */
bool del_node (dlist *l, int v)
{
if (!l->head) {
std::cout << "list-empty\n";
return false;
}
dlist_node **ppn = &l->head; /* pointer to pointer */
dlist_node *pn = l->head; /* pointer to node */
for (; pn; ppn = &pn->next, pn = pn->next) {
if (pn->data == v) {
*ppn = pn->next; /* set node at address to next */
if (pn != l->tail) /* prev is next prev */
(*ppn)->prev = pn->prev;
else /* deleting tail, set tail to prev */
l->tail = pn->prev;
delete pn; /* free current */
pn = nullptr;
break;
}
}
return true;
}
/** delete all nodes in list */
void del_nodes (dlist *l)
{
dlist_node *n = l->head;
while (n) {
dlist_node *victim = n;
n = n->next;
delete victim;
}
l->head = l->tail = nullptr;
}
int main (void) {
dlist list = { nullptr, nullptr }; /* initialize list pointers nullptr */
int a[NNODES]; /* array to shuffle */
for (int i = 0; i < NNODES; i++) { /* fill array with NNODES int */
add (&list, i+1);
a[i] = i+1;
}
shuffle (a, NNODES); /* shuffle array for random removal */
prn (&list); /* print list forward */
prnrev (&list); /* print list reverse */
std::cout.put('\n');
for (int i = 0; i < NNODES; i++) { /* remove all nodes in random order */
std::cout << "deleting : " << a[i] << '\n';
del_node (&list, a[i]); /* delete node with random value a[i] */
if (prn (&list)) { /* print list forward if nodes remain */
prnrev (&list); /* print list reverse if nodes remain */
std::cout.put('\n'); /* tidy up with a '\n' */
}
}
}
Example Use/Output
$ ./bin/dlist_dlist_node
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
deleting : 1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2
deleting : 9
2 3 4 5 6 7 8 10 11 12 13 14 15 16
16 15 14 13 12 11 10 8 7 6 5 4 3 2
deleting : 12
2 3 4 5 6 7 8 10 11 13 14 15 16
16 15 14 13 11 10 8 7 6 5 4 3 2
deleting : 7
2 3 4 5 6 8 10 11 13 14 15 16
16 15 14 13 11 10 8 6 5 4 3 2
deleting : 16
2 3 4 5 6 8 10 11 13 14 15
15 14 13 11 10 8 6 5 4 3 2
deleting : 5
2 3 4 6 8 10 11 13 14 15
15 14 13 11 10 8 6 4 3 2
deleting : 8
2 3 4 6 10 11 13 14 15
15 14 13 11 10 6 4 3 2
deleting : 14
2 3 4 6 10 11 13 15
15 13 11 10 6 4 3 2
deleting : 4
2 3 6 10 11 13 15
15 13 11 10 6 3 2
deleting : 3
2 6 10 11 13 15
15 13 11 10 6 2
deleting : 13
2 6 10 11 15
15 11 10 6 2
deleting : 2
6 10 11 15
15 11 10 6
deleting : 6
10 11 15
15 11 10
deleting : 10
11 15
15 11
deleting : 11
15
15
deleting : 15
list-empty
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/dlist_dlist_node
==17580== Memcheck, a memory error detector
==17580== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==17580== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==17580== Command: ./bin/dlist_dlist_node
==17580==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
deleting : 15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 16
16 14 13 12 11 10 9 8 7 6 5 4 3 2 1
...
deleting : 16
12
12
deleting : 12
list-empty
==17580==
==17580== HEAP SUMMARY:
==17580== in use at exit: 0 bytes in 0 blocks
==17580== total heap usage: 19 allocs, 19 frees, 74,664 bytes allocated
==17580==
==17580== All heap blocks were freed -- no leaks are possible
==17580==
==17580== For counts of detected and suppressed errors, rerun with: -v
==17580== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
Link of the question-[Link][1]
Basically we are given an array of integers and it's size. Question is to construct a binary tree from it. Each index corresponds to data stored in a node, and the value of that index is the data of the parent. Value of the root node index would always be -1 as there is no parent for root. The Output will be the sorted level order traversal of the tree.
Now my approach is that I parse the array from 1 to n(not the 0th element/root node), and for each element, I get it's parent using the first function, and insert the child accordingly. But one particular test case is failing. Maybe the website's own output is not correct. I will post everything below:-
Example test case-
Size of array-7
Elements- -1 0 0 1 1 3 5
Output- 0 1 2 3 4 5 6
Particular test case(which is my doubt)-
Size of array- 42
Elements-
3 19 1 41 35 29 27 11 17 23 9 15 33 13 39 23 19 25 21 1 33 15 31 21 5 7 37 29 7 11 31 39 -1 27 3 9 25 17 13 41 37 35
Website's output- 32
My output - 0
Functions
void getParent(Node* root, int val, Node* &main)
{
if(root==NULL) return;
if(root->data==val){
main=root;
return;
}
getParent(root->left,val,main);
getParent(root->right,val,main);
}
Node *createTree(int parent[], int n)
{
if(n==0) return NULL;
Node * root=new Node(0);
for(int i=1;i<n;i++)
{
Node* main=NULL;
getParent(root,parent[i],main);
//main has the parent
Node* child=new Node(i);
if(main==NULL) break;
if(main->left==NULL)
{
main->left=child;
}
else if(main->right==NULL)
{
main->right=child;
}
}
return root;
}
[1]: https://www.geeksforgeeks.org/construct-a-binary-tree-from-parent-array-representation/
[2]: https://i.stack.imgur.com/0fRmn.png
Not sure what you are doing with your getParent method. Also you are initiating a root node with value 0 and not doing anywith it in the loop and then finally you return the root. I suspect your root will always have a value 0.
The solution is very simple actually. You initialize an array of nodes with each node's value as the index of the array. For example for an array of size 5, you create an array of 5 nodes with each node having a value of the index at which it is located.
Then next step is go through the parent array and see if the node located at parent[i] has either left or right "available", if yes assign the node accordingly.
the code is :
Node* createTree(int parent[], int n) {
Node** nodes = new Node*[n];
for ( int i = 0; i < n; i++ )
nodes[i] = new Node(i);
int rootIndex = 0;
for ( int i = 0; i < n; i++ ) {
if ( parent[i] == -1 ) {
rootIndex = i;
} else {
if ( nodes[parent[i]] -> left == NULL ) {
nodes[parent[i]] -> left = nodes[i];
} else if ( nodes[parent[i]] -> right == NULL ) {
nodes[parent[i]] -> right = nodes[i];
}
}
}
return nodes[rootIndex];
}
I have two chains where lets say chain 1 has head, 1 , 2 , 3 , 4 and chain 2 had head, 5, 6, 7, 8. Weaving it should produce chain 1 with head, 1, 5, 2, 6, 3, 7, 4, 8. My function is currently weaving, but only for the first 2 and it stops.
void Chain::weave(Chain & other) {
while (length_ > 0 && other.length_ > -1){
Node * current = head_->next;
Node * otherNode = other.head_->next;
Node * currentNext = current->next;
Node * currentPrev = current->prev;
Node * otherNext = otherNode->next;
Node * otherPrev = otherNode->prev;
if (current != NULL && otherNode != NULL){
current->next = otherNode;
currentNext = otherNode->next;
currentNext->next = otherNext;
length_++;
other.length_--;
}
For class I have to create a binaryTree and I can't seem to get the insert method to work properly.
Expected results:
first: tree is not empty
no of nodes = 15
height of tree = 5
The elements of 'first' in inorder:
-11 8 -3 12 -1 -9 -5 2 16 10 6 -13 4 14 -7
The elements of 'first' in preorder:
2 -1 -3 8 -11 12 -5 -9 4 6 10 16 -13 -7 14
The elements of 'first' in postorder:
-11 8 12 -3 -9 -5 -1 16 10 -13 6 14 -7 4 2
second: tree is not empty
no of nodes = 9
height of tree = 4
The elements of 'second' in inorder:
7 3.25 0.75 -7.75 -0.5 -11.5 4.5 -4 8.25
The elements of 'second' in preorder:
-0.5 0.75 3.25 7 -7.75 -4 4.5 -11.5 8.25
The elements of 'second' in postorder:
7 3.25 -7.75 0.75 -11.5 4.5 8.25 -4 -0.5
third: tree is not empty
no of nodes = 7
height of tree = 4
The elements of 'third' in inorder:
objects. list is string This of a
The elements of 'third' in preorder:
This is list objects. string a of
The elements of 'third' in postorder:
objects. list string is of a This
My Results:
first: tree is not empty
no of nodes = 15
height of tree = 4
The elements of 'first' in inorder:
-9 -5 4 16 -1 -13 10 -7 2 14 8 6 -3 -11 12
The elements of 'first' in preorder:
2 -1 4 -5 -9 16 -7 10 -13 -3 6 8 14 12 -11
The elements of 'first' in postorder:
-9 -5 16 4 -13 10 -7 -1 14 8 6 -11 12 -3 2
second: tree is not empty
no of nodes = 9
height of tree = 3
The elements of 'second' in inorder:
-7.75 -4 0.75 -11.5 8.25 -0.5 7 4.5 3.25
The elements of 'second' in preorder:
-0.5 0.75 -4 -7.75 8.25 -11.5 3.25 4.5 7
The elements of 'second' in postorder:
-7.75 -4 -11.5 8.25 0.75 7 4.5 3.25 -0.5
third: tree is not empty
no of nodes = 7
height of tree = 3
The elements of 'third' in inorder:
string a is This objects. of list
The elements of 'third' in preorder:
This is a string list of objects.
The elements of 'third' in postorder:
string a is objects. of list This
Code:
template <class T>
void binTree<T>::insert(binTreeNode < T >*& node, const T& data) {
if(node == NULL) {
root = new binTreeNode<T>(data, NULL, NULL);
return;
}
binTreeNode<T>* ptr1 = node;
binTreeNode<T>* ptr2 = node;
bool placeRight = 0;
while(ptr1 != NULL) {
ptr2 = ptr1;
if(height(ptr1->left) > height(ptr1->right)) {
placeRight = true;
ptr1 = ptr1->right;
} else if (height(ptr1->right) > height(ptr1->left)) {
placeRight = false;
ptr1 = ptr1->left;
} else {
placeRight = false;
ptr1 = ptr1->left;
}
}
if(placeRight) {
ptr2->right = new binTreeNode<T>(data, NULL, NULL);
} else {
ptr2->left = new binTreeNode<T>(data, NULL, NULL);
}
}
Driver Program:
const vector<int> A { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12, 13, -14, 15 };
const vector<float> B { 0.5, 1.75, -3, 4.25, 5.50, -6.75, 8, 9.25, -10.5 };
const vector<string> C { "This", "is", "a", "list", "of", "string", "objects." };
int main() {
binTree<int> intTree = binTree<int>();
binTree<float> floatTree = binTree<float>();
binTree<string> strTree = binTree<string>();
for (std::vector<int>::const_iterator it = A.begin() ; it != A.end(); ++it) {
intTree.insert(*it);
}
intTree.preorder(increase);
cout << "first: ";
header(intTree);
inorder(intTree, "first");
preorder(intTree, "first");
postOrder(intTree, "first");
}
Functions to display results: (should be correct)
template <class T>
void binTree<T>::inorder(binTreeNode < T >* node, void (*f)(T&))
{
if (node == NULL) {
return;
}
inorder(node->left,f);
f(node->data);
inorder(node->right,f);
}
template <class T>
void binTree<T>::preorder(binTreeNode < T >* node, void(*f)(T&))
{
if (node == NULL) {
return;
}
f(node->data);
preorder(node->left, f);
preorder(node->right, f);
}
template <class T>
void binTree<T>::postorder(binTreeNode < T >* node, void(*f)(T&))
{
if (node == NULL) {
return;
}
postorder(node->left, f);
postorder(node->right, f);
f(node->data);
}
template <class T>
int binTree<T>::height(binTreeNode <T>* node) const {
if (node == NULL || ((node->left == NULL) && (node->right == NULL))) {
return 0;
}
int leftSide = height(node->left);
int rightSide = height(node->right);
if (leftSide > rightSide) {
return leftSide + 1;
} else {
return rightSide + 1;
}
}
Your bug is in your height method. If you have a node which is not null but has no children, you are returning zero. You should be returning 1.
Change this condition in your height method from:
if (node == NULL || ((node->left == NULL) && (node->right == NULL))) {
return 0;
}
to:
if (node == NULL) {
return 0;
}
It appears the sign of your vector A is backwards. You have 1,-2,3,-4,... but the correct solution has -1,2,-3,4,.... Similarly, you B is
const vector<float> B { 0.5, 1.75, -3, 4.25, 5.50, -6.75, 8, 9.25, -10.5 };
Comparing this with the elements you say we are expecting:
7, 3.25, 0.75, -7.75, -0.5, -11.5, 4.5, -4, 8.25
These don't look even close to identical.
Transcription error somewhere?
What is your height() function ?
I think you misunderstand the definition of the BST:
A. the value of the left child is smaller than the value of root node.
B. the value of the right child is bigger than the value of root node.
C. his left child tree and right child tree are also a BST.
But through your code here:
while(ptr1 != NULL) {
ptr2 = ptr1;
if(height(ptr1->left) > height(ptr1->right)) {
placeRight = true;
ptr1 = ptr1->right;
} else if (height(ptr1->right) > height(ptr1->left)) {
placeRight = false;
ptr1 = ptr1->left;
} else {
placeRight = false;
ptr1 = ptr1->left;
}
}
you just compare the height of your node instead of comparing the real value of the node.
I'm trying to write a method which adds a key-value pair to a tertiary tree, but I'm obviously doing something wrong as I get a segfault whenever I reach the marked code
void Tree::add(int k, Node *&r)
{
cout<<"add"<<endl;
if(r==NULL){
r = new Node(k);
//check(heap area);
}
begin problem code
else if(r->keyCount == 1){
cout<<"adding second key";
if(r->getKey() < k){
Node * temp = new Node(r->getKey(),k,r->data[0],0);
delete r;
r = temp;
r->keyCount++;
cout<<"test"<<endl;
}
else
{
Node * temp = new Node(k,r->getKey(),0,r->data[0]);
delete r;
r = temp;
r->keyCount++;
cout<<"test"<<endl;
}
end code
}
else if(k < r->getKey())
{
cout<<"left"<<endl;
add(k,r->child[Node::L]);
}
else if(r->keyCount > 1 && k < r->getKey(1))
{
cout<<"middle"<<endl;
add(k,r->child[Node::M]);
}
else if(r->keyCount > 1 && k > r->getKey(1))
{
cout<<"right"<<endl;
add(k,r->child[Node::R]);
}
else
r = new Node(k);
}
What I'm trying to do is, in the case that there is only 1 out of the 2 keys used in this particular node, replace the current node with a new node which has the keys in the appropriate places (lesser val in key[0], greater val in key[1])
How do I do this properly?
My code apparently deletes both the address AND pointer for the old node, but doesn't properly reassign the pointer to the new node.
EDIT
updated code. the output is as follows:
% p4
Enter pairs consisting of an int and a double. I create a
ternary tree, keeping the data in order, by int. Finish entering
data by pressing ^d
2 2
add
Entering the pair: 2, 2
1 1
add
adding second key to current node
test
Entering the pair: 1, 1
-1 -1
add
left
add
Entering the pair: -1, -1
3 3
add
right
Segmentation Fault
EDIT 2
Here's a link to a zip containing the entire project if you want to look at all the code: http://sdrv.ms/WSrLfv
EDIT 3
More error data - output from gdb on crash
Program received signal SIGSEGV, Segmentation fault.
0x08051628 in getData (x=#0x8047554) at testTree.cc:26
26 x[k]=d;
Current language: auto; currently c++
EDIT 4
stepping through gdb to the segfault:
Breakpoint 1, Tree::add (this=0x8047554, k=3, r=#0x8047554) at tree.cc:58
58 cout<<"add"<<endl;
(gdb) n
add
61 if(r==NULL){
(gdb) n
65 else if(r->keyCount == 1){
(gdb) n
87 else if(k < r->getKey())
(gdb) n
92 else if(r->keyCount > 1 && k < r->getKey(1))
(gdb) n
97 else if(r->keyCount > 1 && k > r->getKey(1))
(gdb) n
99 cout<<"right"<<endl;
(gdb) n
right
100 add(k,r->child[Node::R]);
(gdb) n
Breakpoint 1, Tree::add (this=0x8047554, k=3, r=#0x806416c) at tree.cc:58
58 cout<<"add"<<endl;
(gdb) n
add
61 if(r==NULL){
(gdb) n
62 r = new Node(k);
(gdb) n
107 }
(gdb) n
107 }
(gdb) n
Tree::operator[] (this=0x8047554, index=3) at tree.cc:47
47 return *(locate(index,root)->data);
(gdb) n
48 }
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x08051628 in getData (x=#0x8047554) at testTree.cc:26
26 x[k]=d;
(gdb)
This should be working.
In response to your edit: I noticed something interesting in your ouput:
-1 -1
add
left
add
Entering the pair: -1, -1
Notice how it says "left" and then it says "add" afterward because of the recursive call. However, in the input that crashes the program you don't see "add" after:
3 3
add
right
Segmentation Fault
If you look at your Tree::locate function:
Node * Tree::locate(int k, Node *rt) const
{
if(rt==NULL)
return rt;
if(k==rt->getKey())
return rt;
if(rt->keyCount>1 && k==rt->getKey(1))
return rt;
if(k < rt->getKey())
{
return locate(k,rt->child[Node::L]);
}
else if(rt->keyCount>1 && k < rt->getKey(1))
{
return locate(k,rt->child[Node::M]);
}
else if(rt->keyCount>1 && k<rt->getKey(1))
{
return locate(k,rt->child[Node::R]);
}
else
return NULL;
}
This line:
else if(rt->keyCount>1 && k<rt->getKey(1))
is the same condition as the previous one, so it is being skipped completely.