The normal way to do this is by having a predicate function which inspects two objects and returns true/false whether the left-hand-side object is less-than the right-hand-side. In modern C++ you can do this with a lambda:
auto sortByYards = [](const team_stats& lhs, const team_stats& rhs) -> bool {
return lhs.yards_per_game < rhs.yards_per_game;
};
quickSort(arr, numTeams, sortByYards);
Your quickSort function would have a fingerprint like this:
void quickSort(team_stats* arr, size_t numTeams, std::function<bool(const team_stats&, const team_stats&)> predicate) {
...
}
or you could use a using
statement to make this more readable:
using QuickSortPred = std::function<bool(const team_stats&, const team_stats&)>;
void quickSort(team_stats* arr, size_t numTeams, QuickSortPred predicate) {
where you currently do the comparison left < right
or right > left
you would replace with
if (predicate(left, right))
(if you have any >
comparisons, just switch them around to a <
and then map to predicate)
#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
struct TeamStats {
std::string name;
float yards_per_game;
int total_points;
};
using QuickSortPred = std::function<bool(const TeamStats&, const TeamStats&)>;
void quickSort(TeamStats* arr, size_t numTeams, QuickSortPred predicate)
{
/// NOTE: This is NOT a complete quicksort, it's just to demonstrate
/// the usage of predicate.
for (size_t i = 0; i < numTeams - 1; ++i) {
// before: if (arr[i] < arr[i+1])
if (predicate(arr[i], arr[i+1]))
std::swap(arr[i], arr[i+1]);
}
}
int main() {
TeamStats arr[] = {
{ "Red", 100, 30, },
{ "Blue", 150, 10, },
{ "Green", 200, 20, },
};
// approach one, store the lambda before hand
auto sortByYards = [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
return lhs.yards_per_game < rhs.yards_per_game;
};
quickSort(arr, 3, sortByYards);
// approach two, write the lambda inline.
quickSort(arr, 3, [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
return lhs.total_points < rhs.total_points;
});
return 0;
}
Live demo: http://ideone.com/7qLtfV
And if we're going to do it properly in modern C++, we'd probably use a container other than a flat array for our sortable objects, such as a vector. If your exercise is to develop a quick sort routine, you'll want to replace 'std::sort' with your own code :)
#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
struct TeamStats {
std::string name;
float yards_per_game;
int total_points;
};
using QuickSortPred = std::function<bool(const TeamStats&, const TeamStats&)>;
template<typename I>
void quickSort(I begin, I end, QuickSortPred predicate)
{
/// NOTE: This is NOT a complete quicksort, it's just to demonstrate
/// the usage of predicate.
std::sort(begin, end, predicate);
}
int main() {
std::vector<TeamStats> arr {
{ "Red", 100, 30, },
{ "Blue", 150, 10, },
{ "Green", 200, 20, },
};
// approach one, store the lambda before hand
auto sortByYards = [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
return lhs.yards_per_game < rhs.yards_per_game;
};
quickSort(arr.begin(), arr.end(), sortByYards);
std::cout << "By yards:\n";
for (auto& it : arr) {
std::cout << it.yards_per_game << " " << it.name << "\n";
}
// approach two, write the lambda inline.
quickSort(arr.begin(), arr.end(), [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
return lhs.total_points < rhs.total_points;
});
std::cout << "By points:\n";
for (auto& it : arr) {
std::cout << it.total_points << " " << it.name << "\n";
}
return 0;
}
Live demo: http://ideone.com/N35RRn
If you're not trying an exercise to write your own quicksort, you can remove all the quicksort stuff here and boil it down to
#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
struct TeamStats {
std::string name;
float yards_per_game;
int total_points;
};
int main() {
std::vector<TeamStats> arr {
{ "Red", 100, 30, },
{ "Blue", 150, 10, },
{ "Green", 200, 20, },
};
// approach one, store the lambda before hand
auto sortByYards = [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
return lhs.yards_per_game < rhs.yards_per_game;
};
std::sort(arr.begin(), arr.end(), sortByYards);
std::cout << "By yards:\n";
for (auto& it : arr) {
std::cout << it.yards_per_game << " " << it.name << "\n";
}
// approach two, write the lambda inline.
std::sort(arr.begin(), arr.end(), [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
return lhs.total_points < rhs.total_points;
});
std::cout << "By points:\n";
for (auto& it : arr) {
std::cout << it.total_points << " " << it.name << "\n";
}
return 0;
}
live demo: http://ideone.com/vDSYtj