7.学习完数据结构后,考虑怎么有效的进行取出的问题(问题4中提到的)。
以下是截取方式(可能不是最佳的):
1) 查找到’<’位置,‘:’位置,然后用CString类型截取出关键字。关键字取出后有冒号,需要过滤掉。注意Mid()函数的第二个参数是截取的个数。
2) 找到第二个‘:’,用Mid()截取出结点的个数。截断字符串。
3) 考虑使用二重循环来遍历所有。
第一层循环是使用getline()读取每行;第二层循环是依次读取读入的这行的数据。那么就是找’.’,这样可以依次取出编号的长度,以及编号。取出编号长度,以及编号后将其存储到int型的指针中。
知识点:
★String转化成int型函数 _ttoi()。
○最后一个数字即分号前的数,单独处理。
○当当前的结点编号结束后要加入到CArray中
★将string转换为CString,用 c_str()
注意:
写程序时遇到的粗心的问题:
◎使用while()自变量忘记自加
◎变量命名不规范(没有见名知意等),使得测试时花费了很多时间
◎什么时候该加入到CArray中,什么时候该加入到CMap中
◎小于和小于等于问题
◎由于逻辑问题导致每次取的个数都不一样,这个需要细心观察
◎存储的长度问题,考虑是否是需要加一
全部结束后,将CArray加入到CMap中去。
刚刚开始写读函数可能会遇到各种问题,当时在读函数上用了几天的时间。由于逻辑问题,易把问题想的太复杂了。
8.左右匹配问题(重点,时间主要花费在左右匹配上了)
计算它的左右匹配的原因是距离越近,其LCA越低。
注意1:在做左右匹配时一定要保证数据保存的正确性。因此需要测试一下。
左匹配:无论是左匹配还是右匹配都使用折半查找。因为折半查找的时间复杂度是 。
注意2:由于数据集中不同的关键字的结点的编号可能会相同。例如:text 和 tissue 同时含有7.1.2.3505.5383.5394.5407.5411。
这是因为XML中的标签和及其此标签中的文本会被抽象成为不同的关键字。例如:
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
灰色区域的form 与John的编号相同。
在左右匹配时,必须考虑左右匹配不存在的情况。
提示:刚刚开始写左右匹配时可能会想到把左右匹配写成一个函数,但是若发现这个有点困难,何不放一放,暂且将左右匹配写为两个函数,待实现左右匹配时再将左右匹配合为一个函数即可。
9.lca(v1,v2)即找最低共同祖先
最长共同前缀的求法:根据参数(指针类型),循环访问,其数据是否相等,直到不相等,退出循环。从而得到其最长共同前缀。
写这个函数并没有什么难度。
注:在此注意的是长度的边界问题。
10. descedant(v1,v2)//返回子孙结点

子孙结点的判断方法:
观察子孙结点与其祖先结点,祖先结点的编号会完全在子孙结点中出现,这样以来,可以判断其长度即可,长度长的为子孙结点,长度短的是祖先结点。
可能会有此顾虑:参数v1,v2会不会出现不是祖先和子孙的关系?
这种情况是不会存在的,如图所示:
Ben 0.1.1.2.0(与自己写的编码不太一样,但道理一样)与John的左匹配是0.1.1.1.0,右匹配是0.1.2.0.0。在经过lca()后为0.1.1和0.1。结果肯定是祖孙关系。所以descedant(),传递的两个参数是确定的祖孙关系。
11.get_slca()找最小最低共同祖先
本函数就是调用前面的几个函数。
◎初始根结点u = 0,在实现时可以设为1.1。
◎判断u的编码是否是小于x的编码
◎判断u是否是x的祖先,若不是祖先则加入到Result中。
u = x是包含在if(pre(u) < pre(x))中的,伪代码有规定(可能是不成文)缩进对齐的是同一级别。即:
12.写一个调用get_slca()的函数即可。
//////////////////////////////////////////
优化阶段
首先优化的是左右匹配,可以考虑是否是用一个函数来完成左右匹配。
解决方法:使用了两个全局变量left,right,来记录的是左右匹配的位置,而不是使用指针;左匹配做完之后,右匹配的位置也就得到了。这样可以通过位置来获得左右匹配。
1. Lca(),descendant()
优化的方法:
将返回的最低共同祖先/子孙结点的编号改为使用结点类来存储。而结点类中包含了一个指针,指向的是子孙的编号;一个int型的变量存储的是编号的长度。
2. get_slca()
优化方法:
将u的初始化的1.1改为了,第一次的求子孙的结果。减少了一步(将1.1做为祖先)。在此不做进一步的分析。当然u相应的改为了结点类型的,因为我们在加入Result中时使用的是指针型,因此在加入前设置一个指针,将结点存的值复制给指针。
将比较大小单独做一个函数进行判断,判断时所传递的参数是结点类型。且不允许修改其值。即:
int InStream::Compare(const Node &v, const Node &node)//比较大小
3. 在调用get_slca时的优化
因为少量的结点中找量大的结点的左右匹配的时间<将量大的与量小的结点中找左右匹配时所用的时间。所以可以考虑将比较的关键字的个数进行按升序排序。然后再调用get_slca()函数。使用的是直接插入排序。
4. 释放空间
刚刚写完xmark500时仅仅只能跑一遍,这就需要进行释放空间。

Carray->RemoveAll(),仅仅是将Carray中的空间进行释放,而空间中的指针没有被释放掉。因此将指针进行释放,这就需要使用双层循环将Carray进行释放干净。
相应的CMap也需要在析构函数中进行释放空间。
◆注意:释放空间时,需要将之前不再使用的空间进行释放,若下次还会使用,则需申请一个临时的空间暂存,使用完后,将临时空间释放即可。
5.此外还可以将结点类转换为结构体。如下:
struct Node
//class Node
{
//public:
// Node(void);
// ~Node(void);
//public:
int length;//长度
int *p;//指针
};
将cpp文件注释掉即可。