I have tried to make my own implementation for a BST task I was given for a complex type (Transaction), that should be able to store duplicate values as well.
However, I am not sure if I have gone about it the right, way and if there is anything I could do to make my code cleaner / more to c++ best practices?
I was told multiset/multimap is something I could use and decided to go with multimap and everything seems to be working ok unless anyone can spot things I could have done better.
(Still very new to c++ and coding in general, just looking for some better coding practices).
#include<iostream>
using namespace std;
#include <algorithm>
#include <cctype>
#include <string>
#include <memory>
#include <map>
// Complex type used for the BST
class Transaction
{
private:
std::string desc;
time_t timestamp;
std::string value;
bool isWithdrawal;
public:
Transaction(const std::string& value, std::string reason = "None.")
: desc(reason), timestamp(time(nullptr)), value(value) { // timestamp is current date/time based on current system
// Lambda to convert reason to lower to we can identify elements easier
std::transform(reason.begin(), reason.end(), reason.begin(),
[](unsigned char c) { return std::tolower(c); });
this->isWithdrawal = (reason.find("withdrawal") != std::string::npos) ? true : false;
}
std::string toString() const {
// convert timestamp to string form
const char* string_timestamp = ctime(×tamp);
if(this->isWithdrawal) { return "-- " + desc + ": -£" + value + " on " + string_timestamp;}
else {return "-- " + desc + ": £" + value + " on " + string_timestamp;}
}
// Gets the amount, converts it to a double and returns it
double getAmount() const {
return std::stod(this->value);
}
};
// The binary search tree implementation
class BST {
struct node {
multimap<const double, std::shared_ptr<Transaction>> data;
node* left;
node* right;
};
node* root;
node* makeEmpty(node* t) {
if(t == NULL)
return NULL;
{
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
return NULL;
}
node* insert(std::shared_ptr<Transaction> x, node* t)
{
if(t == NULL)
{
t = new node;
t->data.insert(pair<const double, std::shared_ptr<Transaction>>(x->getAmount(), x));
t->left = t->right = NULL;
}
else if(x->getAmount() == getFirstData(t->data)){
t->data.insert(pair<const double, std::shared_ptr<Transaction>>(x->getAmount(), x));
}
else if(x->getAmount() < getFirstData(t->data)){
t->left = insert(x, t->left);
}
else if(x->getAmount() > getFirstData(t->data)){
t->right = insert(x, t->right);
}
return t;
}
node* findMin(node* t)
{
if(t == NULL)
return NULL;
else if(t->left == NULL)
return t;
else
return findMin(t->left);
}
node* findMax(node* t) {
if(t == NULL)
return NULL;
else if(t->right == NULL)
return t;
else
return findMax(t->right);
}
void inorder(node* t) {
if(t == NULL)
return;
inorder(t->left);
cout << getFirstData(t->data) << " ";
inorder(t->right);
}
node* find(node* t, double x) {
if(t == NULL)
return NULL;
else if(x < getFirstData(t->data))
return find(t->left, x);
else if(x > getFirstData(t->data))
return find(t->right, x);
else
return t;
}
public:
BST() {
root = NULL;
}
~BST() {
root = makeEmpty(root);
}
void insert(std::shared_ptr<Transaction> x) {
root = insert(x, root);
}
void display() {
inorder(root);
cout << endl;
}
std::string search(double x) {
node* result = find(root, x);
if(result != NULL) { return loopNode(result->data); }
else { return "N/A"; }
}
// Gets the first pair key from a multimap
double getFirstData(const multimap<const double, std::shared_ptr<Transaction>>& m){
// Declare an iterator to first element
auto itr = m.begin();
return itr->first;
}
// Loop through a node and return its values
std::string loopNode(const multimap<const double, std::shared_ptr<Transaction>>& m){
std::string result;
for (auto it = m.begin(); it != m.end(); ++it){
result += (*it).second->toString();
}
return result;
}
};
int main() {
BST t;
t.insert(std::make_shared<Transaction>("1400", "Withdrawal"));
t.insert(std::make_shared<Transaction>("1400.59", "Deposit"));
t.insert(std::make_shared<Transaction>("1400.59", "Deposit - test"));
t.display();
std::cout << t.search(1400.59);
return 0;
}
IMPROVED VERSION
#include<iostream>
using namespace std;
#include <algorithm>
#include <cctype>
#include <string>
#include <memory>
#include <set>
// Complex type used for the BST
class Transaction
{
private:
std::string desc;
time_t timestamp;
std::string value;
bool isWithdrawal;
public:
Transaction(const std::string& value, std::string reason = "None.")
: desc(reason), timestamp(time(nullptr)), value(value) { // timestamp is current date/time based on current system
// Lambda to convert reason to lower to we can identify elements easier
std::transform(reason.begin(), reason.end(), reason.begin(),
[](unsigned char c) { return std::tolower(c); });
this->isWithdrawal = (reason.find("withdrawal") != std::string::npos) ? true : false;
}
std::string toString() const {
// convert timestamp to string form
const char* string_timestamp = ctime(×tamp);
if(this->isWithdrawal) { return "-- " + desc + ": -£" + value + " on " + string_timestamp;}
else {return "-- " + desc + ": £" + value + " on " + string_timestamp;}
}
// Gets the amount, converts it to a double and returns it
double getAmount() const {
return std::stod(this->value);
}
// Overloading comparision operators by value (transaction amount)
bool operator < (const Transaction& rhs){
return this->value < rhs.value;
}
bool operator > (const Transaction& rhs){
return this->value > rhs.value;
}
bool operator == (const Transaction& rhs){
return this->value == rhs.value;
}
bool operator != (const Transaction& rhs){
return this->value != rhs.value;
}
};
// The binary search tree implementation
class BST {
struct node {
std::multiset<std::shared_ptr<Transaction>> data;
node* left;
node* right;
};
node* root;
node* makeEmpty(node* t) const {
if(t == NULL)
return NULL;
{
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
return NULL;
}
node* insert(std::shared_ptr<Transaction> x, node* t) {
if(t == NULL)
{
t = new node;
t->data.insert(x);
t->left = t->right = NULL;
}
else if(*x == getFirstData(t->data)){
t->data.insert(x);
}
else if(*x < getFirstData(t->data)){
t->left = insert(x, t->left);
}
else if(*x > getFirstData(t->data)){
t->right = insert(x, t->right);
}
return t;
}
node* findMin(node* t) const {
if(t == NULL)
return NULL;
else if(t->left == NULL)
return t;
else
return findMin(t->left);
}
node* findMax(node* t) const {
if(t == NULL)
return NULL;
else if(t->right == NULL)
return t;
else
return findMax(t->right);
}
node* find(node* t, double x) {
if(t == NULL)
return NULL;
else if(x < getFirstData(t->data).getAmount())
return find(t->left, x);
else if(x > getFirstData(t->data).getAmount())
return find(t->right, x);
else
return t;
}
public:
BST() {
root = NULL;
}
~BST() {
root = makeEmpty(root);
}
void insert(std::shared_ptr<Transaction> x) {
root = insert(x, root);
}
std::string search(double x) {
node* result = find(root, x);
if(result != NULL) { return loopNode(result->data); }
else { return "N/A"; }
}
// Gets the first pair key from a multimap
Transaction getFirstData(const multiset<std::shared_ptr<Transaction>>& m) const{
// Declare an iterator to first element
auto itr = m.begin();
return *(*itr);
}
// Loop through a node and return its values
std::string loopNode(const multiset<std::shared_ptr<Transaction>>& m) const{
std::string result;
for (auto it = m.begin(); it != m.end(); ++it){
result += (*it)->toString();
}
return result;
}
};
int main() {
BST t;
t.insert(std::make_shared<Transaction>("1400", "Withdrawal"));
t.insert(std::make_shared<Transaction>("1400.59", "Deposit"));
t.insert(std::make_shared<Transaction>("1400.59", "Deposit - test"));
std::cout << t.search(1400.58);
return 0;
}
```
std::complex
... \$\endgroup\$std::multimap
, which effectively is a BST of its own. \$\endgroup\$