You must implement the following c++ containers from the Standard Library (STL) : vector, stack and map
You also gonna rewrite std:: functions such as equal, lexicographical_compare, is_integral, pair, make_pair, enable_if, iterator_traits and reverse_iterator.
- π Containers/Algorithm/Iterators
- β±οΈ Strat for ft_containers
- π² How does the Red Black Tree works?
a) β Insertion
b) β Deletion
c) π Search
d) β Step to follow in order to check if the tree is balanced - π¨ Tools
- βοΈ Potential mistakes !
- βοΈ How to run the project ?
- ποΈ Usefull documentation
1. Containers: These are used to manage collection of objects of a certain kind. Containers can be of two types: Sequence Containers (vector, deque, list) and Associative Containers (Set, Multiset, Map, Multimap).
2. Algorithms: These are used to process the elements of a collection. That is algorithms feed from containers and process those elements in a predefined way and may also push the results into the same/different container.
3. Iterator: These are used to step through the elements of collection of objects (aka containers).
At first, I didn't know where to start on this project. I spent quite some time thinking about an effective strategy, in order to finish the project faster. The following instructions are precious, and gives you an easy-to-understand roadmap.
- Start by coding all the following std functions, asked in the subject (you gonna be able to use them later, inside your containers)
- equal
- lexicographical_compare
- is_integral
- pair
- make_pair
- enable_if
- iterator_traits
- reverse_iterator
- Then, code stack as your first container, and use original vector from STL to test it.
namespace ft {
template <class T, class Container = std::vector<T> >
class stack {
[...]
- When your stack container works properly. start coding vector container and test it with your previously handmade stack container.
namespace ft {
template <class T, class Container = ft::vector<T> > //std::vector become ft::vector
class stack {
[...]
- Final step, code map and drop a β on this repo for the time I saved you ;)
A Red-Black tree is a type of self-balancing binary search tree (BST). It is characterized by the following properties:
- Each node is either red π΄ or black β«οΈ.
- The root is black β«οΈ.
- All leaf nodes (NIL) are black β«οΈ.
- If a node is red, both its children are black β«οΈ.
- Every path from a node to its leaf nodes contains the same number of black nodes β«οΈ.
These properties ensure that the tree remains balanced, and the height of the tree is always O(log n) where n is the number of nodes in the tree.
Operations such as insertion, deletion and search are similar to those in a regular binary search tree, with the added step of re-balancing the tree if the red-black properties are violated.
Insert the new node as in a regular binary search tree.
Color the new node red π΄.
Starting from the new node, check if the red-black properties are violated, and if so, perform rotations and color changes to fix the violation.
Delete the node as in a regular binary search tree.
Starting from the node's parent, check if the red-black properties are violated, and if so, perform rotations and color changes to fix the violation.
Search for the desired node as in a regular binary search tree.
The time complexity for insertion, deletion and search operations on a Red-Black tree is O(log n) on average, making it a good choice for a data structure that needs to efficiently support insertion, deletion, and search operations.
A Red-Black tree is considered balanced if it satisfies the previously shown properties.
To check if a Red-Black tree is balanced, you can perform the following steps:
Start at the root of the tree and traverse through the tree in-order.
- For each node, check that it is either red or black, and that if it is red π΄, both its children are black β«οΈ.
- Check that the root is black β«οΈ.
- Check that all leaf nodes (NIL) are black β«οΈ.
- For each node, compute the black height β«οΈ of the left and right subtrees. The black height of a subtree is the number of black nodes from the root of the subtree to a leaf node. Check that the black height β«οΈ is the same for all leaf nodes in the tree.
If all the above checks pass, the Red-Black tree is considered balanced. (more documentation at the end of the readme)
1. typedef: allows to give a new name to an existing data type.
template <class T, ...>
class stack {
public:
typedef T value_type;
value_type& top() {
return (_container.back());
}
[...]
};
1.bis typename: let the compiler know that Iter is a type and not a static member of std::vector
typedef typename std::vector<T>::iterator Iter
2. explicit: allows only direct-initialization (avoid implicit conversions and copy initialization from braced-init-list).
template <class T, class Container>
class stack {
private:
Container _container;
public:
explicit stack(const Container &ctnr) : _container(ctnr) {}
[...]
};
int main()
{
std::vector<int> vector_std;
for (int i = 0; i <= 10; i++)
vector_std.push_back(i);
std::stack<int, std::vector<int> > stack_std = vector_std;
}
...
>> error: no viable conversion [...] explicit constructor is not a candidat.
3. friend: allows a function to access private and protected members of a class.
template <class T, class Container>
class stack {
private:
Container _container;
public:
friend bool operator==(const stack<T, Container>& lhs, const stack<T, Container>& rhs) {
return (lhs._container == rhs._container);
}
[...]
};
/usr/include/c++/11/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
32 | #error This file requires compiler and library support \
| ^~~~~
To fix this, you should check in your files that you are not including libraries from c++11 that are not supported and which block compilation with the c++98 standard.
In my case, I forgot this include in my is_integral file:
#include <iostream>
// #include <type_traits> <- this include is from c++11
And here you go!
vector.hpp:52:31: error: invalid type argument of unary β*β (have βintβ)
52 | push_back(*it);
| ^~~
inside this specific constructor:
template<class InputIterator>
vector(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()) : _alloc(alloc), _capacity(0), _size(0) {
for (InputIterator it = first; it != last; it++)
push_back(*it);
}
To fix this, you gonna need to use enable_if to check if the user pass as a 4th parameter an iterator, that has the type of an integral integer (is_integral)
typename ft::enable_if<!ft::is_integral<InputIterator>::value>::type* = NULL
And here you done !
- Clone the repository:
git clone https://github.com/ethan0905/ft_containers.git
- Compile the project:
make -j
or you can either choose which containers tests to compile:make
+vector
,stack
ormap
- Run the program:
./vector
./stack
./map
- Enjoy ;)
https://en.cppreference.com/w/cpp/algorithm/equal
https://en.cppreference.com/w/cpp/algorithm/lexicographical_compare
https://en.cppreference.com/w/cpp/types/is_integral
https://learn.microsoft.com/fr-fr/cpp/cpp/char-wchar-t-char16-t-char32-t?view=msvc-170
https://cplusplus.com/reference/utility/pair/pair/
https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a02030.html
https://eli.thegreenplace.net/2014/sfinae-and-enable_if/
https://www.codeproject.com/Articles/36530/An-Introduction-to-Iterator-Traits
https://en.cppreference.com/w/cpp/container/vector
https://www.geeksforgeeks.org/introduction-to-red-black-tree/
https://algorithmtutor.com/Data-Structures/Tree/Red-Black-Trees/