stl::map erase vs std::vector erase behave differently - c++

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!

Related

How is a Vector of Vector aligned in memory?

I understand as Set size of vector of vectors at run time
describes, one can declare vector of vector as
vector<vector<int> > ref;
then resize the first level by
ref.resize(i);
and push element at the 2nd level:
ref[i].push_back(23);
But how are vector of vector aligned in memory?
For simple vector, it's a container and align its element continuously, like an array; but in the case of vector of vector, I couldn't see the picture.
As the size of each inner vector (the vector in vector of vector) size might change, does the outer vector of vector (the vector in vector of vector) align inner vectors continously? Does the outer vector researve memeory space for each inner vector? what if one vector overshoot?
The size of the vector<int> struct that is stored in ref is constant. Common implementations has this as three pointers, or around 12 bytes on 32-bit architectures, or 24 bytes on shiny new 64-bit architectures.
So ref manages roughly ref.capacity() * 12 bytes of continuous storage.
Each element/vector<int> in ref manages its own integers independent of the elements ref manages. In the artistic rendering below ref.size() == ref.capacity() for the sake of simplicity.
So your
ref.resize(i);
only affects the top row. Your
ref[i].push_back(23);
only affects the i-th column.
vector<vector <int>> m;
The inner vector or rows are implemented as independent
objects on the free store.
Elements in each row are compactly stored, capable of performing dynamic allocation through push_back and resizing.
It is not necessary for each inner vector in the vector< vector<int> > to have the same size. So, the inner-vectors (not their elements) are not stored contiguously. That means, the first element of m[i] is not stored in the address immediately next to the last element of m[i-1].
does the outer vector of vector (the vector in vector of vector) align inner vectors continously?
No. See point#2
Does the outer vector researve memeory space for each inner vector?
No. See point#1. you need to resize or do push_back into inner vector.
how are vector of vector aligned in memory?
vector<T> vec;
consumes this much memory
sizeof(vector<T>) + (vec.size() ∗ sizeof(T))
where,
sizeof(vector<T>) = 12 bytes
and T is vector<int> for a vector of vector.
So, the memory consumed for a 3-by-4 vector<vector<int>> would be.
= sizeof(vector<vector<int>>) + (vec.size() * sizeof(vector<int>))
= 12 + 3 * 12
= 48
what if one vector overshoot?
vector.resize function corrupting memory when size is too large
A vector<vector<int>> could look like this in memory:
+-+-+-+
|b|e|c| vector<vector<int>
+-+-+-+
| | |
| | +-------------------+
| | |
| +---------------+ |
| | |
V V V
+-+-+-+-+-+-+-+-+-+
|b|e|c|b|e|c|b|e|c| 3x vector<int>
+-+-+-+-+-+-+-+-+-+
| | | | | | | | |
| | | | | | | | +-------------+
| | | | | | | | |
| | | | | | | +-------+ |
| | | | | | | | |
| | | | | | V V V
| | | | | |+-+-+-+-+-+
| | | | | ||i|i|i|i|i| 5x int
| | | | | |+-+-+-+-+-+
| | | | | |
| | | | +-+---+
| | | | |
| | | V V
| | |+-+-+-+-+
| | ||i|i|i|i| 4x int
| | |+-+-+-+-+
| | |
| +-+-----------+
| |
V V
+-+-+-+-+-+-+-+-+
|i|i|i|i|i|i|i|i| 8x int
+-+-+-+-+-+-+-+-+
Here b denotes the begin() poiner, e denotes the end() pointer and c denotes the capacity() pointer.
You see, that the rows are not contiguous in memory as you would expect from a matrix structure. Every vector (inner and outer vectors) takes care of it's own memory allocations. The outer vector does not care about what it's elements are doing.

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

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 |
+---+ +---+ +---+ +---+

Get confused with this declaration - int (*(*foo)(double))[3]

I am lost in this declaration - int (*(*foo)(double))[3];
My understanding is that this is an array with size 3 which element is a function pointer taking double and returning pointer to int. However, the correct explanation seems to be "pointer to function taking double and returning pointer to array of 3 int". The returning pointer to array of 3 int confuses me a lot as int and [3] far apart.
Why is that? What is the syntax or rule to declare variables like this complex?
You just read from the inside out remembering that postfix array ([]) and function "call" (()) bind tighter than prefix pointer (*):
(*foo) // foo is a pointer...
(*foo)(double) // to a function taking a double...
(*(*foo)(double)) // returning a pointer...
(*(*foo)(double))[3] // to an array of 3...
int (*(*foo)(double))[3]; // ints
(To work out where to start you might want to work from the outside in, but you need to read back from the inside out to read the declaration in the conventional order.)
You can use "clockwise spiral rule"
+----------------------------------+
| +---------------------------+ |
| | +--------------------+ | |
| | | +----+ | | |
| | | |+--+| | | |
| | | |^ || | | |
int ( * ( *foo)( double ) [3 ];
| ^ ^ ^ ^ || | | |
| | | | +---+| | | |
| | | +------+ | | |
| | +------------------------+ | |
| +------------------------------+ |
+-------------------------------------+
Thus, Identifier foo
is a pointer
to function taking double as argument returning
pointer to
array 3
of int

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.

populate n-ary tree using tree.hh STL Like

how can i use tree.hh: an STL-like C++ tree class to populate my tree and obtain the tree below. some help would be appreciate. A and G are root node
thank's
A G
______|____ |
/ | \ |
B C D H
| | | |
| E | |
\_____/ | |
| | |
F | |
|_________|______|
|
I
|
J
In then code above, i'm using depth first search to enumarate item in the list. i have few data formated like this
typedef tree<std::string> TreeNode;
typedef struct
{
int nBases;
char * name;
} BASES;
BASES rgbases[] =
{
{0xB, "J"},
{0xA, "I"},
{0x1, "H"},{0x0, "G"},
{0x5, "F"},{0x2, "E"},{0x1, "C"},{0x0, "A"},
{0x1, "D"},{0x0, "A"},
{0x1, "B"},{0x0, "A"}
};
//here i'm trying to populate my tree
void populateTree(TreeNode &tr, BASES *pBaseArray, int numBase)
{
int n = 0;
while ( n < numBase )
{
BASES *pBase = &pBaseArray[n];
if ( pBase->nBases > 0) // Check for children of the new node
populateTree(tr, pBaseArray + (n + 1),pBase->nBases);
// i suppose i need to insert tree code part here
n += pBase->nBases + 1;
}
}
void BuildTree(TreeNode &tr)
{
populateTree(tr, rgBases, _countof(rgBases));
}
A tree, spanning the original graph presented, could be obtained in removing the edges linking node A with B and D(or possibly the edges linking node A with C and D). The tree class would then be applicable:
A G A G
| | ______| |
| | / |
B C D H B C D H
| | | | | | | |
| E | | | E | |
\______/ | | \______/ | |
| | | | | |
F | | F | |
|_________|______| |__________|______|
| |
I I
| |
J J
Edges in the above tree giving rise to loops, could be recorded separately, that is AB and AD, could be noted in a structure, apart from the tree class. Merging the tree with such a structure would recover the original graph.