使用基于此标志的条件语句是否比添加更多代码行更有效?
Is using a conditional statement based on this flag more efficient than adding more lines of code?
我有一个排序函数,它接受一个布尔参数 desc
(降序),如果 true
& algo
是一个枚举 class 选择算法(此处代码的子集用于 algo::BUBBLE
(冒泡排序))
使用这个内联条件语句 (if (!desc ? A[j] > A[j + 1] : A[j] < A[j + 1])
),我可以避免重写反向排序的整个代码,因为它会根据 desc
标志评估适当的条件。但我想知道这是否会产生不必要的开销,因为它会重复检查标志 [(n-1)*(1+2+...+n-1) 次 ]。对于较大的数据元素,这种开销是否会显着增加?更多代码还是更多开销?
void Array<T>::sort(bool desc = false, algo a)
{
if (algo == algo::BUBBLE)
{
bool wasSwapped = true;
for (size_t i = 0; i < size - 1 && wasSwapped; i++)
{
switched = false;
for (size_t j = 0; j < size - i - 1; j++)
{
if (!desc ? A[j] > A[j + 1] : A[j] < A[j + 1])
{
wasSwapped = true;
swap(A[j], A[j + 1]);
}
}
}
}
}
A
和 size
是私有数据成员(分别是数组指针和大小)。
为了代码清晰,最好将其设为非成员函数模板并将其传递给比较仿函数。确保将函数放在应用程序的命名空间中,以免与 std
命名空间中的同名函数混淆。
假设 Array<T>::A
可以访问,
namespace MyApp
{
template <typename T, typename Compare = std::less<T>>
void sort(Array<T>& array, algo a, Compare compare = Compare());
{
if (a == algo::BUBBLE)
{
bool wasSwapped = true;
for (size_t i = 0; i < size - 1 && wasSwapped; i++)
{
switched = false;
for (size_t j = 0; j < size - i - 1; j++)
{
if (!compare(array.A[j], array.A[j + 1]))
{
wasSwapped = true;
swap(array.A[j], array.A[j + 1]);
}
}
}
}
}
}
现在您可以使用:
Array<int> a = { ... };
MyApp::sort(a, algo::BUBBLE); // std::less<int> is the default functor.
MyApp::sort(a, algo::BUBBLE, std::greater<int>()); // Explicit compare functor.
如果您真的担心这个额外的检查,您可以将实现函数创建为一个模板,其中比较器作为模板参数提供(类似于 std::sort
)。
您将从主函数调用实现函数,根据布尔标志,将大于或小于作为比较器。
但我想知道这是否会产生不必要的开销,因为它会重复检查标志 [(n-1)*(1+2+...+n-1) 次
不,不会。编译器查看每个变量的写入和读取位置。它会相应地调整。
而且,在任何情况下,在您的示例中,读写数组都会限制性能。随着冒泡排序的进行,您将进行比需要更多的读写操作。在大型数组(百万条目)上将其与原代码进行比较,并进行硬编码降序搜索。赌的是时间相同。
我有一个排序函数,它接受一个布尔参数 desc
(降序),如果 true
& algo
是一个枚举 class 选择算法(此处代码的子集用于 algo::BUBBLE
(冒泡排序))
使用这个内联条件语句 (if (!desc ? A[j] > A[j + 1] : A[j] < A[j + 1])
),我可以避免重写反向排序的整个代码,因为它会根据 desc
标志评估适当的条件。但我想知道这是否会产生不必要的开销,因为它会重复检查标志 [(n-1)*(1+2+...+n-1) 次 ]。对于较大的数据元素,这种开销是否会显着增加?更多代码还是更多开销?
void Array<T>::sort(bool desc = false, algo a)
{
if (algo == algo::BUBBLE)
{
bool wasSwapped = true;
for (size_t i = 0; i < size - 1 && wasSwapped; i++)
{
switched = false;
for (size_t j = 0; j < size - i - 1; j++)
{
if (!desc ? A[j] > A[j + 1] : A[j] < A[j + 1])
{
wasSwapped = true;
swap(A[j], A[j + 1]);
}
}
}
}
}
A
和 size
是私有数据成员(分别是数组指针和大小)。
为了代码清晰,最好将其设为非成员函数模板并将其传递给比较仿函数。确保将函数放在应用程序的命名空间中,以免与 std
命名空间中的同名函数混淆。
假设 Array<T>::A
可以访问,
namespace MyApp
{
template <typename T, typename Compare = std::less<T>>
void sort(Array<T>& array, algo a, Compare compare = Compare());
{
if (a == algo::BUBBLE)
{
bool wasSwapped = true;
for (size_t i = 0; i < size - 1 && wasSwapped; i++)
{
switched = false;
for (size_t j = 0; j < size - i - 1; j++)
{
if (!compare(array.A[j], array.A[j + 1]))
{
wasSwapped = true;
swap(array.A[j], array.A[j + 1]);
}
}
}
}
}
}
现在您可以使用:
Array<int> a = { ... };
MyApp::sort(a, algo::BUBBLE); // std::less<int> is the default functor.
MyApp::sort(a, algo::BUBBLE, std::greater<int>()); // Explicit compare functor.
如果您真的担心这个额外的检查,您可以将实现函数创建为一个模板,其中比较器作为模板参数提供(类似于 std::sort
)。
您将从主函数调用实现函数,根据布尔标志,将大于或小于作为比较器。
但我想知道这是否会产生不必要的开销,因为它会重复检查标志 [(n-1)*(1+2+...+n-1) 次
不,不会。编译器查看每个变量的写入和读取位置。它会相应地调整。
而且,在任何情况下,在您的示例中,读写数组都会限制性能。随着冒泡排序的进行,您将进行比需要更多的读写操作。在大型数组(百万条目)上将其与原代码进行比较,并进行硬编码降序搜索。赌的是时间相同。