I am currently learning C++, and as an exercise I tried to implement a BST in a C++11. I am not sure at all if what I have done could be considered a good example of c++ programming, thus I would love to know from you if you believe my code could be improved in terms of functionalities, efficiency, or just programming style.
In particular, these are my doubts:
- Is the use I made of
unique_ptr
a good idea in this situation? (It should be because of RAII, from what I got.) - Is the use of nested class a good idea in this situation, or even in general? In this case I think that maybe it could not be a problem because all its members are public but the class itself is encapsulated within the
BinarySearchTree
, so the inner class is not visible from outside theBinarySearchTree
class. - I am not really sure about the checkBST function. Could it be better?
I had a look at others implementations that I was able to find on the web, in order to correct my first (and I must admit too much C-like first attempt).
template<class T> class BinarySearchTree {
private:
// nested class for the node of the tree
class TreeNode {
public:
std::unique_ptr<TreeNode> left;
std::unique_ptr<TreeNode> right;
T value;
TreeNode(T val) {
value = val;
}
};
// private attributes / methods of BST class
std::unique_ptr<TreeNode> root; // root of the BST
int V; // number of nodes
void private_recursive_inorderVisit(TreeNode *node) {
if(node == nullptr)
return;
private_inorderVisit(node->left.get());
std::cout << node->value << std::endl;
private_inorderVisit(node->right.get());
}
void private_iterative_inorderVisit(TreeNode *node) {
TreeNode *currNode = node;
std::stack<TreeNode*> s;
while(s.size() > 0 || currNode != nullptr) {
if(currNode != nullptr) {
s.push(currNode);
currNode = currNode->left.get();
} else {
currNode = s.top();
s.pop();
std::cout << currNode->value << ", ";
currNode = currNode->right.get();
}
}
std::cout << std::endl;
}
public:
BinarySearchTree(const T& RootValue) {
std::unique_ptr<TreeNode> node(new TreeNode(RootValue));
root = std::move(node);
V = 1;
}
void insert(const T& newValue) {
TreeNode* currentNode, *fatherNode;
currentNode = root.get();
fatherNode = nullptr;
std::unique_ptr<TreeNode> newNode(new TreeNode(newValue));
while(currentNode != nullptr) {
fatherNode = currentNode;
if(newValue < currentNode->value) {
// insert left
currentNode = currentNode->left.get();
} else {
// inser right
currentNode = currentNode->right.get();
}
}
if (fatherNode->value > newValue) {
fatherNode->left = std::move(newNode);
} else {
fatherNode->right = std::move(newNode);
}
V++;
}
void inorderVisit() {
//private_recursive_inorderVisit(root.get()); // recursive method
private_iterative_inorderVisit(root.get());
}
bool checkBST() {
TreeNode *currNode = root.get(), *prevNode = root.get();
std::stack<TreeNode*> s;
T minVal;
bool minFound = false;
while(s.size() > 0 || currNode != nullptr) {
if(currNode != nullptr) {
s.push(currNode);
currNode = currNode->left.get();
if(currNode == nullptr && !minFound) { // left extreme node. Supposed to be the minimum
minVal = s.top()->value; // the parent of the null one is the minimum
minFound = true;
}
} else {
// root = predecessor
prevNode = s.top();
s.pop();
currNode = prevNode->right.get();
if(prevNode->value < minVal || currNode != nullptr && currNode->value < minVal)
return false;
}
}
return true;
}
int size() {
return V;
}
};
int main(int argc, const char * argv[]) {
BinarySearchTree<int> BST(50);
BST.insert(15);
BST.insert(20);
BST.insert(70);
BST.insert(3);
BST.inorderVisit();
std::cout << "BST checked. Result is " << ((BST.checkBST() == true) ? "positive" : "negative") << std::endl;
return 0;
}
private_
? Looks really unnecessary to me. Also these methods usecout
. You should consider using anostream
-parameter (that may, or may not be defaulted tocout
) instead. \$\endgroup\$private_
i think you are right. Actually there is no need to use it. Thank you. Andostream
can really be a good idea: I had a look at it and it seems to be a more flexible approach. Anyway, if I can ask you, do you have any further advices on the three small questions I asked? Thanks \$\endgroup\$