Sortere en struct etter siste deretter fornavn

stemmer
1

Jeg har algoritmen for sorter etter etternavn, men jeg har problemer med å finne ut hvordan du kan sortere etter etternavn, så hvis to personer har samme etternavn, sorter etter deres fornavn.

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;
            }
        }
    }
}

=== EDIT ====================

Jeg ønsker ikke å bruke STD sort()

Publisert på 14/05/2009 klokken 17:07
kilden bruker
På andre språk...                            


11 svar

stemmer
9

Hvorfor er du ikke bruker std::sort? Det er hva det er for:

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());

Selvfølgelig, du virkelig bør bruke C ++ std::stringklasse også. Det er det det handler om. Og så trenger du ikke å skru rundt med feilutsatte C streng manipulasjon funksjoner som stricmp.

Svarte 14/05/2009 kl. 17:18
kilden bruker

stemmer
5

Først sammenligne etternavn. Hvis de er like, og deretter sammenligne fornavn:

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]
Svarte 14/05/2009 kl. 17:10
kilden bruker

stemmer
4

For det første, anvendelse qsorteller de riktige C ++ tilsvarende som tar en funksjon som sammenligner to objekter.

Sammenligningen bør da være trivielt:

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: en real C ++ implementering ville sannsynligvis bruke maler for sammenligningsfunksjonen.

Svarte 14/05/2009 kl. 17:11
kilden bruker

stemmer
3

Du må endre sammenligning. Den grunnleggende algoritmen er hvis venner [i]> venner [J] deretter bytte dem. Så endrer din definisjon av ">" for å inkludere fornavn sammenligninger.

Noe som følgende burde gjøre:

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))

Du vil kanskje gjøre etternavn sammenligning bare én gang selv om (lagre den i en temp variabel i stedet for å sammenligne to ganger), men ideen er den samme.

Legg merke til at den "beste" måten å gjøre dette på kan være å gi sammenligning funksjoner i VENN klassen. Deretter kan du bruke if(friends[i].CompareTo(friends[j]) > 0)i stedet.

Svarte 14/05/2009 kl. 17:12
kilden bruker

stemmer
2

I tillegg til valg av å bygge en sammenligning funksjon som bruker begge navnene, kan du sortere på neven navnene deretter sortere på etternavn, men du må passe på å bruke en stabil form for andre pass. Kan like godt bruke det for det første også.

Gode nyheter: std::stable_sorter tilgjengelig og garantert å være, vel, stabil (takket være Adam og libt for korreksjon). Sletten std::sortog c standard bibliotek qsorter ikke garantert å være stabil, men noen gjennomføring kan være. Som Mark påpeker i kommentarfeltet, den boblesortering du viser er allerede stabil.


Dette er mindre effektiv at single-sort-med-en-tilpasset sammenligne funksjons valg, men det gjør det lett å la deg brukeren velge flere former ved kjøring (fordi du ikke trenger å definere alle mulige sammenligning funksjon eller en mini-språk).

Svarte 14/05/2009 kl. 17:19
kilden bruker

stemmer
1

Hvis du ikke har noe imot å bruke boost.tuple (og erstatte eller i det minste endre eksisterende implementering av Friend), er det en inkludert sammenligning funksjon.

#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;

Alle de ovennevnte skal fungere.

Svarte 14/05/2009 kl. 17:29
kilden bruker

stemmer
1

Vennligst ikke implementere slags selv - std :: sort (i <algorithm>) gjør denne jobben mye bedre og mye mer effektiv. (Bortsett fra at du bare ønsker å se hvordan algoritmen fungerer for eksperimentelle formål)

Du må oppgi en sammenligning funksjon eller bedre en funktor uansett.

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

Du kan bare påberope seg slik:

std::sort(friendArray, friendArray + count, FriendComparer());
Svarte 14/05/2009 kl. 17:17
kilden bruker

stemmer
0

Du kan sortere etter etternavn og hvis etternavn er de samme, sortere dem etter fornavn. Noe sånt som dette (boblesortering brukt):

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]);
    }
Svarte 16/01/2016 kl. 16:18
kilden bruker

stemmer
0

du kan bruke en sammensetning av venstre justert etternavn og fornavn som en sorteringsnøkkel

Dette er et annet synspunkt du leter etter, tror jeg :)

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
}
Svarte 14/05/2009 kl. 18:06
kilden bruker

stemmer
0

Definer en sammenligning funksjon (eller klassen som jalf foreslått) og bruke STL er std :: sort ():

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);
}
Svarte 14/05/2009 kl. 17:21
kilden bruker

stemmer
0

Legg til følgende:

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;
}
Svarte 14/05/2009 kl. 17:11
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more