I'm creating a binary tree by linking individual nodes all the way up to the root node, which I return from the method.
MaxWinnerTree::MaxWinnerTree(int elements)
{
WinnerTree(elements);
}
`Node MaxWinnerTree::WinnerTree(int elements)
{
int size = 1;
while (size<elements)
size = size * 2; //gets closest power of 2 to create full bottom row
Node* a[size]; //array of pointers to nodes
for (int i = (2*elements-1); i>0; i--)
{
//Create nodes and link them to parent, right, and left values
if (i > elements-1) //leaf
{
//Create new nodes with data -1, store pointer to it in array
*a[i] = newNode(i,-1,NULL,NULL,NULL);
}
else // not leaf
{
//Create node with data = max of children, store pointer
*a[i] = newNode(i,-1,a[i*2],a[i*2 +1], NULL); //create
a[i]->data = max(a[i*2]->data, a[i*2+1]->data); //gets max
a[i]->right->parent = a[i];
a[i]->left->parent = a[i];
if(i=1)
root = a[i];
}
}
return *root; }
However, trying to create an object in my main method isn't working like it should.
MaxWinnerTree* tree = new MaxWinnerTree(elements);
Gives a standard x86 architecture error, where as
MaxWinnerTree tree = new MaxWinnerTree(elements);
Gives
main.cpp:22: error: invalid conversion from ‘MaxWinnerTree*’ to ‘int’
main.cpp:22: error: initializing argument 1 of ‘MaxWinnerTree::MaxWinnerTree(int)’
Why does the compiler think that my method is returning an int? What is to correct way to create an object in this fashion? In reality, I just need a pointer to the root node, where all my other methods will begin.
Thanks for any help in advance.
Changes I would make:
Change newNode (which you haven't shown us) to return a Node *. If newNode isn't actually allocating a new Node, then you need to rethink its design. Or, move the arguments to newNode into a constructor for Node, and change your code to read new Node( ... args ... ).
Instead of saying *a[i] = newNode( ... ) say a[i] = newNode( ... ) (or whatever you replace newNode with as per my first bullet). What you have written asks the C++ compiler to invoke a copy constructor to copy whatever newNode returned into the object pointed to by *a[i], but from the snippet you shared with us, *a[i] doesn't point to anything yet.
You've built a heap, but with explicit pointers. If you really wanted a heap, you don't need the explicit pointers...
This next line can just ruin your whole day. i=1 assigns 1 to i and then returns 1 as its value, which doesn't really do the right thing. In your case, it'll make your loop stop iterating as soon as it gets to the part of the heap-building where the elements have children.
if(i=1)
root = a[i];
Related
I am currently learning separate chaining to resolve collisions in hashing. Below shows an example that creates a hash table. I see hash_tbl *new_table = malloc(sizeof(hash_tbl)); allocates a big chunk of memory for new_table. Next, new_table->list = malloc(sizeof(node *) * size); seems to divide new_table by size to store the 1st level of pointer of node **list.
Q1: The part I can't figure out is that why I do NOT need to malloc() the 2nd level of the pointer at node **list; marked by ###?
Q2: Since the code is correct, does for (int i=0; i<size; i++){
new_table->list[i] = NULL; } initialize the head pointer of the linked list pointed to by new_tbl->list[i]?
p.s. Could someone can illustrate his explanation graphically?
typedef struct Node {
char *str;
struct Node *next;
} node;
typedef struct Hash_Tbl {
int size;
node **list; //###
} hash_tbl;
int main() {
int size = 6;
create_hash_table(size);
}
hash_tbl *create_hash_table(int size) {
if (size < 1) return NULL;
hash_tbl *new_table = malloc(sizeof(hash_tbl));
if (new_table == NULL) return NULL;
new_table->list = malloc(sizeof(node *) * size);
if (new_table->list == NULL) return NULL;
// Initialize the elements of the hash table
for (int i=0; i<size; i++){
new_table->list[i] = NULL;
}
new_table->size = size;
return new_table;
}
I can't figure out is that why do I NOT need to malloc() the 2nd level of the pointer at node **list;
Since the hash table starts off empty, you do not need to allocate the 2nd level yet. The code of create_hash_table sets all buckets to NULL to indicate that they are empty.
does [for loop] initialize the head pointer of the linked list pointed to be new_tbl->list[i]?
There isn't one "head pointer" in a hash table. Each element of the list[] array is a head pointer of its own. All these pointers are initialized to NULL, indicating that their corresponding bucket is empty.
Initially, all bucket lists are empty. When you start adding items to the hash table, the lists start filling in.
The diagram below shows a hash table with six buckets. Buckets 1 and 3 have some items; the remaining buckets are empty. Bucket 1 has no collisions, while bucket 3 has a two-way collision.
The part I can't figure out is that why do I NOT need to malloc() the 2nd level of the pointer at node **list; marked by ###?
The 2nd level of pointer will be allocated whenever required. This is just the initialization part and that is why we simply initialize it to NULL here.
Since the code is correct, does for (int i=0; ilist[i] = NULL; } initialize the head pointer of the linked list pointed to be new_tbl->list[i]?
Consider new_table->list as an array of pointers. With each element representing a chain of nodes. So, in a sense you are correct. Each element of this array could be a head to the respective chains/buckets you are going to form later on.
I'm intentionally creating a wrong and unbalanced binary tree in this code:
void createlist (tree*& node) {
node = new tree;
node->num = 1;
node->left = new tree;
node->left ->num = 2;
node->right = new tree;
node->right->num = 3;
node->left->left = new tree;
node->left->left->num = 4;
node->left->right = new tree;
node->left->right->num = 5;
node->right->left = new tree;
node->right->left->num = 6;
node->left->left->left = new tree;
node->left->left->left->num = 7;
}
Then, when I am trying to print it using an ordinary function for that:
void print (tree* node) {
if (node!= 0) {
print (node->left);
cout << node->num << " ";
print (node->right);
}
}
It throws out an error:
Access violation reading location 0xcdcdcdd5.
at this location:
print (node->left);
I'm just starting with trees and don't quite follow the reason for this error. Could you help with that?
This is an excellent chance for you to learn how to debug your programs. I suggest you run the program in a debugger and see what the values of node and node->left is when the segfault happens.
An access violation is when you are accessing memory that your program is not allowed to access.
Your problem is not trees your problem is using pointers correctly and not initializing your variables properly.
I suspect your problem is that the constructor for tree is not properly doing:
left = NULL;
right = NULL;
Remember in C/C++ that the compiler does not set any specific values into variables when they are created, it is up to you to initialize variables.
It is custom to use NULL (or nullptr in C++11) to rather than 0 to test/set pointers.
Link to C++ pointers tutorial
Hard to tell without the source of your tree class, but perhaps making a new tree doesn't initialize the left and right members to null pointers? In that case, some of your trees will contain uninitialized pointer data.
I am working on a project where I create a double bounded pointer list, delete several elements, and still be able to read off the list. I have a double bounded pointer list, but am having trouble deleting elements and keeping the list double bounded. This then causes issues when trying to print the list.
Below is the IF statement I've placed in a while loop to help delete unwanted elements. I keep getting a segmentation fault (core dumped).
if ((black2 != black)||(white2 != white)) {
dump = help;
help = help ->next;
dump -> before = temp;
temp -> next = help;
help ->before = temp;
delete dump;
}//if
else { temp = help;
help = help->next;
help ->before = temp; }//else
To maintain properly the doubly linked list you should do something like :
void remove(X *elt) {
X* before = elt->before;
X* after = elt->next;
if (before != NULL) { // assuming first element points to NULL
before->next = after;
}
else {
first = after; // assuming first is a pointer to first element of list
}
if (after != NULL) { // assuming last element points to NULL
after->before = before;
}
else {
last = before; // assuming last is a pointer to last element
}
delete elt;
}
That way, you ensure that elements around current correctly point to each other dealing with special cases of removing first or last element.
But you already have a std::list template in Standard Template Library
One logical issue in your code is the line dump->before = temp.
What this does is that it sets the previous node pointer of dump to temp, as opposed to defining temp as the previous node.
The correct line should read temp = dump->before
PS: Your code is correct assuming that the node you are deleting isn't the first or last node (and you haven't padded with dummy nodes). You should introduce checks for these cases if required.
So, I'm getting a heap corruption error in the Expand method for an Ordered List Class I'm working on. The expand method is called when the client tries to Insert() a new item into the list, and there isn't currently room left in the array. When I take the delete line out, the program runs fine, but I know I have an inaccessible object each time it expands. However, when I put the delete line in, the program explodes at run-time.
Additionally, this only happens in my Expand() method. It doesn't do this in my Contract() method, which is called each time there is a deletion from the list that brings the number of list elements down below 1/4 the total space currently available, it cuts the size in half. I can delete the old list in this method without any problems.
GetListPtr(), SetListPtr(), and GetLength() are all inherited from a ListClass object, which I received in the form of a header file and object code, so I'm not sure exactly how they work. ItemType is a struct, only containing an integer field, key.
I've read a number of questions on here already and didn't find any that seemed to provide any help in regards to my situation.
void OrdListClass::Expand()
{
ItemType* newList = new ItemType[size * 2];
ItemType* temp = GetListPtr();
size = size * 2;
// Copy the current list to the new list.
for(int i = 0; i < GetLength(); i++)
newList[i] = temp[i];
// Point to the new list.
SetListPtr(newList);
// Delete the old list
delete temp; <-- This line
// Reset the pointers
temp = nullptr;
newList = nullptr;
}
void OrdListClass::Contract()
{
ItemType* newList = new ItemType[size / 2];
ItemType* temp = GetListPtr();
size = size / 2;
// Copy the old list into the new one
for(int i = 0; i < GetLength(); i++)
newList[i] = temp[i];
// Set the list pointer to point to the new list
SetListPtr(newList);
// Delete the old list
delete temp;
temp = nullptr;
newList = nullptr;
}
Thanks again for reading this, any and all help is appreciated.
I assume that your list was allocated with:
ItemType* newList = new ItemType[size * 2];
If that's the case, you need to do:
delete[] temp;
Elements allocated with new[], need to be deleted with delete[].
http://www.cplusplus.com/reference/new/operator%20delete[]/
I'm trying to deep copy a linked list . I need an algorithm that executes in Linear Time O(n). This is what i have for now , but i'm not able to figure out what's going wrong with it. My application crashes and i'm suspecting a memory leak that i've not been able to figure out yet. This is what i have right now
struct node {
struct node *next;
struct node *ref;
};
struct node *copy(struct node *root) {
struct node *i, *j, *new_root = NULL;
for (i = root, j = NULL; i; j = i, i = i->next) {
struct node *new_node;
if (!new_node)
{
abort();
}
if (j)
{
j->next = new_node;
}
else
{
new_root = new_node;
}
new_node->ref = i->ref;
i->ref = new_node;
}
if (j)
{
j->next = NULL;
}
for (i = root, j = new_root; i; i = i->next, j = j->next)
j->ref =i->next->ref;
return new_root;
}
Can anyone point out where i'm going wrong with this ??
This piece alone:
struct node *new_node;
if (!new_node)
{
abort();
}
Seems good for a random abort() happening. new_node is not assigned and will contain a random value. The !new_node expression could already be fatal (on some systems).
As a general hint, you should only require 1 for-loop. Some code upfront to establish the new_root.
But atruly deep copy would also require cloning whatever ref is pointing to. It seems to me the second loop assigns something from the original into the copy. But I'm not sure, what is ref ?
One thing I immediately noticed was that you never allocate space for new_node. Since auto variables are not guaranteed to be initialized, new_node will be set to whatever value was in that memory before. You should probably start with something like:
struct node *new_node = (new_node *) malloc(sizeof(struct node));
in C, or if you're using C++:
node* new_node = new node;
Copying the list is simple enough to do. However, the requirement that the ref pointers point to the same nodes in the new list relative to the source list is going to be difficult to do in any sort of efficient manner. First, you need some way to identify which node relative to the source list they point to. You could put some kind of identifier in each node, say an int which is set to 0 in the first node, 1 in the second, etc. Then after you've copied the list you could make another pass over the list to set up the ref pointers. The problem with this approach (other that adding another variable to each node) is that it will make the time complexity of the algorithm jump from O(n) to O(n^2).
This is possible, but it takes some work. I'll assume C++, and omit the struct keyword in struct node.
You will need to do some bookkeeping to keep track of the "ref" pointers. Here, I'm converting them to numerical indices into the original list and then back to pointers into the new list.
node *copy_list(node const *head)
{
// maps "ref" pointers in old list to indices
std::map<node const *, size_t> ptr_index;
// maps indices into new list to pointers
std::map<size_t, node *> index_ptr;
size_t length = 0;
node *curn; // ptr into new list
node const *curo; // ptr into old list
node *copy = NULL;
for (curo = head; curo != NULL; curo = curo->next) {
ptr_index[curo] = length;
length++;
// construct copy, disregarding ref for now
curn = new node;
curn->next = copy;
copy = curn;
}
curn = copy;
for (size_t i=0; i < length; i++, curn = curn->next)
index_ptr[i] = curn;
// set ref pointers in copy
for (curo = head, curn = copy; curo != NULL; ) {
curn->ref = index_ptr[ptr_index[curo->ref]];
curo = curo->next;
curn = curn->next;
}
return copy;
}
This algorithm runs in O(n lg n) because it stores all n list elements in an std::map, which has O(lg n) insert and retrieval complexity. It can be made linear by using a hash table instead.
NOTE: not tested, may contain bugs.