22

I am having a hard time with this problem which requires a sort of customer names, customer ids, and finally amount due. I have the whole program figured, but cannot figure out the last prototype needed to do the sorting. i have a struct called Customers, and i will provide the int main() part also. I just need any help to gt started on the prototype SortData().

struct Customers {
    string Name;
    string Id;
    float OrderAmount;
    float Tax;
    float AmountDue;
};

const int MAX_CUSTOMERS = 1000;
bool MoreCustomers(int);
Customers GetCustomerData();
void OutputResults(Customers [], int);
void SortData(const int, const int, Customers []);

int main() {
    Customers c[MAX_CUSTOMERS]; 
    int Count = 0;      
    do {
      c[Count++] = GetCustomerData();   
    } while (MoreCustomers(Count));     


    for (int i = 0; i < Count; i++) {
        c[i].Tax = 0.05f * c[i].OrderAmount;        
        c[i].AmountDue = c[i].OrderAmount + c[i].Tax;   
    }

    SortData(0, Count, c);     //0:Sorts by customer name       
    OutputResults(c, Count);            
    GeneralSort(1, Count, c);   //1:Sorts by ID     
    OutputResults(c, Count);        
    GeneralSort(2, Count, c);   //2: Sorts by amount due        
    OutputResults(c, Count);        

    return 0;                       
}


void SortData(const int SortItem, const int count, CustomerProfile c[]) {
     //0: Sort by name
    //1: Sort by ID
    //3: Sort by amount due
}
animuson
  • 53,861
  • 28
  • 137
  • 147

5 Answers5

56

You should use C++'s standard sort function, std::sort, declared in the <algorithm> header.

When you sort using a custom sorting function, you have to provide a predicate function that says whether the left-hand value is less than the right-hand value. So if you want to sort by name first, then by ID, then by amount due, all in ascending order, you could do:

bool customer_sorter(Customer const& lhs, Customer const& rhs) {
    if (lhs.Name != rhs.Name)
        return lhs.Name < rhs.Name;
    if (lhs.Id != rhs.Id)
        return lhs.Id < rhs.Id;
    return lhs.AmountDue < rhs.AmountDue;
}

Now, pass that function to your sort call:

std::sort(customers.begin(), customers.end(), &customer_sorter);

This assumes you have an STL container (and not an array, like you have in your sample code) called customers containing customers.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
14

Its often overlooked that you can actually use STL range functions with C based arrays, like in your example. So you don't actually have to move over to using an STL based container (I won't debate the merits of doing that here :-)).

So, building on the answer from Chris, you could invoke sort as follows:

std::sort( customers, customers+Count, &customer_sorter);
CodeBuddy
  • 5,749
  • 1
  • 25
  • 30
2

You only need to write a comparison function that compares two CustomerProfile types. Once you have this function, you can use either the STL sort (see http://www.sgi.com/tech/stl/sort.html or http://msdn.microsoft.com/en-us/library/ecdecxh1(VS.80).aspx) or the old C qsort: http://en.wikipedia.org/wiki/Qsort_(C_Standard_Library). I would advise against writing your own sort algorithm, unless this is a homework assignment. Your comparison depends on the technology you like to use, it could look do something like this:

int CompareCustomerProfile(
   const CustomerProfile* pC1,
   const CustomerProfile* pC2)
{
 int result = strcmp(pC1->name, pC2->name);
 if (0 != result) return result; 

  result = strcmp(pC1->ID, pC2->ID);
  if (0 != result) return result;

  if (pC1->amountDue < pC2->amountDue) return -1;
 if (pC1->amountDue > pC2->amountDue) return 1;

  return 0
}

this assumes that the 'string' type in your example is a char*. If you use Unicode or multibyte types then the appropriate Unicode or multibyte comparison has to be used, obviously. Then you would just call the algorithm, with your comparison function. Eg. using qsort:

qsort(c, Count, sizeof(CustomerProfile), CompareCustomerProfiler).

Now if this is a homework assignment, you shouldn't be asking here how to do it...

Remus Rusanu
  • 288,378
  • 40
  • 442
  • 569
1

You can find a lot of sort implementations in C++ with creative googling.. The only difference is that instead of sorting numbers, you are sorting structs.

So wherever there is something like if(a[i]<a[j]) in the algorithm you will use, make a call like `if(isFirstCustomerLowerThanOther(a[i]

Now, create a function with the following structure:

bool isFirstCustuomerLowerThanOther(const Customer& firstCustomer, const Customer& secondCustomer)
{
 // Implement based on your key preferences
}

Even better, if you use C++ you can use the STL's sort algortihm (again, google for info and for how to pass an ordering to it.

Uri
  • 88,451
  • 51
  • 221
  • 321
0

I assume that you are new to programming or in C++, so here is what you probably are looking for:

#include <search.h> // for the qsort()

int
CompareByName( const void *elem1, const void *elem2 )
{
  return ((Customers*)elem1)->Name > ((Customers*)elem2)->Name? 1 : -1;
}

int
CompareByOrderAmount( const void *elem1, const void *elem2 )
{
  return ((Customers*)elem1)->OrderAmount > ((Customers*)elem2)->OrderAmount? 1 : -1;
}

void SortData( int SortItem, int count, Customers customers[] )
{
  switch (SortItem) {
  case 0:
    qsort(customers, count, sizeof(Customers), CompareByName);
    break;
  case 1:
    qsort(customers, count, sizeof(Customers), CompareByOrderAmount);
    break;
  // ...
  }
}

void test()
{
  Customers cust[10];

  cust[0].Name = "ten";
  cust[1].Name = "six";
  cust[2].Name = "five";
  SortData( 0, 3, cust );
  cout << cust[0].Name << endl;
  cout << cust[1].Name << endl;
  cout << cust[2].Name << endl;
}
Nick Dandoulakis
  • 42,588
  • 16
  • 104
  • 136
  • Your answer is distinctly a C-style answer, with no C++ qualities to it (except for the use of the overloaded > operator for strings). If this were a C question (and you changed the string comparison to be strcmp), your answer would be useful, but the way it is, it's not useful for the question at all. For starters, in C++ style, sorting should be using std::sort, not qsort. (BTW, even in using qsort, your comparison function must handle the case when two elements are equal, and return 0.) – C. K. Young May 17 '09 at 23:52
  • Yes you are right. But using plain struct is also C-style. Using STL maybe is a bit cryptic for starters. Anyway, I have no problem to delete my answer. – Nick Dandoulakis May 18 '09 at 07:32
  • 1
    My comparison function should handle the case of equal elements, true. However, that case is rare and the actual problem is that when we sort arrays it is better to use arrays of pointers and not arrays of structures. So any *good* answer is subjective. – Nick Dandoulakis May 18 '09 at 07:41
  • Agree about not having containers of whole structures, to make the sort less expensive. I can't speak about idiomatic use of arrays in C++, but it's discouraged to use (bare) pointers in STL containers, because object lifetime is harder to track that way. (shared_ptr is recommended when pointers are desired, e.g., to avoid slicing, or to prevent lots of object copying (like this case), or when used with an uncopyable type.) – C. K. Young May 18 '09 at 11:58
  • Actually, on that note, AFAIK qsort is usable only with POD types (the standard seems to be silent on this topic, but Googling "can qsort be used with non-pod types" is revealing). The OP's example uses some non-POD types (std::string, in particular) in the struct, so this is another argument in favour of holding pointers instead of whole objects. (However, smart pointers like shared_ptr are not POD types either, so using qsort is generally not recommended, regardless.) – C. K. Young May 18 '09 at 12:06
  • For reference: Later revisions of the C++ standard are not so silent on whether qsort is usable with non-POD types: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2062.html – C. K. Young May 18 '09 at 12:11