【问题标题】:How do I compare strings (insensitive case), while inserting same strings into a binary Tree (sensitive case)?如何比较字符串(不区分大小写),同时将相同的字符串插入二叉树(区分大小写)?
【发布时间】:2020-02-23 23:14:48
【问题描述】:

本质上,对于如何将字符串与我的insert 函数进行比较,我是一堵砖墙,在将相同的字符串与其原始大小写同时插入时不考虑大小写。

这是我的insert 函数。

TreeNode* Tree::insert(TreeNode* node, string value) {
    transform(value.begin(), value.end(), value.begin(), ::tolower);

    if (node == nullptr) {
        return newTreeNode(value);
    }
    if (node->data < value) {
        node->left = insert(node->left, value);
    }
    else if(node-> data > value) {
        node->right = insert(node->right, value);
    }
    else {
        return node;
    }
    node->height = 1 + max(height(node->left), height(node->right));
    return node;
}

这是我的树头文件:

struct TreeNode {
public:
    TreeNode* left;
    TreeNode* right;
    string data;
};

class Tree {
public:
    TreeNode * newTreeNode(string data);
    TreeNode * insert(TreeNode* node, string value);
    void lexographicPrint(TreeNode* root);
};

newTreeNode 函数:

TreeNode* AvlTree::newTreeNode(string value) {
    TreeNode* treeNode = new TreeNode();
    treeNode->data = value;
    treeNode->left = nullptr;
    treeNode->right= nullptr;
    treeNode->height = 1;
    return treeNode;
}

打印功能:

void AvlTree::lexographicPrint(TreeNode* root) {
    if (root != nullptr) {
        lexographicPrint(root->right);
        cout << root->data << " ";
        lexographicPrint(root->left);
    }
}

这目前可以按我的意愿工作,除了 Tree 包含所有小写的值,这显然是由于 transform 函数。我尝试过使用holdValue,如下所示:

string holdValue;
if (isupper(value[0]) {
    holdValue = value;
}

在我的函数顶部,用holdValue 替换所有insert 调用。我很困惑为什么在与value 进行比较时会改变我的树的顺序。我希望这能奏效,但事实并非如此。我还没有通过 Google 搜索找到解决方案。

【问题讨论】:

  • 请用无效的代码创建一个minimal reproducible example
  • 添加了 newTreeNode() 和 lexicographicPrint() 函数。这就是我从你提供的链接中得到的,如果我弄得更糟,对不起。
  • 首先,创建一个返回truefalsecompare 函数,具体取决于插入的字符串是否小于树中的字符串——不要硬编码在insert 中进行比较。一旦你有了它,你就有了如何解决问题的框架,那就是compare 函数在某种程度上应该是通用的。
  • 明白了,谢谢。本质上,我正在创建一个单独的compare,其中true 可以表示插入左节点和右节点(反之亦然),比较函数将忽略大小写,而insert 函数将保留原始价值观?
  • @Suede -- 是的 -- 到目前为止,其他人给出的两个答案都抓住了你应该做的事情的本质。

标签: c++ binary-tree binary-search-tree string-comparison


【解决方案1】:

您可以使用不区分大小写的比较,而不是使用std::string&lt;

bool ci_less(const std::string & lhs, const std::string & rhs) {
    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](char l, char r){ return std::to_lower(l) < std::tolower(r); });
}

TreeNode* Tree::insert(TreeNode* node, std::string value) {

    if (node == nullptr) {
        return newTreeNode(std::move(value));
    }
    if (ci_less(node->data, value)) {
        node->left = insert(node->left, std::move(value));
    }
    else if(ci_less(value, node->data)) {
        node->right = insert(node->right, std::move(value));
    }
    else {
        return node;
    }
    node->height = 1 + max(height(node->left), height(node->right));
    return node;
}

您需要#include &lt;algorithm&gt; 才能获得std::lexicographical_compare

类似地,您可以改为定义 case insensitive string type

struct ci_char_traits : public std::char_traits<char> {
    static char to_upper(char ch) {
        return std::toupper((unsigned char) ch);
    }
    static bool eq(char c1, char c2) {
         return to_upper(c1) == to_upper(c2);
     }
    static bool lt(char c1, char c2) {
         return to_upper(c1) <  to_upper(c2);
    }
    static int compare(const char* s1, const char* s2, size_t n) {
        while ( n-- != 0 ) {
            if ( to_upper(*s1) < to_upper(*s2) ) return -1;
            if ( to_upper(*s1) > to_upper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, int n, char a) {
        auto const ua (to_upper(a));
        while ( n-- != 0 ) 
        {
            if (to_upper(*s) == ua)
                return s;
            s++;
        }
        return nullptr;
    }
};

using ci_string = std::basic_string<char, ci_char_traits>;

【讨论】:

    【解决方案2】:

    本质上,您希望存储大小写混合的值,但按小写形式排序。

    你可以做两件事。

    1. case_insensitive_compare(a, b) &lt; 0case_insensitive_compare(a, b) &gt; 0 替换所有a &lt; ba &gt; b 检查,其中case_insensitive_compare 看起来像:

      // +ve => l > r
      // 0 => l equivalent to r (possibly different case)
      // -ve => l < r
      int case_insensitive_compare(const std::string& l, const std::string& r) noexcept {
          std::size_t max_size = std::max(l.size(), r.size());
          for (std::size_t i = 0; i < max_size; ++i) {
              int cmp = std::tolower(l[i]) - std::tolower(r[i]);
              if (cmp != 0) return cmp;
          }
          return l.size() - r.size();
      }
      
      // Or in c++20
      // std::weak_ordering::greater => l > r
      // std::weak_ordering::equivalent => l equivalent to r
      // std::weak_ordering::less => l < r
      std::weak_ordering case_insensitive_compare(const std::string& l, const std::string& r) noexcept {
          std::size_t max_size = std::max(l.size(), r.size());
          for (std::size_t i = 0; i < max_size; ++i) {
              auto cmp = std::tolower(l[i]) <=> std::tolower(r[i]);
              if (cmp != 0) return cmp;
          }
          return l.size() <=> r.size();
      }
      

      您应该能够将此推广到任何比较器函数(对于Tree&lt;T&gt;,比较器cmp(const T&amp;, const T&amp;) -&gt; int

    2. 让您的TreeNode 存储一个键/值对,其中键是小写字符串,值是混合大小写字符串。如果您需要让树存储另一个值,请将值设为 std::tuple&lt;std::string, ValueType&gt;

    【讨论】:

    • 所以本质上是一个忽略大小写然后仍然插入原始大小写的通用比较函数?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2011-05-27
    • 1970-01-01
    相关资源
    最近更新 更多