【问题标题】:How to create a binary search tree for complex type that allows duplicates in C++?如何为允许在 C++ 中重复的复杂类型创建二叉搜索树?
【发布时间】:2022-01-22 20:24:21
【问题描述】:

我已经阅读了很多关于 BST 和重复的帖子,并且我知道允许重复是不太可能/没有干净的方法,尤其是对于我正在使用的复杂类型。因此,我需要一些帮助,了解如何/是否可以在我的场景中实现具有重复项的 BST。

我的场景: 我使用事务类作为我的节点键,我比较的主要数据是事务类中的“金额”,所以我的二叉搜索树可以让您输入一个金额并使用它的“toString()”输出任何交易' 对用户的功能,与搜索量相匹配。但是,现在我面临无法重复交易金额的问题。我该如何解决这个问题?谁能提供一个例子?谢谢。

重现要解决的问题的代码:

#include<iostream>
using namespace std;
#include <algorithm>
#include <cctype>
#include <string>
#include <memory>

// 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(&timestamp);
    
        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 {
        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 = x;
            t->left = t->right = NULL;
        }
        else if(x->getAmount() < t->data->getAmount())
            t->left = insert(x, t->left);
        else if(x->getAmount() > t->data->getAmount())
            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 << t->data->getAmount() << " ";
        inorder(t->right);
    }

    node* find(node* t, double x) {
        if(t == NULL)
            return NULL;
        else if(x < t->data->getAmount())
            return find(t->left, x);
        else if(x > 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);
    }

    void display() {
        inorder(root);
        cout << endl;
    }

    std::string search(double x) {
        node* result = find(root, x);
        if(result != NULL) { return result->data->toString(); }
        else { return "N/A"; }
    }
};

int main() {
    BST t;
    t.insert(std::make_shared<Transaction>("1500.50", "Deposit"));
    t.insert(std::make_shared<Transaction>("1600.98", "Deposit"));
    t.insert(std::make_shared<Transaction>("1400", "Withdrawal"));
    t.insert(std::make_shared<Transaction>("1400.59", "Deposit"));
    t.display();
    
    std::cout << t.search(1500.50);
    
    return 0; 
}

【问题讨论】:

  • “二叉搜索树”和“重复”通常不能很好地结合在一起。当您说“重复”时,您的意思是什么?一个键可以有多个完全相同的条目?或者一个键可以有多个不同的条目?
  • @Someprogrammerdude 那么你是如何理解 multimap 和 multiset 的呢?
  • @Someprogrammerdude 相同金额的交易对象
  • 那么可能是树中每个节点的Transaction 对象列表?或者采取简单的方法并使用std::multimap
  • @Someprogrammerdude 你能举个例子我将如何使用 multimap 导致我很困惑

标签: algorithm oop pointers


【解决方案1】:

我已经阅读了很多关于 BST 和重复的帖子,并且我知道允许重复是不太可能/没有干净的方法,尤其是对于我正在使用的复杂类型。

这是不正确的,您可以在这种情况下使用multimap or multiset

例如,cppreference

Multimap 是一个关联容器,其中包含键值对的排序列表,同时允许具有相同键的多个条目。排序是根据比较函数比较完成的,应用于键。搜索、插入和删除操作具有对数复杂度。

您只需提供一个 Compare 函子作为模板参数,它表示对于两个等效键,没有一个小于另一个。

【讨论】:

  • 所以我有一个交易和计数的多重映射?但是如果我想在搜索函数中调用 toString() 函数,它不会只调用一次而不显示交易的不同“原因”。
  • @paigelarry342 您可以从 Compare 类中调用您想要的任何方法。如果比较类返回两个对象彼此不小于彼此,则就 multi-* 而言它们是等价的。如何实施,取决于您。
  • 所以我将 Node 结构中的数据成员更改为 std::multimap>?然后在我的插入中我比较第一个键,如果它匹配我将事务插入到数据多映射中?
  • 使用doubles 进行十进制算术是自找麻烦,看看here。您的代码中有很多问题。
  • @user1095108 没有进行算术运算?只是比较
【解决方案2】:

您可以通过使您的data 成员成为容器来将BST 节点与多个值相关联,例如,更改:

std::shared_ptr<Transaction> data;

进入

std::list<std::shared_ptr<Transaction>> data;

这与将一个键与多个值关联起来是一回事。本质上,这就是std::multimapstd::multiset 所做的。您还必须更新树操作/迭代器。例如,在进行容器遍历时,您必须将单个 std::lists 压缩在一起。

编辑:

一个简单的替代方法是使用std::multiset&lt;std::tuple&lt;std::string, time_t, std::string, bool&gt;&gt;

【讨论】:

  • 这是一个示例implementation
  • 抱歉有点困惑,为什么在这里使用 std::list 而不是 multimap?并且 std::map / std::unordered map 也会做同样的事情。希望你能解释一下谢谢。
  • 好吧,你自己说过你希望能够支持重复,std::list 可以存储重复。因此,data 是您的 node struct 的数据成员,并且键位于列表的前面。
  • 那么您基本上是建议使用列表而不是多图吗?
  • 不,我建议更改您发布的代码,如果您的代码实际上是您想要使用的。其他人说的是,你不需要,你可以使用std::multiset
【解决方案3】:

二叉搜索树可让您存储键和相关记录。它允许有效地搜索给定的键(目的是检索相关信息)。

由于它还支持按排序顺序枚举,它允许检索给定范围内的所有键,重复键不是问题。

【讨论】:

  • 您能否提供一个实现/示例,说明如何让它在我的代码中接受重复值,谢谢
  • @paigelarry342 本质上,将 )。
  • 仅此而已?但是当我开始搜索以查找 x 的所有值及其重复项时,检索所有 x 会不会很困难
  • @paigelarry342 重读我的第二句话。相等的键形成一个范围。修改中缀树遍历。
  • 抱歉,这一切都是新手,等号形成一个范围是什么意思?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
相关资源
最近更新 更多