前言
花了一个星期准备构思,结果感觉还是回到原来的设想上,不过当然也收获了STL源码的20%,的确精妙,学不来了,先做吧。
要花点时间将模板和运算符重载的知识点整理总结一下。明晚 后晚 大后晚 争取三晚完成
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.25
time consume: around 1h
完成了线性表头文件的模板类定义,但不包含LinkedList的定义。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.26
有两个问题
1. 待验证
template<class T> class A {}
template<class T> class B:public A<T> {}
有函数func(A<T> a) 问类型为B<T>的实参能够传入这个函数呢?待验证
2. 第二个问题是获取cout
已经验证可以用函数来获取:
void print(std::ostream &o, int d){ o<<d;} 但是注意ostream的形参不能是const
但是如果用类来获取呢?
如class A
{
ostream mo;
A(ostream &o) { mo = o; }
}
报错:
error C2512: 'basic_ostream<char,struct std::char_traits<char> >' : no appropriate default constructor available
这里暂时还没弄清楚是怎么回事。请教各位老师同学了。
最后发泄一下:这里这个博客太烂了。没有及时保存功能,我是重写了3遍呀!!!!!!!!!!!!!!!!!!!!!
哈哈!好了。
明晚继续吧。
------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.27
解决昨晚的问题:
对于cout的问题:
事实上,ostream o = cout 是没问题的,问题存在于在一个模板类的构造函数中,能不能将一个ostream对象传入后赋值给o?
template<typename T>
struct Prdct_Output : public Unary_Function<T,void>
{
std::ostream m_oOutput;
Prdct_Output<T>(std::ostream o)
{
m_oOutput = o;
}
void operator()(T &e) {
m_oOutput<<"<"<<e<<">";
}
};
对于这段源码,编译报错是:
error C2512: 'basic_ostream<char,struct std::char_traits<char> >' : no appropriate default constructor available
还是没能解决。
*这里需要注意的一点是:对一些编译错误提示,深入理解是无意义的,因为很有可能这些奇奇怪怪的报错是由于其他的一些错误引起,而这些错误,编译器是检查不出来的,这就是使用高级编程机制时,编译器的智能化程度没跟上的结果。Maybe?
*另外需要注意的一点是,对于形参表中的const,不是可以随便用的,因为这些涉及到类型转换问题,所以特别是自定义类型传参时,用const很容易就是报错。关于这个方面还需要深入研究。
然而已经基本弄清楚了函数对象的用法,并且对这种遍历的机制有所了解,其实我想写的就是foreach,而其实foreach是一个模板函数~!
另外还领略了一下关于 绑定器, 成员函数适配器,函数指针适配器, 否定器等几种适配器,C++ PL果然是宝典。
然而已经基本弄清楚了函数对象的用法,并且对这种遍历的机制有所了解,其实我想写的就是foreach,而其实foreach是一个模板函数~!
另外还领略了一下关于 绑定器, 成员函数适配器,函数指针适配器, 否定器等几种适配器,C++ PL果然是宝典。、
有点进展了:原来真正的问题出现在:std::ostream m_oOutput;
也就是说必须先弄清楚ostream的声明方法。
目前的理解是ostream o必须在定义的第一时间进行初始化,即ostream o=std::cout; o<<e; 是OK的,但是除此之外都不行。
那么上面的void print(std::ostream &o, int d){ o<<d;}可以 是为什么呢?可能是引用的关系?那些将&去掉,一样是OK的,那就表明对实参o也是在定义的时候就初始化了。
在网上看到这么一句,流是不能被赋值的,待正式确认。
-----------------------------------------------------------------------------------------------------------------------------------------------------------
1.28
今晚就是重新写了一篇几个排序算法。O(n)的都没写。
* 一个问题,抽象类,即里面有虚函数的类是不能实例化的。这个问题出自:
template<typename T>void _merge(LinearList<T> &dest, LinearList<T> src, int _s, int _m, int _t, int &t)
也就是说不能出现LinearList<T> src 解决方法是在函数中进行表的复制。
* 第二个遇到的问题 其实也不是第一次遇到了。经常会有些Access Violation的报错,在ctrl+F5运行时还报错,但是如果F11逐步调试是完全没有问题的,这样实在是太浪费时间。要知道有时逐步调试就要花上10分钟。所以应该要注意:1,clear 2.要培养对迭代式正确性的敏感度
-----------------------------------------------------------------------------------------------------------------------
1.29
今晚写排列和组合 发现这些算法忘得真的很快
(1)组合
首先花了45分钟 包括调试写了组合 感觉比之前写的有进步 代码更简洁 而且思路清晰 不过还是花了许多时间调试
记录两个出错点:
1. _push_1_left方法, 其实思路有很多,比如说可以利用插入排序的思想,很明显,将1都排在前面,但是这样n平方,也可以利用partition的思路:用一个下标记录已经整理过的1的后一位的位置,遇到1则与之调换,这样可以在O(n)时间内完成。
2. 另一个出错点是:while (p=_find_10(tags, n) != -1) 属于运算符结合优先级的问题,这样最后p的结果是1,而不是_find_10函数的返回值。
(2)排列(字典)
终于发现#ifndef的用处了。由于同时:
#include "composition.h"
#include "permutation.h"
结果疯狂报错。
所以注意 每次include一个头文件,先问问,你定义它了吗?
如:
#ifndef _LINEAR_LIST
#include "..//data_structure//basic_data_structure//linear_list//linear_list.h"
#endif
结果组合的字典算法还是很快就写好调好了。不过算法还是完全不是自己的思路,这证明只是机械编码阶段,没有进入思考阶段。
(3)排列(递归)
递归方法也写好了。虽然速度还行,但是很没达到心里的标准。
这次犯的错误完全是算法上的错误,根本对算法没有完全的了解。才会出现这样的错误。
错误:
count++;
//get a result
std::cout<<"Permutation: ";
for (int i=0;i<list.length();i++)
std::cout<< "<" << list[i] << ">";
std::cout<<"/n";
if (_s==list.length()-1)
{
return ;
}
也就是没有意识到 输出结果的条件是_s到达序列尾部。
------------------------------------------------------------------------------------------------------------------------
1.30
今晚准备写两个算法,一个是随机化的顺序统计,期望时间On, 另一个是同样的算法,但是时间是 Ω(n)
今晚进展不是很顺利,脑袋有点发胀。第一个算法写了一个半小时,而问题居然出现在partition上面,证明对一些基础算法还是很生疏呀。。。。
对一个随机选择pivot的partition算法,正确的步骤应该是:
先将这个pivot跟列表头部元素交换,然后再利用:
int p = _s;
//start the loop from _s+1
for (int i=_s+1; i<=_t; i++ )
if (list[i] < pivot )
{
p++;
if (i!=p) util::Swap(list[i],list[p]);
}
util::Swap(list[p],list[_s]);
利 用一个循环,在[_s+1,_t]的区间上作分区,最后交换保存在表头的pivot和list[p]。而我居然将最后一句写成list[p] = pivot。。。。。太错了!更重要的是,在前天写的sort里面,quicksort的partition也是有错误的。。。。。。但是我居然没有 test出来,证明test也是太疏忽了。。。。还好发现得早。。。。
-----------------------------------------------------------------------------------------------------------------------------------
1.31
今天回家。晚上9点开始写程序。虽然感觉今晚思维还是比较清晰,但是还是不熟练 不熟练 不熟练。。。。。
今晚写的是算法导论中最坏情况下线性时间的选择算法Select。这个算法比较复杂,但是我昨晚已经作了一定思考,觉得应该可以用传入间距来实现,第二步中,对每组的中位数进行递归Select。
结果写了将近一个小时后,发现纯粹利用间距 是无法完成这样的工作的 因为有可能 最后一组是不足5个元素,于是其中位数就不符合 前一中位数下标+interval*5的规律。
其 实之前有一个想法是,直接获取每组的中位数,产生一个新的线性表对象,而不是直接在原来的线性表上做查找,但是觉得这样会影响速度,就先放弃了。其实目前 来看,只能是这样做了。而由于产生一个新的对象,花的时间是O(n) 应该有一个更紧致的上界,但是就不分析了, 这样也是不会影响这个算法的总体速度的,还是O(n)。
接下来就按这个思想再重新写一遍吧。