我有一个包含19个变量的结构,我需要使用不同的排序算法来对这个结构进行排序,事实是它可以通过任何这些变量进行排序。我想知道是否有任何方法可以在结构中动态访问这些数据,这样我就可以编写一个方法来进行排序,而不是编写19个不同的方法来运行相同的排序算法但是在内部的不同变量上。
所以我有我的结构
struct team_stats{
float yards_per_game;
int total_points;
etc etc
team_stats* arr = new team_stats[32];
我想做这样的事情(很明显它不会是一个字符串,因为这没有意义,但只是背后的想法):
quickSort(arr, "yards_per_game"); // sorts by yards per game
quickSort(arr, "total_points"); // sorts by total points
quickSort(team_stats* arr, string field) {
while (i <= j) {
while (arr[i].field < pivot)
etc. etc.
而不是这样做:
if (field == "yards_per_game")
quickSortYards(arr);
else if (field == "total_points")
quickSortPoints(arr);
quickSortYards(team_stats* arr) {
while (i <= j) {
while (arr[i].yards_per_game < pivot)
etc. etc.
quickSortPoints(team_stats* arr) {
while (i <= j) {
while (arr[i].total_points < pivot)
etc. etc.
因为后者要求我必须编写38个不同的函数,仅用于使用一种算法进行排序,我觉得这只是一团糟
谢谢
答案 0 :(得分:6)
如果您的所有数据字段都具有相同的类型,则可以使用纯pointers-to-members并且不使用模板来实现。
但是,看起来您对不同的字段有不同的类型。在这种情况下,模板是最简单的方法。例如,您可以使用类似这样的内容
template <typename T, typename M> void sort_by_field(T a[], size_t n, const M T::*p)
{
std::sort(a, a + n, [p](const T &l, const T &r) { return l.*p < r.*p; });
}
struct S
{
int a;
float b;
};
int main()
{
S s[100] = { ... };
sort_by_field(s, 100, &S::a);
sort_by_field(s, 100, &S::b);
}
很容易更新上面的sort_by_field
函数来接受自定义比较器,而不是lambda中的硬编码<
比较。
在sort_by_field
的上述版本中,我将指向成员的p
指向正常的运行时函数参数。也可以使它成为编译时模板参数。这只是在代码的运行时参数化(更慢,但代码膨胀更少)和编译时参数化(更快,但更多代码膨胀)之间找到适当平衡的问题。
也可以完全不使用模板,使用纯运行时参数化,通过使用字节偏移替换指向成员的指针并使用qsort
样式的比较器回调来实现它。但是,这将成为一种更具参与性和最具攻击性的C风格解决方案。
答案 1 :(得分:1)
执行此操作的常规方法是使用谓词函数检查两个对象,并返回true / false,无论左侧对象是否小于右侧。在现代C ++中,您可以使用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);
你的quickSort功能会有这样的指纹:
void quickSort(team_stats* arr, size_t numTeams, std::function<bool(const team_stats&, const team_stats&)> predicate) {
...
}
或者您可以使用using
语句使其更具可读性:
using QuickSortPred = std::function<bool(const team_stats&, const team_stats&)>;
void quickSort(team_stats* arr, size_t numTeams, QuickSortPred predicate) {
您目前正在进行比较left < right
或right > left
,您将替换为
if (predicate(left, right))
(如果您进行了>
次比较,只需将其切换为<
,然后映射到谓词)
#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;
}
如果我们要在现代C ++中正确地完成它,我们可能会使用除平面数组之外的容器来处理我们的可排序对象,例如向量。如果你的练习是开发一个快速排序例程,你需要用你自己的代码替换'std :: sort':)
#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;
}
如果您没有尝试编写自己的快速排序练习,可以删除所有快速排序的内容并将其归结为
#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;
}
答案 2 :(得分:0)
你可以使用指向成员的指针映射并使用指针调用变量,这可能会给你一个提示
// typedef for the pointer-to-member
typedef int X::*ptr_attr;
// Declare the map of pointers to members
map<string,ptr_attr> mattr;
// Add pointers to individual members one by one:
mattr["xx"] = &X::xx;
mattr["yy"] = &X::yy;
// Now that you have an instance of x...
X x;
// you can access its members by pointers using the syntax below:
x.*mattr["xx"] = A["aa"];