在插入set c ++之前比较字符串

时间:2015-06-21 04:46:11

标签: c++ set

我试图通过比较字符串的长度来比较插入到我的集合之前的字符串。应首先插入最短的字符串。我不知道发生了什么,但有些话不在场上。

我的代码:

#include <iostream>
#include <string>
#include <set>

struct compare {
    bool operator() (const string& a, const string& b) const{
        return a.size() < b.size();
    }
};

template<typename T>
void print(const T& t){
    for(auto& it : t)
        cout << it << endl;
}

int main() {    
    string word;
    set<string, compare> c;

    while(cin >> word)
        c.insert(word);

    print(c);

    return 0;
}

以下是要插入的测试词

Apple
Apricots
Avocado
Durian
Fig
Tangerine/Clementine
Kumquat
Lemon
Pear
Prunes
Raspberries
Strawberries
Watermelon

这是OUTPUT

Fig
Pear
Apple
Durian
Avocado
Apricots
Watermelon
Raspberries
Strawberries
Tangerine/Clementine

它按预期工作,但显然有些词语缺失 喜欢:

Kumquat
Lemon
Prunes

5 个答案:

答案 0 :(得分:4)

std::set不能包含重复项。在这种情况下,它不能有两个相同长度的字符串。也许你会用std::multiset做得更好?

#include <iostream>
#include <string>
#include <set>

struct compare {
    bool operator() (const std::string& a, const std::string& b) const{
        return a.size() < b.size();
    }
};

template<typename T>
void print(const T& t){
    for(auto& it : t)
        std::cout << it << std::endl;
}

int main() {
    std::string word;
    std::multiset<std::string, compare> c; // multiset!!!

    while(std::cin >> word)
        c.insert(word);

    print(c);

    return 0;
}

<强>输出:

Fig
Pear
Apple
Lemon
Durian
Prunes
Avocado
Kumquat
Apricots
Watermelon
Raspberries
Strawberries
Tangerine/Clementine

注意:此解决方案允许重复的字符串长度,以便字符串可以按长度排序。但这意味着它还允许重复的字符串值,以便相同的字符串可以出现多次。

答案 1 :(得分:3)

设置不允许重复元素。如果集合的比较函数是less,则集合使用!less(a, b) && !less(b, a)来确定两个元素是否相同(因此是重复的)。

默认情况下,集合使用的比较函数是<运算符。所以当你这样做时:

set::set<int> s;
int x = 42, y = 42;
s.insert(x);
s.insert(y);

仅插入一个元素的原因是x < y为false且y < x也为false,因此集合确定x == y并忽略第二个插入。

但是通过你定义的比较函数,所有相同长度的字符串都被认为是相同的。一旦字符串中存在长度为N的字符串,您尝试插入的所有未来字符串N将不会被插入(因为该集合认为它们已经存在)。

std::set<string, compare> s;
s.insert("abc");
s.insert("def");

less("abc", "def")为false且less("def", "abc")为false,因此该集合将"abc""def"解释为相同。

您可以使用打破平局less功能解决此问题,例如:

bool operator() (const string& a, const string& b) const{
    if (a.size() == b.size()) {
      return a < b;
    }
    return a.size() < b.size();
}

这将首先按大小对字符串进行排序,但通过按字典顺序排序来断开连接。现在两个字符串不会被认为是相等的,除非它们实际上是相同的。

答案 2 :(得分:2)

您是否注意到集合中的所有条目都有不同的长度?

那是因为compare函数决定了某些内容是否被认为是该集合中已有内容的重复:

  

如果key_comp以反射方式返回false(即无论元素作为参数传递的顺序),则集合中的两个元素被认为是等效的。

因为,对于两个长度相同的单词,key_comp(word1, word2)key_comp(word2, word1)都返回false,单词被认为是相同的,因此第二个单词不会插入到集合中。

您可以通过略微修改您的功能来解决此问题:

bool operator() (const string& a, const string& b) const {
    if (a.size() == b.size()) return a < b;
    return a.size() < b.size();
}

执行基于内容的比较(而不是基于长度),其中两个项目的长度相同)。

答案 3 :(得分:2)

解决这个问题的第一步应该是简化,在这种情况下,删除输入作为潜在原因。这样做表明问题不是由数据源引起的。因此,让我们看看是否存储了值:

#include <iostream>
#include <string>
#include <set>

struct compare {
    bool operator() (const std::string& a, const std::string& b) const{
        return a.size() < b.size();
    }
};

template<typename T>
void print(const T& t){
    for(auto& it : t)
        std::cout << it << "\n";
}

template<typename T>
void insert(T& t, const char* value)
{
    t.insert(value);
    std::cout << "After inserting " << value << "\n";
    print(t);
    std::cout << "\n";
}

int main() {    
    std::set<std::string, compare> c;

    insert(c, "Apple");
    insert(c, "Apricots");
    insert(c, "Avocado");
    insert(c, "Durian");
    insert(c, "Fig");
    insert(c, "Tangerine/Clementine");
    insert(c, "Kumquat");
    insert(c, "Lemon");
    insert(c, "Pear");
    insert(c, "Prunes");
    insert(c, "Raspberries");
    insert(c, "Strawberries");
    insert(c, "Watermelon");

    print(c);

    return 0;
}

这些价​​值不会被存储,但似乎我们可以解决这个问题:

    insert(c, "Apple");
    insert(c, "Lemon");

http://ideone.com/aGZOIN

std::set::insert会返回一些可能有用的信息:http://www.cplusplus.com/reference/set/set/insert/

    auto result = t.insert(value);

我们对result.second感兴趣。对于成功插入将是真实的(1),对于失败则为假(0)。

http://ideone.com/wP4CaG

After inserting Apple. inserted? 1
Apple

After inserting Lemon. inserted? 0
Apple

您的比较运算符导致集合认为这两个值相等。 std::set使用<运算符两次确定等效性:

if (!cmp(a, b))
    if (!cmp(b, a))
        // equal;

您可能想要使用:

struct compare {
    bool operator() (const string& a, const string& b) const{
        if (a.size() < b.size())
            return true;
        if (a.size() == b.size() && a.compare(b) < 0)
            return true;
        return false;
    }
};

完整代码:

#include <iostream>
#include <string>
#include <set>

struct compare {
    bool operator() (const std::string& a, const std::string& b) const{
        if (a.size() < b.size())
            return true;
        if (a.size() == b.size() && a.compare(b) < 0)
            return true;
        return false;
    }
};

template<typename T>
void print(const T& t){
    for(auto& it : t)
        std::cout << it << "\n";
}

template<typename T>
void insert(T& t, const char* value)
{
    auto result = t.insert(value);
    std::cout << "After inserting " << value << ". inserted? " << result.second << "\n";
    print(t);
    std::cout << "\n";
}

int main() {    
    std::set<std::string, compare> c;

    insert(c, "Apple");
    insert(c, "Lemon");
    insert(c, "Fig");
    insert(c, "Kumquat");

    print(c);

    return 0;
}

http://ideone.com/Vs5p0i

输出:

After inserting Apple. inserted? 1
Apple

After inserting Lemon. inserted? 1
Apple
Lemon

After inserting Fig. inserted? 1
Fig
Apple
Lemon

After inserting Kumquat. inserted? 1
Fig
Apple
Lemon
Kumquat

答案 4 :(得分:1)

如果您不是特别关心最有效的解决方案,只关心插入的顺序。这是一个简单的解决方案:排序然后插入。

#include <vector>
#include <set>
#include <algorithm>
#include <iostream>

std::set<std::string> InsertByLength(std::vector<std::string> src)
{
  std::sort(src.begin(), src.end(), [](const std::string& a, const std::string& b)
            {
            return a.size() < b.size();
            });

  std::set<std::string> ret;
  for(auto s : src) {
    std::cout << s << std::endl;
    ret.insert(s);
  }

  return ret;
}

int main()
{
  auto result = InsertByLength({
    "Apple", "Apricots", "Avocado", "Durian", "Fig", "Tangerine/Clementine",
    "Kumquat", "Lemon", "Pear", "Prunes"  "Raspberries", "Strawberries",
    "Watermelon"});

  std::cout << "Inserted: " << result.size() << " elements\n";

  return 0;
}

http://ideone.com/d1T0ew