I've been trying to implement a heap into my program. It seems to me that heaps are the same as binary trees. Is this the case with all heaps such as min heap and max heap since all that is being done is a traversal through the tree putting the largest/smallest node to the top?
Also, I've read that using 1-D arrays are only beneficial when we have a complete binary tree. If we don't have a complete binary tree, it would be more beneficial to use class that is a friend class to another? Why is that? Such as:
template<class T> class BT; // forward declartion -> added at edit
template<class T>
class BTNode{
friend class BT<T>; // not sure why we need two classes
private:
T data;
BTNode<T> *leftChild; // what is the benefit of making a object Node?
BTNode<T> *rightChild;
};
template<class T>
class BT{
private:
BTNode<T> *root; // what is the benefit of having this root in another class?
};
Thank you in advance.
There's a perfectly good heap implementation in the standard library; you should take a look at it (but it is a useful learning exercise to write your own, too.)
A binary heap is a binary tree, but it is stored efficiently as a vector. The links are implicit. That is to say, the children of the node at position i (zero-based) are at 2i+1 and 2i+2. (At most one node in a heap has only one child.) That means that you don't actually have to store links, so in the case of small data objects (like integers), you're saving at least two-thirds of the needed space.
Wikipedia has a nice article on binary heaps (the kind you normally store in vectors), but it also has a number of articles on other types of heaps.
Related
So I am in process of coding class for some graph structure (suffix tree), and I encountered this difficult thing: a node should have pointers, one pointing on its parent, and also a set of pointers to its sons. I am using smart pointers to avoid errors with memory, and here is the thing: I write
class node {
...
std::shared_ptr<node> parent;
...
};
I guess there is a term for this thing. Like self-referencing, or whatever. When I wrote it, initialy i was confident, that there will be an error, but no it had been successfully compiled. I was curious, can i write something like that:
class some_class_2{
...
std::vector<some_class_2> some_vector;
std::string string_;
some_class() {
string_ = "lol";
some_vector = std::vector<some_class>(10);
}
};
Its appeared that the answer on this question is yes. So when i launched the test programm which had been succesfully compiled, of course it wouldn't stop, maybe i waited not enough and it should throw me some memory related error.
So the question is, how you should handle with this kind of things in c++? Isn't it strange that those things allowed in c++? Is it normal to put std::shatre_ptr inside some_class? How to write safe code, where errors like in some_class_2 are avoided, and what is the best way to
represent graph structure?
If the language did not allow any use of node inside the definition of node, then there would be no way to create linked data structures such as lists and trees. In order for the language to be useful, it has to allow such constructs as:
struct node {
int key;
node* next;
};
On the other hand, the language cannot allow this:
struct node {
int key;
node next;
};
because then a node object would contain an infinite nested sequence of node objects and be infinitely large.
The way the language deals with this is to allow members of classes only to be complete types. A complete type's size is known. A class type is not complete until its full definition has been seen. So node is not complete inside its own definition, so you cannot put a node member inside a node object. But node* is complete even when node is not complete yet.
Some standard library templates can be used with complete types. The smart pointers, std::unique_ptr<T>, std::shared_ptr<T>, and std::weak_ptr<T>, are allowed to have incomplete T, since they have pointer semantics. However, std::vector does not allow its template parameter to be incomplete, and the result is undefined behaviour. The way to avoid this is to just not write it (it's not that hard).
In c++, We all know that this code is wrong:
class Node {
public:
Node node;
};
However, declaring a vector like this is right, WHY?
class Node {
public:
std::vector<Node> nodeVec;
};
It works just fine in the C++14 compiler I'm using. And it provides a very convenient pattern for representing an arbitrarily large complex tree-shaped data structure inside a “single” instance. A nice property is that all storage management for the entire tree is handled automatically by std::vector. For example you can have a Node member variable in a class Foo and not worry about deleting the tree when you are done with the enclosing Foo instance.
As described elsewhere (How can I declare a member vector of the same class?) it is not a problem for the compiler because the size of std::vector<Node> itself is independent of the size of Node, because std::vector is a fixed size header with a pointer to a separate block of managed storage on the heap.
If you have a generic Node that store ints, float or Objects of a certain type, how could you store generic objects in your node?
typedef struct node{
Dog data;
node* next;
}*nodePtr;
This node stores Dog objects... how could I store generic objects?
One idea I have is to have Dog objects and all other objects inherit from a more general Object class. Good way to go other than using templates?
C++ offers the template<> for generics:
template<typename T>
struct node {
T data;
node<T> *next;
}
Make a template, like this:
template<typename T>
struct Node
{
T data;
Node<T> *next;
};
A good resource to find information on templates can be e.g. the Wikipedia.
One idea I have is to have Dog objects and all other objects inherit from a more general Object class. Good way to go?
If the types all have something in common, create a common base type for them. If not, then don't.
Don't make the types derive from a common base just because you want to store them all in the same container. You'd have it backwards. If you want to store all the types in the same container, they should have something in common already. Otherwise your container is just a sequence of bits. There would be nothing it could do that wouldn't be better done by separate containers for each type. For example, you couldn't iterate through the container and call a method on each element, because there wouldn't be a method that all the elements have!
You said,
Great answer, but I'm looking to do it through OO principles.
One of the basic principles of OO, IMO, is that all your classes should be meaningful. This doesn't mean they have to correspond to concrete objects, or even contain any implementation, but they do have to at least contain some interface. A generic Object class in C++ is not meaningful. Don't create one.
I am reading one of the books and stuck at one particular question.
Definition of a struct for linked list :::
typedef struct LinkedList{
LinkedList* next;
int data;
}
Book says "Placing the next pointer at the beginning of the structure or class makes it easy to write generic list-handling routines no matter what the data holds."
I am not able to understand how placing the next pointer on top will help here.
Also, to make a generic list, wouldn't we need the data type as generic or say void*?
The book you're looking at, Programming Interviews Exposed, is (as far as I can tell) not a book on C++, but rather a book meant to prepare you to answer the kinds of questions that might be asked at a typical technical interview. I wouldn't take anything in the book as a best C++ practice unless it's labelled as such (and perhaps not even then).
The advice to put the next pointer first in a linked list node structure comes from languages like C, where you can't rely on real, compiler-supported inheritance. The idea is, in fact, to implement something like inheritance yourself by piggybacking data onto the linked list node structure. Consider:
typedef struct LinkedList {
LinkedListNode* next;
int type;
}
typedef struct Person {
LinkedList listNode;
char name[64];
int age;
}
typedef struct Address {
LinkedList listNode;
char streetAddress[128];
char city[32];
char state[2];
char zip[10];
}
typedef struct Employee {
Person person;
int department;
int salary;
}
LinkedList here is a base type -- not good for much by itself, but useful as a starting point for nodes with more data. You don't have to know anything about the other types in order to perform linked list operations on a node... you can cast any node pointer to LinkedList* and access the information you need. So, you can have a list of Person and list of Address, and both can be manipulated with the same set of routines. Likewise, you can cast a Employee* to a Person* and use any operations that you've written for Person on Employee as well. If you assign appropriate constants to LinkedList's type field, you can even mix PersonNode and use the type field to determine the type of each node later.
This was a useful way to program 20+ years ago. It still works, of course, but most people would choose to let the compiler manage inheritance for them if they have the option, and all modern object-oriented langauges do offer that option.
Lesson: Understand the technique in case you come across it in old code, but choose a different implementation for your new code if you can.
If you place the next pointer at the beginning, and all you have is a void*, but you know it's a linked list node, you can always find the next pointer. This is in contrast to the next pointer being placed after the 'data', assuming 'data' can be of different sizes, you'd need to know more about the object in order to find the next pointer
I personally do not see any reason, and I agree, the argument should be templated:
template <class T> class ListElement
{
T data;
ListElement* next;
...
}
There may be some issues regarding speed with memory alignment being a bit better the other way round, but I doubt this!
hth
Mario
I came across the following code and despite some help from others, I am still having trouble understanding it.
This code is supposed to implement a General Tree. Single_List and Single_Node classes are also available for use in implementation.
template <class Object>
class General_tree {
private:
Object element; // the stored in the node
Single_list< General_tree<Object> * > children;
// a linked list of pointers to general trees
public:
Object retrieve() {
return element;
}
// ...
};
Can someone tell me what one instance of this class will consist of?
I think it will consist of
[element value in node made by Single_Node] ----->
/ next pointer (part of Single_list class)
/
/ children pointer to another such instance of General_Tree
V
Then these instances can be combined to form a tree... I am still getting used to Object Oriented Design I guess so please let me know if this reasoning and interpretation is correct?
thanks!
The tree object is really a node in the tree, where children points to the nodes at the next level, which will have pointers to their children, etc.
Together they form a subtree (or the whole tree, if it is the root node).