代码之家  ›  专栏  ›  技术社区  ›  Joe

按姓氏和名对结构排序

  •  1
  • Joe  · 技术社区  · 15 年前

    我有按姓氏排序的算法,但是我很难找出如何按姓氏排序,如果两个人的姓氏相同,就按他们的姓氏排序。

    void sortLastName(FRIEND friends[ARRAY_MAX], int& count) {
    
        FRIEND temp;
    
        for(int i = 0; i < count - 1; i++) {
            for (int j = i + 1; j < count; j++) {
                if (stricmp(friends[i].lastName, friends[j].lastName) > 0)  {
                    temp = friends[i];    //swapping entire struct
                    friends[i] = friends[j];
                    friends[j] = temp;
                }
            }
        }
    }
    

    ==编辑====================

    我不想用 STD sort()

    11 回复  |  直到 12 年前
        1
  •  9
  •   Stack Overflow is garbage    15 年前

    你为什么不使用 std::sort ?这就是它的用途:

    struct NameComparer {
      bool operator()(const FRIEND& lhs, const FRIEND& rhs){
        int compareResult = stricmp(lhs.lastName, rhs.lastName);
        if(compareResult == 0){
          compareResult = stricmp(lhs.firstName, rhs.firstName);
        }
        return compareResult < 0;
      }
    };
    
    std::sort(friends, friends + ARRAY_MAX, NameComparer());
    

    当然,你真的应该使用C++ std::string 上课也一样。这就是它的用途。然后你就不必纠结于容易出错的c字符串操作函数,比如 stricmp .

        2
  •  5
  •   Adam Rosenfield    15 年前

    首先,比较姓氏。如果它们相等,则比较第一个名称:

    int compareResult = stricmp(friends[i].lastName, friends[j].lastName);
    if(compareResult == 0)
        compareResult = stricmp(friends[i].firstName, friends[j].firstName);
    if(compareResult < 0)
        // swap friends[i] and friends[j]
    
        3
  •  4
  •   Alnitak    15 年前

    首先,使用 qsort 或者适当的C++等价物,它取一个比较两个对象的函数。

    然后,比较应该是微不足道的:

    int compare_by_name(const FRIEND& f1, const FRIEND& f2)
    {
        int last_name_matches = strcmpi(f1.lastName, f2.lastName);
        return (last_name_matches != 0) ? last_name_matches :
                strcmpi(f1.firstName, f2.firstName) ;
    }
    

    NB:一个真正的C++实现可能使用比较器函数的模板。

        4
  •  3
  •   lc.    15 年前

    你必须改变你的比较。基本算法是,如果朋友[i]>朋友[j],则交换它们。因此,请更改您对“>”的定义以包括名字比较。

    应该这样做:

    if (stricmp(friends[i].lastName, friends[j].lastName) > 0 ||
        (stricmp(friends[i].lastName, friends[j].lastName) == 0 && 
        stricmp(friends[i].firstName, friends[j].firstName) > 0))
    

    不过,您可能只想进行一次姓氏比较(将其存储在一个临时变量中,而不是进行两次比较),但想法是相同的。

    注意,最好的方法可能是在friend类中提供比较函数。然后你可以使用 if(friends[i].CompareTo(friends[j]) > 0) 相反。

        5
  •  2
  •   Community CDub    7 年前

    除了选择使用两个名称的比较函数之外,还可以对第一个名称进行排序。 然后 按姓氏排序,但必须注意使用 stable sort 第二次传球。也不妨先用一下。

    好消息: std::stable_sort 是可用的,并保证,嗯,稳定(感谢亚当和利伯特的纠正)。平原 std::sort 以及C标准库 qsort 虽然有些实现可能是稳定的,但不能保证是稳定的。正如马克在评论中指出的,你展示的泡沫分类已经很稳定了。


    这比单排序与自定义比较函数的选择效率低,但它使您可以轻松地在运行时选择多个排序(因为您不必定义每个可能的比较函数或迷你语言)。

        6
  •  1
  •   Dario    15 年前

    请不要自己实现排序——STD::排序(in) <algorithm> )这项工作做得更好,效率更高。(除非你只是想看看你的算法是如何用于实验目的的)

    无论如何,你必须指定一个比较函数或更好的函子。

    struct FriendComparer {
      bool operator () (const FRIEND& a, const FRIEND& b) {
          // Comparison code here (see previous posts)
      }
    };
    

    你可以这样调用它:

    std::sort(friendArray, friendArray + count, FriendComparer());
    
        7
  •  1
  •   Benoît photo_tom    15 年前

    如果你不介意用 boost.tuple (以及替换或至少修改friend的现有实现),其中包含一个比较函数。

    #include <boost/tuple/tuple.hpp>
    #include <boost/tuple/tuple_comparison.hpp>
    
    typedef boost::tuple<std::string, std::string> Friend;
    
    Friend f1, f2;
    bool compareFriends = f1 < f2;
    

    以上这些都应该有效。

        8
  •  0
  •   KevinDTimm    15 年前

    添加以下内容:

    else if (stricmp(friends[i].lastName, friends[j].lastName) == 0 &&
             stricmp(friends[i].firstName, friends[j].firstName) > 0) {
        temp = friends[i];    //swapping entire struct
        friends[i] = friends[j];
        friends[j] = temp;
    }
    
        9
  •  0
  •   Jon-Eric    15 年前

    定义一个比较函数(或类为JALF建议),并使用STL的STD::SoTo():

    bool compareFriends(FRIEND const & lhs, FRIEND const & rhs)
    {
        int const resultLast = stricmp(lhs.lastName, rhs.lastName);
    
        if(resultLast == 0)
        {
            return stricmp(lhs.firstName, rhs.firstName) < 0;
        }
        else
        {
            return resultLast < 0
        }
    }
    
    void sortLastName(FRIEND friends[ARRAY_MAX], int& count)
    {
        std::sort(friends, friends + count, &compareFriends);
    }
    
        10
  •  0
  •   jonny    15 年前

    可以使用左对齐的姓氏和名字作为排序关键字的连接。

    这是你在寻找的另一个观点,我想:)

    string key(const FRIEND& aFriend)
    {
        const int INITIALS_MAX_LENGTH = 200; // assume the worst
    
        string firstNameKeyPart = string(INITIALS_MAX_LENGTH, ' ');
        string lastNameKeyPart = string(INITIALS_MAX_LENGTH, ' ');
    
        firstNameKeyPart.replace(0, 0, aFriend.firstName);
        lastNameKeyPart.replace(0, 0, aFriend.lastName);
    
        return  lastNameKeyPart + firstNameKeyPart;
    }
    
    //...
    
    if ( key(friends[i]) > key(friends[j]) )
    {
      //swap
    }
    
        11
  •  0
  •   Supreme Entropy    8 年前

    你可以用姓氏排序,如果姓氏是相同的,用名字来排序。 类似这样(使用气泡排序):

    for (int i = 1; i < dictionary.size(); ++i)
        for (int j = 0; j < dictionary.size()-1; ++j) {
            if (dictionary[i].Last < dictionary[j].Last)
                swap(dictionary[i], dictionary[j]);
        }
    
    for (int i = 1; i < dictionary.size(); ++i)
        for (int j = 0; j < dictionary.size() - 1; ++j) {
            if (dictionary[i].Last == dictionary[j].Last && dictionary[i].First < dictionary[j].First)
                swap(dictionary[i], dictionary[j]);
        }