您的位置:首页 > 编程语言 > C语言/C++

模板之小试牛刀---我有点明白为什么这么多人骂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已经在左树中有了,就不构造右节点)。

用几个图来说明。字体有点怪哈,不好意思。



这个构造法用模板实现有一定难度。用树结构来遍历则意味着需要用多继承,注意在生成右子树时要告诉她当前新的最大的已构造节点。

#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树,留给大家优化的空间已经不多了。改日还是做红黑树吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: