摘要: 类型定义 在多叉树中,叶子遍历迭代器有只读、读写、只读反转、读写反转4种,在mtree容器中的定义如下:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->1 &nb...
阅读全文
posted @
2011-08-25 10:35 春秋十二月 阅读(2225) |
评论 (0) |
编辑 收藏
摘要: 类型定义 在多叉树中,兄弟遍历迭代器有只读、读写、只读反转、读写反转4种,在mtree容器中的定义如下:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->1  ...
阅读全文
posted @
2011-08-20 21:06 春秋十二月 阅读(1753) |
评论 (0) |
编辑 收藏
方法1:使用find和xargs命令
find dir | xargs grep str,dir是指某个目录
find file | xargs grep str,file是指某个文件
注意:这种方法,会递归搜索子目录
方法2:直接使用grep命令
grep str dir/*,dir是指某个目录,但不递归搜索其子目录
grep -r str dir/*,使用-r选项,递归搜索其子目录
grep str file,file是指某个文件
方法3:综合以上两种,写一个shell脚本,代码如下
1
#! /bin/bash
2
# findstr.sh
3
4
if [ $# -lt "2" ]; then
5
echo "Usage: `basename $0` path name [option]"
6
exit 1
7
fi
8
9
path=$1
10
name=$2
11
shift
12
shift
13
14
for option in "$@"
15
do
16
case $option in
17
-r) dir_op="-r"
18
;;
19
-i) lu_op="-i"
20
;;
21
*) if [ -n "$option" ]; then
22
echo "invalid option"
23
exit 1
24
fi
25
;;
26
esac
27
done
28
29
grep_str_of_file()
30
{
31
file=$1
32
str=$2
33
out=$(grep -n $lu_op "$str" "$file")
34
if [ -n "$out" -a "$file" != "$0" ]; then
35
echo "$file: $out"
36
fi
37
}
38
39
find_str()
40
{
41
if [ -d "$1" ]; then
42
for file in $1/*
43
do
44
if [ "$dir_op" = "-r" -a -d "$file" ]; then
45
find_str $file $2
46
elif [ -f "$file" ]; then
47
grep_str_of_file $file $2
48
fi
49
done
50
elif [ -f "$1" ]; then
51
grep_str_of_file $1 $2
52
fi
53
}
54
55
find_str $path $name
这样一来,不管$1参数是目录还是文件,都能处理,使用示例如下:
findstr /usr/include main 不递归搜索子目录,大小写敏感
findstr /usr/include main -i 不递归搜索子目录,忽略大小写
findstr /usr/include main -r 递归搜索子目录,大小写敏感
findstr /usr/include main -r -i 递归搜索子目录,忽略大小写
findstr main.cpp main 在文件中搜索,大小写敏感
findstr main.cpp main -i 在文件中搜索,忽略大小写
上面所述的示例中,str不限于特定的文本,可以是带正则表达式的匹配模式。而第3种方法,也可以用sed替换grep来显示文本行,在此基础上能作更多的处理,比如格式化显示、统计匹配的文本个数、搜索策略等,在此就不详究了。
posted @
2011-08-20 19:46 春秋十二月 阅读(2505) |
评论 (0) |
编辑 收藏
摘要: 类型定义 在多叉树中,后序遍历迭代器有只读、读写、只读反转、读写反转4种,在mtree容器中的定义如下:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->1 &nb...
阅读全文
posted @
2011-08-15 12:51 春秋十二月 阅读(1949) |
评论 (2) |
编辑 收藏
摘要: 类型定义
在多叉树中,前序遍历迭代器有只读、读写、只读反转、读写反转4种,在mtree容器中的定义如下:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->1 &n...
阅读全文
posted @
2011-08-14 13:30 春秋十二月 阅读(2804) |
评论 (0) |
编辑 收藏
摘要: 迭代器的分类与框架
迭代器是一种设计模式,用来访问容器对象的内容而无须暴露容器的内部实现,而多叉树是一种具有递归性质的复合对象,因此它的迭代器是一种复合迭代器,且存在多种遍历顺序和策略,如前序、后序、广度、叶子、兄弟等,为了支持实现这种复合迭代器,就需要设计不同的迭代器类,由于迭代器封装了对多叉树的访问,而这种访问又可分为只读和读写两类,它们在stl中的实现就...
阅读全文
posted @
2011-07-31 07:55 春秋十二月 阅读(2755) |
评论 (0) |
编辑 收藏
摘要: 在面向对象开发时,对实际问题分析进而抽象出一种类型,往往会考虑到2个方面:1)类型的内部成员和方法的定义描述 2)类型的多实例存取操作。其中第1点是类型本身数据结构的设计,第2点是类型容器数据结构的选择设计。在stl中,容器有序列式和关联式两种,前者代表有vector,list,deque等;后者代表有set,multiset,map,multimap等,对于一...
阅读全文
posted @
2011-07-16 12:23 春秋十二月 阅读(1922) |
评论 (0) |
编辑 收藏
摘要: 需求分析
在数据结构中,树有两种存储方式,一种是链式存储,另一种是顺序存储。前者就是使用指针来记录树结点间的关系,在新增结点或删除结点时,只需改变与父结点或兄弟结点的指针值即可,实现较为简单;后者就是使用数组来存储,可以用相对偏移量来记录树结点间的关系,在新增结点或删除结点时,则不仅是改变与父结点或兄弟结点的相对偏移量,还需要改变其它结点的相对偏移量,实现较为...
阅读全文
posted @
2011-07-13 15:10 春秋十二月 阅读(4690) |
评论 (9) |
编辑 收藏
继承情景
我们知道一个空的类,也就是其内部没有非静态数据成员,没有虚指针(包括指向虚函数表和虚基类子对象的指针),它的大小通常为1,当然在某些对齐要求严格系统上可能是另一个数(通常是4),如果空类被继承,那么派生类的大小会怎么样呢?一个支持C++标准和EBO的编译器对此会进行空基类的优化,也就是不给空的基类子对象分配空间,换句话说,空基类子对象的地址和其派生类实例的地址是相同的。从编译器实现的角度来看,需要考虑继承时的不同情况,下图中P表示父类,C表示子类,圆形表示空类,矩形表示非空类。单继承EBO情况如下图所示
EBO-1反映的是空类派生自空基类,EBO-2反映的是非空类派生自空基类,EBO-3、EBO-4反映的是在继承链中,对空基类的优化能不能传递到后代中。多继承EBO如下图所示
EBO-5反映的是空类派生自两个空基类,EBO-6反映的是非空类派生自两个空基类,EBO-6反映的是空类派生自一个非空基类和一个空基类,EBO-7反映的是非空类派生自一个非空基类和一个空基类。以上8种情况,不论是单继承还是多继承,一个完全支持EBO的编译器就应该能把空基类部分都优化掉。
优化应用
由于空基类优化技术节省了对象不必要的空间,提高了运行效率,因此成为某些强大技术的基石,基于类型定义类如stl中的binary_function、unary_function、iterator、iterator_traits的实现复用;基于策略类如内存管理、多线程安全同步的实现复用。当某个类存在空类类型的数据成员时,也可考虑借助EBO优化对象布局,例如下
1
template<typename T1,typename T2>
2
class EBO
3

{
4
private:
5
T1 m_t1;
6
T2 m_t2;
7
};
当T1和T2为空类时,可以改进如下
1
template<typename T1,typename T2>
2
class EBO : T1, T2
3

{
4
};
更进一步,如果T1或T2为非类类型,如基本内建类型、函数指针等;或T1和T2类型相同时,则直接继承它们会导致编译错误,怎么办呢?这时可以添加一个中间层来解决,代码如下
1
template<typename T1,typename T2,bool isSame,bool isFirstEmpty,bool isSecondEmpty>
2
class EBO_IMPL;
3
4
template<typename T1,typename T2>
5
class EBO_IMPL<T1,T2,false,false,false>
6

{
7
T1 m_t1;
8
T2 m_t2;
9
};
10
11
template<typename T1,typename T2>
12
class EBO_IMPL<T1,T2,false,true,true> : T1,T2
13

{
14
};
15
16
template<typename T1,typename T2>
17
class EBO_IMPL<T1,T2,false,true,false> : T1
18

{
19
T2 m_t2;
20
};
21
22
template<typename T1,typename T2>
23
class EBO_IMPL<T1,T2,false,false,true> : T2
24

{
25
T1 m_t1;
26
};
27
28
template<typename T1,typename T2>
29
class EBO_IMPL<T1,T2,true,false,false>
30

{
31
T1 m_t1;
32
T2 m_t2;
33
};
34
35
template<typename T1,typename T2>
36
class EBO_IMPL<T1,T2,true,true,true> : T1
37

{
38
T2 m_t2;
39
};
40
41
template<typename T1,typename T2>
42
class EBO : EBO_IMPL<T1,T2,boost::is_same<T1,T2>::value,boost::is_empty<T1>::value,boost::is_empty<T2>::value>
43

{
44
};
为了简便,直接使用了boost中的is_same,is_empty元函数来判断类型的属性,实际上boost中已经实现了EBO的选择运用工具即compressed_pair类模板,研究其源码可发现,该工具充分考虑到了T1和T2实际类型的各种情况,is_empty的判断是运用sizeof来比较类型大小确定的。替换compressed_pair后,代码如下
1
template<typename T1,typename T2>
2
class EBO: boost::compressed_pair<T1,T2>
3

{
4
};
posted @
2011-07-10 12:58 春秋十二月 阅读(2693) |
评论 (0) |
编辑 收藏
著名的千千静听音乐播放器,其界面简洁优雅、美观大方,特别是它那种几个窗口像磁石般相互吸引,当拖动主窗口时,粘在一起的其它窗口会跟随着一起移动,当拖动其它窗口时,又能脱离不粘在一起,这种窗口效果让用户操作方便,省心省力。为描述方便,本文称这种效果为多窗口的组合分离,它的主要特点是仅用鼠标任意移动窗口,就可组合或分离,当组合在一起时,移动某窗口(如主窗口,暂称为老板窗口)能整体移动,移动其口窗口(非老板窗口,暂称为工人窗口)又能将自己脱离出来。近来由于工作需要实现了类似于此的窗口效果,经过几天的测试,终于稳定。在开发过程中,考虑了以下几个问题:
(1) 组合分离的条件如何决定判断。
(2) 当窗口大小改变时,包括最小化,最大化,缩放窗口等,如何保证不影响组合分离,能正常整体移动。
(3) 窗口个数是可变的,当新建或销毁窗口时,如何保证不影响组合分离,能正常整体移动(千千静听窗口个数是有限的,而且可能只是隐藏窗口)。
(4) 采用什么数据结构较好,如何维护任意两个窗口间的距离关系(相交或相切视为组合,相离视为分离)。
(5) 当拖动老板窗口时,如何拖动与其组合的所有窗口,关键是如何得到所有与其组合的窗口列表。
(6) 如何针对这种效果设计一个通用的组件类,只需调用几个方法便可搞定。
针对以上问题,主要思路是视屏幕上任意多个窗口为顶点,以其窗口矩形中心点来看待这个窗口,如果任意两个窗口间关系为组合,则视这两个顶点间是相通的,即两个顶点存在边。如果为分离,则视两顶点间是不通的,即两顶点不存边。因此可以用无向图来存储窗口和关系,为简单起见,我用的是邻接矩阵,问题(4)得以解决。既然用邻接矩阵来存储,那么如何得到所有与老板窗口相关的组合窗口呢?由于实际多个窗口在移动过程中,会改变其组合分离关系,这就会得到多个无向图的连通分量,而我们需要的是包含老板窗口的那一个连通分量,因此可以用DFS深度搜索遍历这个无向图连通分量,起始顶点是老板窗口,遍历完后就会得所有与其组合的窗口列表,问题(5)得以解决。现在讨论问题(1),这里有个细节问题就是组合分离的条件判断有两种情况,一是当移动窗口时的条件,称为条件1,因为实际向一个窗口A移入另一个窗口B时,要达到还没有接近窗口A时便一下子靠近A就像被A吸引的效果,当移出B时还没完全移到A窗口外面时便一下子远离就像被A排斥的效果。二是当大小改变时的条件,称为条件2,这个不同于条件1,因为它不需要那种吸引排斥的效果,也没必要,这个条件2就是简单的判断A和B矩形是否相交,API函数IntersectRect即可完成这一判断。条件1的判断如下图所示:
在B向A移入过程中,当B的中心点在矩形left,top,right,bottom范围内,可认为是发生组合,实现吸引效果;当在center矩形内,认为是已经组合了;同理,B向A移出过程中,当B的中心点在矩形left,top,right,bottom范围内,可认为是发生分离,实现排斥效果。当都不在left,top,right,bottom,center矩形范围时,认为是已经分离了。至此,问题(1)得到解决。当窗口大小改变时,需要更新邻接矩阵反映窗口间关系的变化,而后更新组合窗口列表,组合窗口列表的计算依赖于邻接矩阵,运用DFS算法来更新,这在WM_SIZE消息事件处理内完成,问题(2)得到解决。当新建窗口时,需要向无向图中增加(窗口)顶点,扩充邻接矩阵以备存储与其它窗口的关系;当销毁窗口时,需要从无向图中删除对应的顶点,而后从邻接矩阵中删除对应的关系,问题(3)得到解决。
上述问题(1)--(5)都已分析并得到解决,总的来说,就是以数据结构中无向图的观点和算法来建模解决这些问题的,特别是运用到了DFS搜索算法来重建已组合的所有窗口列表,只有这样,在移动老板窗口过程中,才能保证其它窗口跟随着一起移动。接下来就是最后一个问题,也就是怎么封装设计组件类,以达到方便应用的目的,综上所述,设计接口方法与以下窗口4种消息相关:
1) 创建窗口发生的消息,如WM_CREATE,WM_INITDIALOG等。
2) 关闭或销毁窗口发生的消息,如WM_CLOSE,WM_DESTROY等。
3) 窗口大小改变后消息,WM_SIZE。
4) 窗口移动中消息,WM_MOVING。
另外提供一个设置获取老板窗口的方法,在应用程序中,只需在窗口4种消息处理内调用以上对应4个方法即可实现多窗口组合分离的效果,注意该类没有考虑多线程,因此是非安全的,适用于多窗口属于同一线程内的情况。类声明如下
1
class CWndMagnet
2

{
3
public:
4
CWndMagnet();
5
virtual ~CWndMagnet();
6
7
public:
8
void SetLeadWindow(HWND hWnd)
{ m_hLead = hWnd; }
9
HWND GetLeadWindow() const
{ return m_hLead; }
10
11
void AddMagnetWnd(HWND hWnd);
12
void RemoveMagnetWnd(HWND hWnd);
13
void OnLButtonDown(HWND hWnd);
14
void OnNcLButtonDown(HWND hWnd);
15
void OnMoving(HWND hWnd, LPRECT lpRect);
16
void OnSize(HWND hWnd, UINT uType);
17
18
protected:
19
void MoveLeadWndSet(HWND hWnd, LPCRECT lpRect);
20
void UpdateLeadWndSet(HWND hWnd, LPCRECT lpRect = 0);
21
void DeleteMagWnd(HWND hWnd);
22
void Add2DMatrix();
23
void Delete2DMatrix(HWND hWnd);
24
void Update2DMatrix(HWND hWnd, LPRECT lpRect = 0);
25
26
private:
27
int GetFirstNeighbor(int v);
28
int GetNextNeighbor(int v, int w);
29
void DFS(int v, std::vector<bool>& vecVisited, std::vector<int>& vecNeighbor);
30
31
private:
32
static const int s_c_iThreshold = 10; /**////< 偏移阀值
33
HWND m_hLead; ///< 老板窗口
34
std::map<HWND,POINT> m_map_leadWnd; ///< 粘合窗口列表
35
std::map<HWND,int> m_map_magWnd; ///< 需要组合分离的窗口列表
36
std::vector<std::vector<bool> > m_vec_2DMatrix; ///< 表示任意两个窗口间相交或相切的邻接矩阵
37
38
};
posted @
2011-07-04 11:14 春秋十二月 阅读(2880) |
评论 (0) |
编辑 收藏