Binary Search Tree implementation with unique pointers
$begingroup$
I have implemented a binary search tree using templates and unique_ptr in C++ 11. At present, only insertion and deletion are implemented. Please provide your feedback for improvements.
#include <iostream>
#include <memory>
template<typename T>
class Btree {
public:
void insert(T data)
{
_insert(root, data);
}
void traverse(void (*func)(T data))
{
_traverse(root, func);
}
void del(T data)
{
_del(root, data);
}
private:
struct node {
T data;
std::unique_ptr<node> left, right;
node(T data): data(data), left(nullptr), right(nullptr) {}
};
std::unique_ptr<node> root;
void _insert(std::unique_ptr<node>& curr, T data);
void _del(std::unique_ptr<node>& curr, T data);
void _traverse(std::unique_ptr<node>& curr, void (*func)(T data));
T _findmin(std::unique_ptr<node> &curr);
};
template<typename T>
void Btree<T>::_insert(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr) {
curr.reset(new node(data));
return;
}
if (data < curr->data)
_insert(curr->left, data);
else
_insert(curr->right, data);
}
template<typename T>
T Btree<T>::_findmin(std::unique_ptr<node>& curr)
{
if (curr && curr->left == nullptr)
return curr->data;
return _findmin(curr->left);
}
template<typename T>
void Btree<T>::_del(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr)
return;
if (data < curr->data)
_del(curr->left, data);
else if (data > curr->data)
_del(curr->right, data);
else {
// if one child is nullptr or both child are nullptr
if (curr->left == nullptr) {
auto &p = curr->right;
curr.reset(p.release());
}
else if (curr->right == nullptr) {
auto &p = curr->left;
curr.reset(p.release());
}
//if child is non leaf node
else {
T temp = _findmin(curr->right);
curr->data = temp;
_del(curr->right, temp);
}
}
}
template<typename T>
void Btree<T>::_traverse(std::unique_ptr<node>& curr, void (*func)(T data))
{
if (curr == nullptr)
return;
_traverse(curr->left, func);
func(curr->data);
_traverse(curr->right, func);
}
c++ object-oriented c++11 pointers
$endgroup$
add a comment |
$begingroup$
I have implemented a binary search tree using templates and unique_ptr in C++ 11. At present, only insertion and deletion are implemented. Please provide your feedback for improvements.
#include <iostream>
#include <memory>
template<typename T>
class Btree {
public:
void insert(T data)
{
_insert(root, data);
}
void traverse(void (*func)(T data))
{
_traverse(root, func);
}
void del(T data)
{
_del(root, data);
}
private:
struct node {
T data;
std::unique_ptr<node> left, right;
node(T data): data(data), left(nullptr), right(nullptr) {}
};
std::unique_ptr<node> root;
void _insert(std::unique_ptr<node>& curr, T data);
void _del(std::unique_ptr<node>& curr, T data);
void _traverse(std::unique_ptr<node>& curr, void (*func)(T data));
T _findmin(std::unique_ptr<node> &curr);
};
template<typename T>
void Btree<T>::_insert(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr) {
curr.reset(new node(data));
return;
}
if (data < curr->data)
_insert(curr->left, data);
else
_insert(curr->right, data);
}
template<typename T>
T Btree<T>::_findmin(std::unique_ptr<node>& curr)
{
if (curr && curr->left == nullptr)
return curr->data;
return _findmin(curr->left);
}
template<typename T>
void Btree<T>::_del(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr)
return;
if (data < curr->data)
_del(curr->left, data);
else if (data > curr->data)
_del(curr->right, data);
else {
// if one child is nullptr or both child are nullptr
if (curr->left == nullptr) {
auto &p = curr->right;
curr.reset(p.release());
}
else if (curr->right == nullptr) {
auto &p = curr->left;
curr.reset(p.release());
}
//if child is non leaf node
else {
T temp = _findmin(curr->right);
curr->data = temp;
_del(curr->right, temp);
}
}
}
template<typename T>
void Btree<T>::_traverse(std::unique_ptr<node>& curr, void (*func)(T data))
{
if (curr == nullptr)
return;
_traverse(curr->left, func);
func(curr->data);
_traverse(curr->right, func);
}
c++ object-oriented c++11 pointers
$endgroup$
add a comment |
$begingroup$
I have implemented a binary search tree using templates and unique_ptr in C++ 11. At present, only insertion and deletion are implemented. Please provide your feedback for improvements.
#include <iostream>
#include <memory>
template<typename T>
class Btree {
public:
void insert(T data)
{
_insert(root, data);
}
void traverse(void (*func)(T data))
{
_traverse(root, func);
}
void del(T data)
{
_del(root, data);
}
private:
struct node {
T data;
std::unique_ptr<node> left, right;
node(T data): data(data), left(nullptr), right(nullptr) {}
};
std::unique_ptr<node> root;
void _insert(std::unique_ptr<node>& curr, T data);
void _del(std::unique_ptr<node>& curr, T data);
void _traverse(std::unique_ptr<node>& curr, void (*func)(T data));
T _findmin(std::unique_ptr<node> &curr);
};
template<typename T>
void Btree<T>::_insert(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr) {
curr.reset(new node(data));
return;
}
if (data < curr->data)
_insert(curr->left, data);
else
_insert(curr->right, data);
}
template<typename T>
T Btree<T>::_findmin(std::unique_ptr<node>& curr)
{
if (curr && curr->left == nullptr)
return curr->data;
return _findmin(curr->left);
}
template<typename T>
void Btree<T>::_del(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr)
return;
if (data < curr->data)
_del(curr->left, data);
else if (data > curr->data)
_del(curr->right, data);
else {
// if one child is nullptr or both child are nullptr
if (curr->left == nullptr) {
auto &p = curr->right;
curr.reset(p.release());
}
else if (curr->right == nullptr) {
auto &p = curr->left;
curr.reset(p.release());
}
//if child is non leaf node
else {
T temp = _findmin(curr->right);
curr->data = temp;
_del(curr->right, temp);
}
}
}
template<typename T>
void Btree<T>::_traverse(std::unique_ptr<node>& curr, void (*func)(T data))
{
if (curr == nullptr)
return;
_traverse(curr->left, func);
func(curr->data);
_traverse(curr->right, func);
}
c++ object-oriented c++11 pointers
$endgroup$
I have implemented a binary search tree using templates and unique_ptr in C++ 11. At present, only insertion and deletion are implemented. Please provide your feedback for improvements.
#include <iostream>
#include <memory>
template<typename T>
class Btree {
public:
void insert(T data)
{
_insert(root, data);
}
void traverse(void (*func)(T data))
{
_traverse(root, func);
}
void del(T data)
{
_del(root, data);
}
private:
struct node {
T data;
std::unique_ptr<node> left, right;
node(T data): data(data), left(nullptr), right(nullptr) {}
};
std::unique_ptr<node> root;
void _insert(std::unique_ptr<node>& curr, T data);
void _del(std::unique_ptr<node>& curr, T data);
void _traverse(std::unique_ptr<node>& curr, void (*func)(T data));
T _findmin(std::unique_ptr<node> &curr);
};
template<typename T>
void Btree<T>::_insert(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr) {
curr.reset(new node(data));
return;
}
if (data < curr->data)
_insert(curr->left, data);
else
_insert(curr->right, data);
}
template<typename T>
T Btree<T>::_findmin(std::unique_ptr<node>& curr)
{
if (curr && curr->left == nullptr)
return curr->data;
return _findmin(curr->left);
}
template<typename T>
void Btree<T>::_del(std::unique_ptr<node>& curr, T data)
{
if (curr == nullptr)
return;
if (data < curr->data)
_del(curr->left, data);
else if (data > curr->data)
_del(curr->right, data);
else {
// if one child is nullptr or both child are nullptr
if (curr->left == nullptr) {
auto &p = curr->right;
curr.reset(p.release());
}
else if (curr->right == nullptr) {
auto &p = curr->left;
curr.reset(p.release());
}
//if child is non leaf node
else {
T temp = _findmin(curr->right);
curr->data = temp;
_del(curr->right, temp);
}
}
}
template<typename T>
void Btree<T>::_traverse(std::unique_ptr<node>& curr, void (*func)(T data))
{
if (curr == nullptr)
return;
_traverse(curr->left, func);
func(curr->data);
_traverse(curr->right, func);
}
c++ object-oriented c++11 pointers
c++ object-oriented c++11 pointers
edited 2 hours ago
1201ProgramAlarm
3,2932923
3,2932923
asked 2 hours ago
bornfreebornfree
1623
1623
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
Since insert
gets its data by value, you're making multiple copies of that data as you navigate down the tree to find where to add the new node. Passing the parameter by const T&
(so you only make one copy) would avoid these copies, a benefit for types that are expensive to copy. Another possibility is to use T &&
to move the data, but this will change the original value being passed in which may be undesirable.
The value passed to the function called by _traverse
is also copied. Depending on your needs, this could also use a const T &
, or overloads of _traverse
that take func
with a reference could be provided. The downside to providing access to the data via a reference is that it can allow that data to be altered.
If _insert
takes curr
as a pointer (std::unique_ptr<node>* curr
) then you can use a loop rather than recursion. This also applies to _findmin
and _del
.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214882%2fbinary-search-tree-implementation-with-unique-pointers%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Since insert
gets its data by value, you're making multiple copies of that data as you navigate down the tree to find where to add the new node. Passing the parameter by const T&
(so you only make one copy) would avoid these copies, a benefit for types that are expensive to copy. Another possibility is to use T &&
to move the data, but this will change the original value being passed in which may be undesirable.
The value passed to the function called by _traverse
is also copied. Depending on your needs, this could also use a const T &
, or overloads of _traverse
that take func
with a reference could be provided. The downside to providing access to the data via a reference is that it can allow that data to be altered.
If _insert
takes curr
as a pointer (std::unique_ptr<node>* curr
) then you can use a loop rather than recursion. This also applies to _findmin
and _del
.
$endgroup$
add a comment |
$begingroup$
Since insert
gets its data by value, you're making multiple copies of that data as you navigate down the tree to find where to add the new node. Passing the parameter by const T&
(so you only make one copy) would avoid these copies, a benefit for types that are expensive to copy. Another possibility is to use T &&
to move the data, but this will change the original value being passed in which may be undesirable.
The value passed to the function called by _traverse
is also copied. Depending on your needs, this could also use a const T &
, or overloads of _traverse
that take func
with a reference could be provided. The downside to providing access to the data via a reference is that it can allow that data to be altered.
If _insert
takes curr
as a pointer (std::unique_ptr<node>* curr
) then you can use a loop rather than recursion. This also applies to _findmin
and _del
.
$endgroup$
add a comment |
$begingroup$
Since insert
gets its data by value, you're making multiple copies of that data as you navigate down the tree to find where to add the new node. Passing the parameter by const T&
(so you only make one copy) would avoid these copies, a benefit for types that are expensive to copy. Another possibility is to use T &&
to move the data, but this will change the original value being passed in which may be undesirable.
The value passed to the function called by _traverse
is also copied. Depending on your needs, this could also use a const T &
, or overloads of _traverse
that take func
with a reference could be provided. The downside to providing access to the data via a reference is that it can allow that data to be altered.
If _insert
takes curr
as a pointer (std::unique_ptr<node>* curr
) then you can use a loop rather than recursion. This also applies to _findmin
and _del
.
$endgroup$
Since insert
gets its data by value, you're making multiple copies of that data as you navigate down the tree to find where to add the new node. Passing the parameter by const T&
(so you only make one copy) would avoid these copies, a benefit for types that are expensive to copy. Another possibility is to use T &&
to move the data, but this will change the original value being passed in which may be undesirable.
The value passed to the function called by _traverse
is also copied. Depending on your needs, this could also use a const T &
, or overloads of _traverse
that take func
with a reference could be provided. The downside to providing access to the data via a reference is that it can allow that data to be altered.
If _insert
takes curr
as a pointer (std::unique_ptr<node>* curr
) then you can use a loop rather than recursion. This also applies to _findmin
and _del
.
answered 1 hour ago
1201ProgramAlarm1201ProgramAlarm
3,2932923
3,2932923
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214882%2fbinary-search-tree-implementation-with-unique-pointers%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown