模板之小试牛刀---我有点明白为什么这么多人骂c++了(爱恨也交加的c++,让我不得不继续说下去)
2010-10-16 11:06
423 查看
昨天晚上有点兴奋,睡不着,哪知道又来惦记起了本主题,突然又想多说几句。
原来的代码中有这个遍历自然数,执行单元测试的类:
template< size_t N >
struct test_nature:public test_nature< N-1 >
{
test_nature():test_nature< N-1 >(){test(N);}
};
template<>
struct test_nature< 1 >
{
test_nature(){test(1);}
};
就模板的嵌套深度而言,深度达到N.多一点编译器就会报错了,现在我们就来优化它。
(哥现在并没有写代码,正边写边想哦)
首先的思路是在构造函数中多执行一次测试用例,深度立即减少到N/2.
template< size_t N >
struct test_nature:public test_nature< N-2 >
{
test_nature():test_nature< N-2 >(){test(N);test(N-1);}
};
再对N=2,N=1进行特化就可以了。复杂度可谓线性下降。
不过继承关系图是一个树形结构图,我们还可以把复杂度设法转化为对数复杂度。
思路:继承关系图中的树我们需要进行遍历整棵树,我们设法构造一棵树。复杂度立即下降到log2N。
算法一:设根节点为N,执行先序构造和后序遍历(先构造出继承关系,再让构造函数去遍历。注意这里的“构造”和“遍历”2词的含义)。然后如何构造子树呢?这是一个问题,规定策略如下:左节点是根节点左节点和当前最大的已构造节点的平均数,右节点是N-1(如果N-1已经在左树中有了,就不构造右节点)。
用几个图来说明。字体有点怪哈,不好意思。
这个构造法用模板实现有一定难度。用树结构来遍历则意味着需要用多继承,注意在生成右子树时要告诉她当前新的最大的已构造节点。
上面这个是个不支持vc6的版本,编译速度大幅度提高,codepad.org在线编译器可以支持300的输出,大约超过300后不再报嵌套过深而是编译时间超时错误。
因为有不定多个空节点,我们不得不使用虚继承来重复继承空节点。其实不用继承,用组合是完全可以的.从数据结构讲到设计模式了,呵呵.
有机会我再来生成一棵满树,一棵avl树,一棵红黑树,呵呵.今天说到这里了.
哦对了,今天生成的树就是avl树,我最喜欢的一种树。我甚至在毫无意识的情况下就构造出了它,直到我输出结果我才看见我其实构造的是avl树,留给大家优化的空间已经不多了。改日还是做红黑树吧。
原来的代码中有这个遍历自然数,执行单元测试的类:
template< size_t N >
struct test_nature:public test_nature< N-1 >
{
test_nature():test_nature< N-1 >(){test(N);}
};
template<>
struct test_nature< 1 >
{
test_nature(){test(1);}
};
就模板的嵌套深度而言,深度达到N.多一点编译器就会报错了,现在我们就来优化它。
(哥现在并没有写代码,正边写边想哦)
首先的思路是在构造函数中多执行一次测试用例,深度立即减少到N/2.
template< size_t N >
struct test_nature:public test_nature< N-2 >
{
test_nature():test_nature< N-2 >(){test(N);test(N-1);}
};
再对N=2,N=1进行特化就可以了。复杂度可谓线性下降。
不过继承关系图是一个树形结构图,我们还可以把复杂度设法转化为对数复杂度。
思路:继承关系图中的树我们需要进行遍历整棵树,我们设法构造一棵树。复杂度立即下降到log2N。
算法一:设根节点为N,执行先序构造和后序遍历(先构造出继承关系,再让构造函数去遍历。注意这里的“构造”和“遍历”2词的含义)。然后如何构造子树呢?这是一个问题,规定策略如下:左节点是根节点左节点和当前最大的已构造节点的平均数,右节点是N-1(如果N-1已经在左树中有了,就不构造右节点)。
用几个图来说明。字体有点怪哈,不好意思。
这个构造法用模板实现有一定难度。用树结构来遍历则意味着需要用多继承,注意在生成右子树时要告诉她当前新的最大的已构造节点。
#define test(x) cout<<x<<endl /*Test from 1 to N*/ template< size_t N, size_t M, bool STOP > struct test_nature_impl : public test_nature_impl< N <= M + 1 ? N : (M + N)/2, M, N <= M + 1 > , public test_nature_impl< N <= M + 2 ? -N : N - 1, (M + N)/2, N <= M + 2 > { test_nature_impl(){test(N);} }; template< bool STOP > //begin node struct test_nature_impl< 0, 0, STOP >{}; template<size_t N, size_t M> //empty node struct test_nature_impl< N, M, true >{}; template<size_t N> struct test_nature :public test_nature_impl<N,0,false> { }; int main() { test_nature<200> x; // test(2); return 0; }
上面这个是个不支持vc6的版本,编译速度大幅度提高,codepad.org在线编译器可以支持300的输出,大约超过300后不再报嵌套过深而是编译时间超时错误。
首先定一个空节点标记static const size_t stop_tag = size_t (-1);
支持vc6的版本:#define LEFT_NODE (1u) #define RIGHT_NODE (2u) #define ROOT_NODE (3u) template< size_t N, size_t M, size_t SIDE > struct test_nature_impl : public virtual test_nature_impl< N <= M + 1 ? stop_tag : (M + N)/2, N <= M + 1 ? stop_tag : M, LEFT_NODE > , public virtual test_nature_impl< N <= M + 2 ? stop_tag : N - 1, N <= M + 2 ? stop_tag : (M + N)/2, RIGHT_NODE > { test_nature_impl(){test(N);} }; template<> //empty left node struct test_nature_impl< stop_tag, stop_tag, LEFT_NODE >{}; template<> //empty right node struct test_nature_impl< stop_tag, stop_tag, RIGHT_NODE >{}; template<size_t N> struct test_nature :public test_nature_impl< N, 0, ROOT_NODE >{}; int main() { test_nature<298> x; cout<<sizeof(x)<<endl; //1196!!·! return 0; }
因为有不定多个空节点,我们不得不使用虚继承来重复继承空节点。其实不用继承,用组合是完全可以的.从数据结构讲到设计模式了,呵呵.
#define LEFT_NODE (1u) #define RIGHT_NODE (2u) #define ROOT_NODE (3u) template< size_t N, size_t M, size_t SIDE > struct test_nature_impl { test_nature_impl< N <= M + 1 ? stop_tag : (M + N)/2, N <= M + 1 ? stop_tag : M, LEFT_NODE > member1; test_nature_impl< N <= M + 2 ? stop_tag : N - 1, N <= M + 2 ? stop_tag : (M + N)/2, RIGHT_NODE > member2; test_nature_impl(){test(N);} }; template<> //empty left node struct test_nature_impl< stop_tag, stop_tag, LEFT_NODE >{}; template<> //empty right node struct test_nature_impl< stop_tag, stop_tag, RIGHT_NODE >{}; template<size_t N> struct test_nature :public test_nature_impl< N, 0, ROOT_NODE >{}; int main() { test_nature<298> x; cout<<sizeof(x)<<endl; return 0; }
有机会我再来生成一棵满树,一棵avl树,一棵红黑树,呵呵.今天说到这里了.
哦对了,今天生成的树就是avl树,我最喜欢的一种树。我甚至在毫无意识的情况下就构造出了它,直到我输出结果我才看见我其实构造的是avl树,留给大家优化的空间已经不多了。改日还是做红黑树吧。
相关文章推荐
- 模板之小试牛刀---我有点明白为什么这么多人骂c++了(补,补充一些骂点)
- 模板之小试牛刀---我有点明白为什么这么多人骂c++了(续,c++图灵完备最小集)
- 模板之小试牛刀---我有点明白为什么这么多人骂c++了
- 模板之小试牛刀---我有点明白为什么这么多人骂c++了(终,算法改变世界)
- 为什么还有这么多人用C++写服务端?
- C++ 中为什么模板不支持分离编译?
- 【C++】模板简述(四):模板为什么不支持分离编译?
- 为什么支付宝一定很难做成社交,而又一定会继续做下去?
- C++之类的构造函数,不得不学明白的重点
- 漫谈C++为什么不支持模板虚函数
- C++中模板为什么不支持分离编译
- C++中模板为什么不支持分离编译
- 让你明白为什么中国这么多外汇,却不敢自己花,,,,,很长,仔细看就明白了
- C++模板声明和实现为什么不能分开来写
- c++中为什么不支持模板分离编译
- 【c++】模板为什么不支持分离编译
- C++中模板定义与声明为什么放在同一个文件中
- c++ 模板的一个例子,实参演绎的时候,有个地方没看明白
- C++的模板为什么要在头文件(.h)中实现?
- 解析C++中为什么模板不支持分离编译?