在避免代码重复和冲突名称的同时,如何实现多个版本的同一算法
How can I implement multiple versions of the same algorithm while avoiding code duplication and conflicting names?
我已经在C 中开发了插入排序和QuickSort算法。现在,我打算至少创建QuickSort算法的四个变体。他们将在选择枢轴以及是否将插入排序用于小列表方面有所不同。在Java或C#中,为了避免代码重复和相互冲突的名称,我将在单独的类文件中实现QuickSort算法的每个版本,并使用继承。具体来说,我将创建以下类:
-
QuicksortFixedPivot
-
QuicksortRandomPivot
-
QuicksortFixedPivotInsertion
-使用插入排序对k
元素的子阵列进行分类 -
QuicksortRandomPivotInsertion
但是,从我的理解中,像QuickSort这样的"独立"算法通常不在C 的类中实现。
以下是我对QuickSort的初步实现。
QuickSort.hpp
#pragma once
#include <vector>
namespace algorithms
{
void quicksort(std::vector<int> &list);
void quicksort(std::vector<int> &list, int left, int right);
int partition(std::vector<int> &list, int left, int right);
}
QuickSort.cpp
#include "quicksort.hpp"
namespace alg = algorithms;
void alg::quicksort(std::vector<int> &list)
{
alg::quicksort(list, 0, list.size() - 1);
}
void alg::quicksort(std::vector<int> &list, int left, int right)
{
if (left >= right)
return;
int oldPivot = alg::partition(list, left, right);
alg::quicksort(list, left, oldPivot - 1);
alg::quicksort(list, oldPivot + 1, right);
}
int alg::partition(std::vector<int> &list, int left, int right)
{
int pivot = list[left + (right-left)/2];
while (true)
{
while (list[left] < pivot)
left++;
while (list[right] > pivot)
right--;
if (left >= right)
return left;
std::swap(list[left], list[right]);
}
}
考虑到上述背景,我有两个问题。
首先,对于单个QuickSort实现,我是否适当地使用了标头文件并以一种很好的方式构造了我的代码?例如,算法不在课堂外吗?
其次,在避免代码重复和命名冲突的同时,如何创建本算法的不同版本?例如,我应该使用类或其他语言构造吗?
我将不胜感激的是,如果答案包括最小代码段,阐明了应如何使用任何相关语言构造来实现整齐的代码。
您可以做类似地执行STD的方法。算法的执行策略。它使用标签,可以轻松地使用结构:
#include <iostream>
struct versionA{};
struct versionB{};
int fooA(versionA tag, int param)
{
(void)tag;//Silences "unused parameter" warning
return 2*param;
}
int fooB(versionB tag,int param)
{
(void)tag;
return 5*param;
}
int main()
{
std::cout<<fooA(versionA{},5)<<'n';
std::cout<<fooB(versionB{},5)<<'n';
//Outputs:
//10
//25
}
编译器可以优化这些空的未使用的结构,因此对此没有任何伤害。替代方法是将模板参数为标签类型,并将它们完全专门用于单个版本。但是,这种方法几乎没有缺点 - 泄漏到标头文件的实现,模板功能不能部分专业化,如果算法本身需要模板参数,则效果不佳。与超载混合的模板可能并不总是会导致调用预期功能。
如果函数中的{}
呼叫您打扰您,则可以制作这些结构的全局实例并改为通过它们(通过复制)。
回答您的第一个问题:是的,您正确使用了它们。很小的注释-#pragma once
不是标准的C ,但是所有标准编译器无论如何都支持它。适当的选择是使用包括警卫。
标记的完整示例:
// header file
#include <vector>
namespace algorithms
{
namespace ver
{
struct FixedPivot_tag{};
struct RandomPivot_tag{};
const extern FixedPivot_tag FixedPivot;
const extern RandomPivot_tag RandomPivot;
}
void quicksort(ver::FixedPivot_tag tag, std::vector<int> &list, int left, int right);
void quicksort(ver::RandomPivot_tag tag, std::vector<int> &list, int left, int right);
}
// cpp file
namespace algorithms
{
namespace ver
{
constexpr const FixedPivot_tag FixedPivot{};
constexpr const RandomPivot_tag RandomPivot{};
}
void quicksort(ver::FixedPivot_tag tag, std::vector<int> &list, int left, int right)
{
(void)tag;
//...
}
void quicksort(ver::RandomPivot_tag tag, std::vector<int> &list, int left, int right)
{
(void)tag;
//...
}
}
// usage
int main()
{
std::vector <int> vector{5,4,3,2,1};
using namespace algorithms;
quicksort(ver::FixedPivot,vector,0,4);
quicksort(ver::RandomPivot,vector,0,4);
}
如果您认为可以独立选择的参数可能存在不同的参数(例如pivot
和insertion
),则应考虑enum
S(或更好的enum class
ES)。
您可以将信息作为参数(使用标准if
的运行时调度)或模板参数(使用if constexpr
进行编译时调度)传递信息。代码将如下:
namespace alg {
enum class pivot { first=0; last=1; middle=2};
enum class insertion { off=0; on=1 };
template <pivot p, insertion i>
int partition(std::vector<int> &list, int left, int right)
{
int pivot;
if constexpr (p==pivot::first)
pivot = list[left];
else if constexpr (p==pivot::last)
pivot = list[right];
else // if constexpr (p==pivot::first)
pivot = list[left + (right-left)/2];
while (true)
{
while (list[left] < pivot)
left++;
while (list[right] > pivot)
right--;
if (left >= right)
return left;
std::swap(list[left], list[right]);
}
}
template <pivot p, insertion i>
void quicksort_section( std::vector<int>& list, int begin, int end )
{
if (left >= right)
return;
int oldPivot = partition(list, left, right);
quicksort_section(list, left, oldPivot - 1);
quicksort_section(list, oldPivot + 1, right);
}
template <pivot p, insertion i>
void quicksort(std::vector<int> &list)
{
quicksort_section<p,i>(list, 0, list.size() - 1);
}
} // namespace alg
请注意,模板通常在标题文件中实现。
这解决了您的所有需求。它是可扩展的,并且避免了代码重复,即,您不必单独处理所有n_pivot * n_insertion可能性。
如果您使用旧的C 版本(PRE C 17),则可以删除constexpr
(使用一些宏观技巧),因为任何合理的编译器都会消除发生的死亡代码。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- C++ 多重继承:使用基类 A 的实现实现基类 B 的抽象方法
- 如何自己为我自己的shared_ptr实现实现别名构造函数
- 这个UTF-8实现实现是定义的还是定义良好的
- 我的 PRNG 实现与我尝试复制的实现有何不同?