Is this how I should be understanding what a multiway tree is? - c++

I am currently about to implement a multi-way tree in c++, but I am still not sure about what exactly they are. I have read a few documentations, but I am still confused because of the lack of pictures or visualization provided.
Lets say I want a 3 way tree, according to online web notes it means each node can have at most 3-1 = 2 elements and each node can have at most 3 children. Below I have drawn some trees that I am not sure if they are 3-way trees, can someone please verify I am understanding this correctly? Thank you!
Also, if I have a 2 way tree, does that mean I have a binary tree as well? O.o?

My understanding of a multi-way tree is the number of subtrees that can be traversed from a single node.
+---+
| D |
+---+
^
|
|
+---+ +------+ +---+
| A | <-- | Root | --> | B |
+---+ +------+ +---+
|
|
V
+---+
| C |
+---+
The diagram above shows a multi-way tree because the root has more than 1 child.
Usually 2 children per node (except leaf nodes) indicates binary trees.
There are many different kinds of binary trees.
See also B-Tree and B*Trees.
Edit 1:
Another view:
+------------------------+
| Root +
+------------------------+
| | | |
V V V V
+---+ +---+ +---+ +---+
| A | | B | | C | | D |
+---+ +---+ +---+ +---+

Related

Why isn't "new" used while making the current variable in the linkedlist?

This is the solution to printing elements of a linked list.
Why isn't it Node *current = new Node; and then current = head;?
void printLinkedList(Node* head)
{
Node *current = head;
while(current!=NULL){
cout << current -> data << endl;
current = current -> next;
}
}
This is a great spot to draw pictures!
Imagine we have a linked list pointed at by head:
head
|
v
+------+ +-----+ +-----+ +-----+
| i'm | -> | the | -> | bad | -> | guy | -> null
+------+ +-----+ +-----+ +-----+
If we use the line of code
Node *current = new Node;
then memory looks like this:
head current
| |
v v
+------+ +-----+ +-----+ +-----+ +------+
| i'm | -> | the | -> | bad | -> | guy | -> null | duh! | -> ?
+------+ +-----+ +-----+ +-----+ +------+
The goal of the function is to print the existing list pointed at by head, but here we've got a pointer to a new linked list cell that isn't a part of the existing list. As a result, we've committed two Programming Sins:
We've allocated memory for an object we don't need.
We've broken the contract we made with the client.
On the other hand, if we write
Node *current = head;
then memory looks like this:
head
|
v
+------+ +-----+ +-----+ +-----+
| i'm | -> | the | -> | bad | -> | guy | -> null
+------+ +-----+ +-----+ +-----+
^
|
current
Here, current is now pointing into the existing list, so we can walk the list to find what we need. No new nodes need to be created here, so we don't create any new nodes.
Generally speaking, in C++ you should avoid using new unless you really truly want to create a new linked list cell. In this case, we don't want to do that, which is why we create current and have it point to an existing linked list cell.
Hope this helps!
Because the node already exists.
new would create a new one.
You don't need or want to create a new one.
You just want to "use" a pointer to an existing node.
Here's it's just the function argument being copied into a variable with a different name. It's actually completely unnecessary.

Conceptual meaning of nodes assignment in linked list

I am just wondering, in a linked list what is the difference between the two:
node1 = node2
and
node1->next = node2
The first line makes me a bit confused.
I'm assuming from context here that node1 and node2 are pointers to nodes (for example, they might have a type like Node *). If that's not the case, please let me know!
If node1 and node2 are pointers, remember that there is a difference between pointers to nodes and actual, honest-to-goodness node objects. The pointers are just a way of saying "look over there and you'll find a node." The nodes themselves are actual objects containing data and links to other nodes.
For example, if you have two node pointers node1 and node2 that point to nodes, perhaps it looks like this:
+----------+ +----------+
| | -----------> | data! |
+----------+ +----------+
node1 | next! | -----> ...
+----------+
+----------+ +----------+
| | -----------> | data! |
+----------+ +----------+
node2 | next! | -----> ...
+----------+
If you write node1->next = node2, you're saying "follow the pointer named node1 to see what node it points at, find the next pointer in that node, and change it to point to wherever node2 points." That makes things look like this:
+----------+ +----------+
| | -----------> | data! |
+----------+ +----------+
node1 | next! | -----> ...
+----------+
|
|
v
+----------+ +----------+
| | -----------> | data! |
+----------+ +----------+
node2 | next! | -----> ...
+----------+
Writing node1 = node2 means "change node1 to point to whatever node node2 is pointing at." That looks like this:
+----------+ +----------+
| | ------+ | data! |
+----------+ | +----------+
node1 | | next! | -----> ...
| +----------+
| |
| |
| v
+----------+ | +----------+
| | ------+----> | data! |
+----------+ +----------+
node2 | next! | -----> ...
+----------+
Fundamentally, there's no deep difference between these operations. They both change where some pointer is pointing. The difference is whether you're changing the next pointer inside of a node object or whether you're changing which node node1 points at.
Whenever you have a question about what a line of code does that involves pointers or linked lists or the like, I highly recommend drawing pictures like the ones shown here. Building a visual intuition for what links you're creating and what links you're breaking is one of the best ways to better understand how code works. Plus, it's great for debugging!

Indefinite quantity of a class member variable(C++)

The C++ program I'm working on is designed to create a custom doubly Linked List class in C++ by utilizing an indefinite number of node struct pointers with a data value and two pointers inside. That's the premise of this program. Can't use the STL LinkedList class, have to make my own.
This being said, how do you create a class member variable that doesn't have a specific amount of pointers to nodes? I don't want to initialize fifty nodes when declaring the class, but then only use ten of them. and at the same time, I don't want to initialize only 5 and then have to use more than that 5. Is there a way to dynamically add node pointers to a linked list class in C++, when node pointers are considered a member variable?
Am I even going about this the right way? And if so, how will I go about doing this?
Picture this:
+----------+-------+------+
| Previous | Data | Next |
| Node | Field | Node |
+----------+-------+------+
A node with two link fields and a data field.
(Linked lists are always easier to understand when you draw them.)
We could have two of them:
+----------+-------+------+
| Previous | Data | Next |
| Node | Field | Node |
+----------+-------+------+
^ |
| V
+----------+-------+------+
| Previous | Data | Next |
| Node | Field | Node |
+----------+-------+------+
The Previous Node field of the 2nd node points to the first. The first node has no predecessors, so it's Previous Node field is empty.
Similarly, the Next Node field of the first node points to the 2nd node. The 2nd node has no successor, so the Next Node field of the 2nd node is empty.
This is what I believe the requirements want: a doubly linked list using pointers.
Edit 1: Three nodes
+----------+-------+------+
| Previous | Data | Next |
| Node | Field | Node |
+----------+-------+------+
^ |
| V
+----------+-------+------+
| Previous | Data | Next |
| Node | Field | Node |
+----------+-------+------+
^ |
| V
+----------+-------+------+
| Previous | Data | Next |
| Node | Field | Node |
+----------+-------+------+
As you can see, to visit (traverse) the nodes in a forward manner, you follow the link field of one node to get to the next node. Similarly, to go in a backwards manner, you follow the Previous Node link to get to a node's predecessor.
A nice issue about the links is that you only need to change the link fields in order to insert a node in the middle of the list. Drawing of the insertion processes is left as an exercise for the reader.
Edit 2: The Container Class
The Linked List is a container of nodes. For simple implementations, the Container class should not be a Node.
The Container has-a pointer to the first node and optionally a pointer to the last node:
+------+-------+
| Last | First |
| Node | Node |
+------+-------+
| |
| +---------------+
| |
| V
| +----------+-------+------+
| | Previous | Data | Next |
| | Node | Field | Node |
| +----------+-------+------+
| ^ |
| | V
| +----------+-------+------+
| | Previous | Data | Next |
| | Node | Field | Node |
| +----------+-------+------+
| ^ |
| | V
| +----------+-------+------+
| | Previous | Data | Next |
+->| Node | Field | Node |
+----------+-------+------+
By using a container class, you don't need to worry about an using an empty node as the first node. Here, we use a simple pointer to point to the first node. Additionally, there is a pointer to the last node.
The pointer to the last node speeds up the operation of appending nodes to the list. Without this pointer, you would have to traverse all the nodes to find the last one, which takes a lot of time.

Union of rectangles in a 2d tiled world

I am trying to find the bounding polygon of a set of adjacent cells(row,col) ( convertable to rectangles) in a 2d tiled world.
Processing the cells in a for loop and using the neighbourhood property of the adjacent cells I could eliminate all internal edges and store the rest of the edges.
The edges are stored in std::vector;
Now I need to merge the edges where there is a common vertex and slope is the same.
After merging the edges I need to make the bounding polygon, starting from a vertex going counter clockwise.
Please help to find a method to make it possible.
I think this is a simple algorithm to achieve that.
Consider we have this as input:
| | | | | |
-+---+---+---+---+---+-
| | | | | |
-+---+---+---+---+---+-
| | | a | | |
-+---+---+---+---+---+-
| | b | c | d | |
-+---+---+---+---+---+-
| | | e | | |
-+---+---+---+---+---+-
| | | | | |
Where a, b, c, d, and e are our input tiles stored as a vector of pairs (Coordinates):
std::vector<std::pair<unsigned,unsigned>> tiles;
What we want is this:
| | | | | |
-+---+---+---+---+---+-
| | | | | |
-+---+---*---*---+---+-
| | | | | |
-+---*---* *---*---+-
| | | |
-+---*---* *---*---+-
| | | | | |
-+---+---*---*---+---+-
| | | | | |
The algorithm works as follows:
Build an array of booleans enclosing the entire set of tiles. You have to trasverse the set to find the bounds of that rectangle. Set as true the positions of the array which represent a tile of the set, and as false otherwise.
The output in the example will be (T is true and f is false):
+---+---+---+
| f | T | f |
+---+---+---+
| T | T | T |
+---+---+---+
| f | T | f ]
+---+---+---+
Now you have to traverse the border of the hull polygon. Start at the first element marked as true in the flag array and trasverse the vertices in the same direction until you reach the first vertex again, using this rules:
If the two tiles in front of the current direction/position are false, turn clockwise and add the vertex to the output list (polygon):
(* are vertices added to the polygon, X the current vertex, the arrow the current direction)
+---+---+---+
| f | f | f |
*---+---X---+ --->
| T | T | f |
*---+---+---+
| f | T | f ]
+---+---+---+
goes to
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---X---+
| f | T | f ]
+---+---+---+
If one tile is false and one true, go in the same direction (Note that true-false or false-true means you are in a border):
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---X---+
| f | T | f ]
+---+---+---+
goes to
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---+---+
| f | T | f ]
+---+---X---+
If both tiles are true, turn counter-clockwise and add the vertex to the output list (Note that true-true means you have reached part of the set of tiles, a "wall"):
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---X---+
| f | T | T ]
+---+---+---+
goes to
+---+---+---+
| f | f | f |
+---+---*---+
| T | T | f | --->
+---+---*---X
| f | T | T ]
+---+---+---+
Considerations:
tilemap coordinates vs flag-array coordinates
The flag-array represents the rectangle region of the tilemap where the tiles are placed. So the tilemap-coordinates of its first element (tile) is (left,top) where left is the minimum x-coordinate of the selected set of tiles, and top is the minimum y-coordinate of the selected set of tiles.
In the second step of the agorithm, you trasverse the frontier (border) of the set of tiles, using the array as a guide. Note that what you really trasverse is that array, so you have to translate the coordinates from flag-coordinates (logical coordinates) to tilemap-coordinates (physical coordinates) to store the vertices of the polygon. Of course thats easy.
Also note that the algorithm abstract steps trasverse vertices of edges (physical tile coordinates), not logical-coordinates. You have to be sure what "I'm in that vertex" means and what "advance" and "turn" mean in terms of flag-array coordinates.
Border conditions and the front-tiles check
We have defined three rules to advance along the border of the set of tiles. We have used the flag-array as a guide to decide what to do (Advance, turn clockwise, or turn counter-clockwise). Note that when the current vertex is in the border of the array, you could (you should) consider that it have neighbour tiles with a false value.
For example:
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---+---+
| f | T | f ]
+---+---X---+
goes to
+---+---+---+
| f | f | f |
*---+---*---+ <--
| T | T | f |
*---+---+---+
| f | T | f ]
+---X---*---+
exactly as if it was this:
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---+---+
| f | T | f ]
+---+---X---+
| f | f | f |
*---*---*---+
Possible optimisations
The first step computes the flag array because the algorithm takes the set of tiles selected as a vector. If your tile engine supports it, you could add a property to the tiles (bool selected) and pass the tilemap directly, avoiding the computation and the vertex cooordinates transformations.
Example
Given this flag-array:
+---+---+---+
| T | f | f |
+---+---+---+
| T | T | T |
+---+---+---+
| f | T | T |
+---+---+---+
The execution works as follows (Note that the drawings are the state AFTER the execution of the step):
Find the first true tile. In this case (0,0). So we start at one of its vertex (bottom-left vertex, looking upwards, for example. Note that because its the first true tile, you could use that vertex being sure that it belongs to the polygon. So add that first vertex to the polygon):
Current position: (0,1)
Polygon: {(0,1)}
+---+---+---+ ^
| T | f | f | |
X---+---+---+ |
| T | T | T |
+---+---+---+
| f | T | T |
+---+---+---+
Start the trasverse. In this case, the front tiles are false-true, so advance:
Current position: (0,0)
Polygon: {(0,1)}
X---+---+---+ ^
| T | f | f | |
*---+---+---+ |
| T | T | T |
+---+---+---+
| f | T | T |
+---+---+---+
The front tiles are false-false (We are in a border), so turn clockwise and add the vertex:
Current position: (1,0)
Polygon: {(0,1),(0,0)}
*---X---+---+
| T | f | f |
*---+---+---+
| T | T | T | --->
+---+---+---+
| f | T | T |
+---+---+---+
Now the fron-tiles are false-false (One is out of the array, and the other is false). turn clockwise and add the vertex:
Current position: (1,1)
Polygon: {(0,1),(0,0),(1,0)}
*---*---+---+
| T | f | f | |
*---X---+---+ |
| T | T | T | v
+---+---+---+
| f | T | T |
+---+---+---+
The two front-tiles are true: Turn counter-clockwise and add the vertex:
Current position: (1,2)
Polygon: {(0,1),(0,0),(1,0),(1,1)}
*---*---+---+
| T | f | f |
*---*---X---+
| T | T | T | --->
+---+---+---+
| f | T | T |
+---+---+---+
One tile is false and the other is true: Advance:
Current position: (1,3)
Polygon: {(0,1),(0,0),(1,0),(1,1)}
*---*---+---+
| T | f | f |
*---*---+---X
| T | T | T | --->
+---+---+---+
| f | T | T |
+---+---+---+
Two false tiles (Both out of array): Turn clockwise and add the vertex:
Current position: (2,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1)}
*---*---+---+
| T | f | f | |
*---*---+---* |
| T | T | T | v
+---+---+---X
| f | T | T |
+---+---+---+
One true and one false(Out of array): Advance:
Current position: (3,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1)}
*---*---+---+
| T | f | f | |
*---*---+---* |
| T | T | T | v
+---+---+---+
| f | T | T |
+---+---+---X
Two false(Out of array) front-tiles: Turn clockwise and add the vertex:
Current position: (2,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3)}
*---*---+---+
| T | f | f |
*---*---+---*
| T | T | T | <---
+---+---+---+
| f | T | T |
+---+---X---*
true-false (One true and one out of bounds): Advance:
Current position: (1,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3)}
*---*---+---+
| T | f | f |
*---*---+---*
| T | T | T | <---
+---+---+---+
| f | T | T |
+---X---+---*
false-false (One false and one out of bounds): Turn clockwise and add the vertex:
Current position: (1,2)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3)}
*---*---+---+
| T | f | f | ^
*---*---+---* |
| T | T | T | |
+---X---+---+
| f | T | T |
+---*---+---*
true-true front-tiles: Turn counter-clockwise and add the vertex:
Current position: (0,2)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3),(1,2)}
*---*---+---+
| T | f | f |
*---*---+---*
| T | T | T | <---
X---*---+---+
| f | T | T |
+---*---+---*
false-false front-tiles: Turn clockwise and add the vertex:
Current position: (0,1)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3),(1,2),(0,2)}
*---*---+---+
| T | f | f | ^
X---*---+---* |
| T | T | T | |
*---*---+---+
| f | T | T |
+---*---+---*
The current vertex is the first vertex of the polygon: The execution have finished. The result is as follows:
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3),(1,2),(0,2)}
*---*
| |
* *-------*
| |
*---* |
| |
*-------*
Because of tiles, this is a 'special case' of finding boundary polygon. I would go with some simple approach.
Tile (x,y) consist of vertices [(x,y), (x+1,y), (x+1,y+1), (x,y+1)]. Vertex is a part of boundary polygon if it is in 1, 2 or 3 tiles. To find vertices on boundary it is enough to count number of tiles it is in. For that it is enough to pass through tiles and increment vertex appearance count for tile 4 vertices. Vertices with tile count 1, 2 or 3 are on the boundary polygon.
To order vertices it is enough to start from some vertex on a boundary and look for a neighbouring vertex that is also on a boundary. To traverse vertices in same direction it is important to take a care of direction order of neighbouring vertices to check. E.g. if last vertex is on -x, than order of directions to check is +y, +x, -y.
Since direction of last edge is known, if next edge is in the same direction than that vertex is for a removal. If region is simple connected, than removal can be known also from tile count. If tile count of a vertex is 2 than vertex is for removal.
For now we don't have guarantee that order is clockwise. That can be check by checking (some of) upper-most edge(s) is it in clockwise direction. If it is not, than reverse polygon.

stl::map erase vs std::vector erase behave differently

class CSensor
{
public:
CSensor(int nVal1,char* pVal2,unsigned int nVal3);
CSensor(const CSensor& refMessage);
const CSensor& operator=(const CSensor& refMessage);
~CSensor(void);
private:
int m_nVal1;
char* m_pVal2;
unsigned int m_nVal3;
};
// vector erase
std::vector<CSensor> SensorList;
CSensor obj1(1,"Test1",10);
SensorList.push_back(obj1);
CSensor obj2(2,"Test2",11);
SensorList.push_back(obj2);
CSensor obj3(3,"Test3",12);
SensorList.push_back(obj3);
SensorList.erase (SensorList.begin()+1);
// map erase
std::map<int ,CSensor> ListSensor;
CSensor obj11(1,"Test1",10);
CSensor obj12(2,"Test2",11);
CSensor obj13(3,"Test3",12);
ListSensor.insert(std::pair<int,CSensor>(1,obj11));
ListSensor.insert(std::pair<int,CSensor>(2,obj12));
ListSensor.insert(std::pair<int,CSensor>(3,obj13));
ListSensor.erase(2);
I debugged both the case.
In both the cases i am deleting the second element.In case of vector
it is copying 3 element to 2nd poition and than it it deleting the 3 rd location.
So when u say
List.erase (List.begin()+1);
it is calling assignment operator(CSensor=) and then calling destructor.
In case of map when i do
ListSensor.erase(2);
it only calls the destructor.
I have gone through STL vector vs map erase.
It talks Iterator,couldn't explain the behavior.
My question is why erase behaves differently for these two STL container??
This is not a behaviour of .erase per se, but a consequence of how each respective container works.
Deleting from a vector
When you delete from a vector (List is a really poor name for a vector, btw), its contents must be shuffled along to fill the gap because the elements of a vector are always stored contiguously in memory.
This is generally done by copying (or moving) elements then chopping off the remainder:
Vector elements in memory:
+---+---+---+---+---+---+---+---+---+
| a | b | c | d | e | f | g | h | i |
+---+---+---+---+---+---+---+---+---+
Erase 'e':
+---+---+---+---+---+---+---+---+---+
| a | b | c | d | | f | g | h | i |
+---+---+---+---+---+---+---+---+---+
Fill the gap by copying/moving across:
<--
+---+---+---+---+---+---+---+---+---+
| a | b | c | d | f | f | g | h | i |
+---+---+---+---+---+---+---+---+---+
<--
+---+---+---+---+---+---+---+---+---+
| a | b | c | d | f | g | g | h | i |
+---+---+---+---+---+---+---+---+---+
<--
+---+---+---+---+---+---+---+---+---+
| a | b | c | d | f | g | h | h | i |
+---+---+---+---+---+---+---+---+---+
<--
+---+---+---+---+---+---+---+---+---+
| a | b | c | d | f | g | h | i | i |
+---+---+---+---+---+---+---+---+---+
Resize the container:
+---+---+---+---+---+---+---+---+
| a | b | c | d | f | g | h | i |
+---+---+---+---+---+---+---+---+
Deleting from a map
This is not the case for a map, whose contents are not necessarily stored contiguously in memory (in fact, the complexity requirements mean it's almost always a tree structure filled with pointers to discontiguous data).
This is one reason to have different containers!
The vector has to copy the elements following the eased element to cover the "hole" that it left. Otherwise the elements wouldn't be contiguous anymore.
The map holds its elements in a tree structure and just has to adjust some pointers to rebalance the tree.
To the vector's defense: Copying a couple of elements might be cheaper than allocating tree nodes separately and keeping the tree balanced. There are always tradeoffs!