Dragon:第一期开发记录

本文记录了作者一周内学习C++ STL模板的过程,包括线性表头文件模板类定义、模板继承、ostream对象传递等问题的探讨及解决方案,以及排序、组合、递归等算法的实现心得。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

花了一个星期准备构思,结果感觉还是回到原来的设想上,不过当然也收获了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)。

 

接下来就按这个思想再重新写一遍吧。


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值