﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-Free mind</title><link>http://www.blogjava.net/morphis/</link><description>Be fresh and eager every morning, and tired and satisfied every night.</description><language>zh-cn</language><lastBuildDate>Sun, 12 Apr 2026 07:52:58 GMT</lastBuildDate><pubDate>Sun, 12 Apr 2026 07:52:58 GMT</pubDate><ttl>60</ttl><item><title>[转] Usefull Sql</title><link>http://www.blogjava.net/morphis/archive/2007/10/30/156998.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Tue, 30 Oct 2007 09:40:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/10/30/156998.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/156998.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/10/30/156998.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/156998.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/156998.html</trackback:ping><description><![CDATA[<p>SQL语句先前写的时候，很容易把一些特殊的用法忘记，我特此整理了一下SQL语句操作。<br />
一、基础<br />
1、说明：创建数据库<br />
CREATE DATABASE database-name <br />
2、说明：删除数据库<br />
drop database dbname<br />
3、说明：备份sql server<br />
--- 创建 备份数据的 device<br />
USE master<br />
EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'<br />
--- 开始 备份<br />
BACKUP DATABASE pubs TO testBack <br />
4、说明：创建新表<br />
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)<br />
根据已有的表创建新表： <br />
A：create table tab_new like tab_old (使用旧表创建新表)<br />
B：create table tab_new as select col1,col2... from tab_old definition only<br />
5、说明：删除新表<br />
drop table tabname <br />
6、说明：增加一个列<br />
Alter table tabname add column col type<br />
注：列增加后将不能删除。DB2中列加上后数据类型也不能改变，唯一能改变的是增加varchar类型的长度。<br />
7、说明：添加主键： Alter table tabname add primary key(col) <br />
说明：删除主键： Alter table tabname drop primary key(col) <br />
8、说明：创建索引：create [unique] index idxname on tabname(col....) <br />
删除索引：drop index idxname<br />
注：索引是不可更改的，想更改必须删除重新建。<br />
9、说明：创建视图：create view viewname as select statement <br />
删除视图：drop view viewname<br />
10、说明：几个简单的基本的sql语句<br />
选择：select * from table1 where 范围<br />
插入：insert into table1(field1,field2) values(value1,value2)<br />
删除：delete from table1 where 范围<br />
更新：update table1 set field1=value1 where 范围<br />
查找：select * from table1 where field1 like '%value1%' ---like的语法很精妙，查资料!<br />
排序：select * from table1 order by field1,field2 [desc]<br />
总数：select count as totalcount from table1<br />
求和：select sum(field1) as sumvalue from table1<br />
平均：select avg(field1) as avgvalue from table1<br />
最大：select max(field1) as maxvalue from table1<br />
最小：select min(field1) as minvalue from table1<br />
11、说明：几个高级查询运算词<br />
A： UNION 运算符 <br />
UNION 运算符通过组合其他两个结果表（例如 TABLE1 和 TABLE2）并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一起使用时（即 UNION ALL），不消除重复行。两种情况下，派生表的每一行不是来自 TABLE1 就是来自 TABLE2。 <br />
B： EXCEPT 运算符 <br />
EXCEPT 运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL)，不消除重复行。 <br />
C： INTERSECT 运算符<br />
INTERSECT 运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL 随 INTERSECT 一起使用时 (INTERSECT ALL)，不消除重复行。 <br />
注：使用运算词的几个查询结果行必须是一致的。 <br />
12、说明：使用外连接 <br />
A、left outer join： <br />
左外连接（左连接）：结果集几包括连接表的匹配行，也包括左连接表的所有行。 <br />
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c<br />
B：right outer join: <br />
右外连接(右连接)：结果集既包括连接表的匹配连接行，也包括右连接表的所有行。 <br />
C：full outer join： <br />
全外连接：不仅包括符号连接表的匹配行，还包括两个连接表中的所有记录。<br />
二、提升<br />
1、说明：复制表(只复制结构,源表名：a 新表名：b) (Access可用)<br />
法一：select * into b from a where 1&lt;&gt;1<br />
法二：select top 0 * into b from a<br />
2、说明：拷贝表(拷贝数据,源表名：a 目标表名：b) (Access可用)<br />
insert into b(a, b, c) select d,e,f from b;<br />
3、说明：跨数据库之间表的拷贝(具体数据使用绝对路径) (Access可用)<br />
insert into b(a, b, c) select d,e,f from b in '具体数据库' where 条件<br />
例子：..from b in '"&amp;Server.MapPath(".")&amp;"\data.mdb" &amp;"' where..<br />
4、说明：子查询(表名1：a 表名2：b)<br />
select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)<br />
5、说明：显示文章、提交人和最后回复时间<br />
select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b<br />
6、说明：外连接查询(表名1：a 表名2：b)<br />
select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c<br />
7、说明：在线视图查询(表名1：a )<br />
select * from (SELECT a,b,c FROM a) T where t.a &gt; 1;<br />
8、说明：between的用法,between限制查询数据范围时包括了边界值,not between不包括<br />
select * from table1 where time between time1 and time2<br />
select a,b,c, from table1 where a not between 数值1 and 数值2<br />
9、说明：in 的使用方法<br />
select * from table1 where a [not] in ('值1','值2','值4','值6')<br />
10、说明：两张关联表，删除主表中已经在副表中没有的信息 <br />
delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )<br />
11、说明：四表联查问题：<br />
select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....<br />
12、说明：日程安排提前五分钟提醒 <br />
SQL: select * from 日程安排 where datediff('minute',f开始时间,getdate())&gt;5<br />
13、说明：一条sql 语句搞定数据库分页<br />
select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段<br />
14、说明：前10条记录<br />
select top 10 * form table1 where 范围<br />
15、说明：选择在每一组b值相同的数据中对应的a最大的记录的所有信息(类似这样的用法可以用于论坛每月排行榜,每月热销产品分析,按科目成绩排名,等等.)<br />
select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)<br />
16、说明：包括所有在 TableA 中但不在 TableB和TableC 中的行并消除所有重复行而派生出一个结果表<br />
(select a from tableA ) except (select a from tableB) except (select a from tableC)<br />
17、说明：随机取出10条数据<br />
select top 10 * from tablename order by newid()<br />
18、说明：随机选择记录<br />
select newid()<br />
19、说明：删除重复记录<br />
Delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)<br />
20、说明：列出数据库里所有的表名<br />
select name from sysobjects where type='U' <br />
21、说明：列出表里的所有的<br />
select name from syscolumns where id=object_id('TableName')<br />
22、说明：列示type、vender、pcs字段，以type字段排列，case可以方便地实现多重选择，类似select 中的case。<br />
select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type<br />
显示结果：<br />
type vender pcs<br />
电脑 A 1<br />
电脑 A 1<br />
光盘 B 2<br />
光盘 A 2<br />
手机 B 3<br />
手机 C 3<br />
23、说明：初始化表table1<br />
TRUNCATE TABLE table1<br />
24、说明：选择从10到15的记录<br />
select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc<br />
三、技巧<br />
1、1=1，1=2的使用，在SQL语句组合时用的较多<br />
"where 1=1" 是表示选择全部&nbsp;&nbsp; "where 1=2"全部不选，<br />
如：<br />
if @strWhere !='' <br />
begin<br />
set @strSQL = 'select count(*) as Total from [' + @tblName + '] where ' + @strWhere <br />
end<br />
else <br />
begin<br />
set @strSQL = 'select count(*) as Total from [' + @tblName + ']' <br />
end <br />
我们可以直接写成<br />
set @strSQL = 'select count(*) as Total from [' + @tblName + '] where 1=1 安定 '+ @strWhere <br />
2、收缩数据库<br />
--重建索引<br />
DBCC REINDEX<br />
DBCC INDEXDEFRAG<br />
--收缩数据和日志<br />
DBCC SHRINKDB<br />
DBCC SHRINKFILE<br />
3、压缩数据库<br />
dbcc shrinkdatabase(dbname)<br />
4、转移数据库给新用户以已存在用户权限<br />
exec sp_change_users_login 'update_one','newname','oldname'<br />
go<br />
5、检查备份集<br />
RESTORE VERIFYONLY from disk='E:\dvbbs.bak'<br />
6、修复数据库<br />
ALTER DATABASE [dvbbs] SET SINGLE_USER<br />
GO<br />
DBCC CHECKDB('dvbbs',repair_allow_data_loss) WITH TABLOCK<br />
GO<br />
ALTER DATABASE [dvbbs] SET MULTI_USER<br />
GO<br />
7、日志清除<br />
SET NOCOUNT ON<br />
DECLARE @LogicalFileName sysname,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @MaxMinutes INT,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @NewSize INT</p>
<p>USE&nbsp;&nbsp;&nbsp;&nbsp; tablename&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- 要操作的数据库名<br />
SELECT&nbsp; @LogicalFileName = 'tablename_log',&nbsp; -- 日志文件名<br />
@MaxMinutes = 10,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- Limit on time allowed to wrap log.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @NewSize = 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- 你想设定的日志文件的大小(M)<br />
-- Setup / initialize<br />
DECLARE @OriginalSize int<br />
SELECT @OriginalSize = size <br />
&nbsp; FROM sysfiles<br />
&nbsp; WHERE name = @LogicalFileName<br />
SELECT 'Original Size of ' + db_name() + ' LOG is ' + <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONVERT(VARCHAR(30),@OriginalSize) + ' 8K pages or ' + <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + 'MB'<br />
&nbsp; FROM sysfiles<br />
&nbsp; WHERE name = @LogicalFileName<br />
CREATE TABLE DummyTrans<br />
&nbsp; (DummyColumn char (8000) not null)</p>
<p>DECLARE @Counter&nbsp;&nbsp; INT,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @StartTime DATETIME,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @TruncLog&nbsp; VARCHAR(255)<br />
SELECT&nbsp; @StartTime = GETDATE(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @TruncLog = 'BACKUP LOG ' + db_name() + ' WITH TRUNCATE_ONLY'<br />
DBCC SHRINKFILE (@LogicalFileName, @NewSize)<br />
EXEC (@TruncLog)<br />
-- Wrap the log if necessary.<br />
WHILE&nbsp;&nbsp;&nbsp;&nbsp; @MaxMinutes &gt; DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND (@OriginalSize * 8 /1024) &gt; @NewSize&nbsp; <br />
&nbsp; BEGIN -- Outer loop.<br />
&nbsp;&nbsp;&nbsp; SELECT @Counter = 0<br />
&nbsp;&nbsp;&nbsp; WHILE&nbsp; ((@Counter &lt; @OriginalSize / 16) AND (@Counter &lt; 50000))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN -- update<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INSERT DummyTrans VALUES ('Fill Log')&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DELETE DummyTrans<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT @Counter = @Counter + 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; EXEC (@TruncLog)&nbsp; <br />
&nbsp; END&nbsp;&nbsp; <br />
SELECT 'Final Size of ' + db_name() + ' LOG is ' +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONVERT(VARCHAR(30),size) + ' 8K pages or ' + <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CONVERT(VARCHAR(30),(size*8/1024)) + 'MB'<br />
&nbsp; FROM sysfiles <br />
&nbsp; WHERE name = @LogicalFileName<br />
DROP TABLE DummyTrans<br />
SET NOCOUNT OFF <br />
8、说明：更改某个表<br />
exec sp_changeobjectowner 'tablename','dbo'<br />
9、存储更改全部表<br />
CREATE PROCEDURE dbo.User_ChangeObjectOwnerBatch<br />
&nbsp;@OldOwner as NVARCHAR(128),<br />
&nbsp;@NewOwner as NVARCHAR(128)<br />
AS<br />
DECLARE @Name&nbsp;&nbsp; as NVARCHAR(128)<br />
DECLARE @Owner&nbsp; as NVARCHAR(128)<br />
DECLARE @OwnerName&nbsp; as NVARCHAR(128)<br />
DECLARE curObject CURSOR FOR <br />
&nbsp;select 'Name'&nbsp;&nbsp; = name,<br />
&nbsp; 'Owner'&nbsp;&nbsp; = user_name(uid)<br />
&nbsp;from sysobjects<br />
&nbsp;where user_name(uid)=@OldOwner<br />
&nbsp;order by name<br />
OPEN&nbsp; curObject<br />
FETCH NEXT FROM curObject INTO @Name, @Owner<br />
WHILE(@@FETCH_STATUS=0)<br />
BEGIN&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;if @Owner=@OldOwner <br />
&nbsp;begin<br />
&nbsp; set @OwnerName = @OldOwner + '.' + rtrim(@Name)<br />
&nbsp; exec sp_changeobjectowner @OwnerName, @NewOwner<br />
&nbsp;end<br />
-- select @name,@NewOwner,@OldOwner<br />
&nbsp;FETCH NEXT FROM curObject INTO @Name, @Owner<br />
END<br />
close curObject<br />
deallocate curObject<br />
GO</p>
<p>10、SQL SERVER中直接循环写入数据<br />
declare @i int<br />
set @i=1<br />
while @i&lt;30<br />
begin<br />
&nbsp;&nbsp; insert into test (userid) values(@i)<br />
&nbsp;&nbsp; set @i=@i+1<br />
end<br />
小记存储过程中经常用到的本周，本月，本年函数 <br />
Dateadd(wk,datediff(wk,0,getdate()),-1) <br />
Dateadd(wk,datediff(wk,0,getdate()),6) <br />
Dateadd(mm,datediff(mm,0,getdate()),0) <br />
Dateadd(ms,-3,dateadd(mm,datediff(m,0,getdate())+1,0)) <br />
Dateadd(yy,datediff(yy,0,getdate()),0) <br />
Dateadd(ms,-3,DATEADD(yy, DATEDIFF(yy,0,getdate())+1, 0)) <br />
上面的SQL代码只是一个时间段 <br />
Dateadd(wk,datediff(wk,0,getdate()),-1) <br />
Dateadd(wk,datediff(wk,0,getdate()),6) <br />
就是表示本周时间段. <br />
下面的SQL的条件部分,就是查询时间段在本周范围内的: <br />
Where Time BETWEEN Dateadd(wk,datediff(wk,0,getdate()),-1) AND Dateadd(wk,datediff(wk,0,getdate()),6) <br />
而在存储过程中 <br />
select @begintime = Dateadd(wk,datediff(wk,0,getdate()),-1) <br />
select @endtime = Dateadd(wk,datediff(wk,0,getdate()),6)</p>
<img src ="http://www.blogjava.net/morphis/aggbug/156998.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-10-30 17:40 <a href="http://www.blogjava.net/morphis/archive/2007/10/30/156998.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c,c++水平相关</title><link>http://www.blogjava.net/morphis/archive/2007/09/08/143698.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Sat, 08 Sep 2007 15:35:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/09/08/143698.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/143698.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/09/08/143698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/143698.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/143698.html</trackback:ping><description><![CDATA[<p><strong><span>1. </span><span>在类的普通成员函数中调用虚函数，情况是怎么样的？（对象、引用、指针）</span></strong></p>
<p><span>多态， 事实上，这是 Template Method模式的关键</span> <span><br />
<strong>2. </strong></span><span><strong>关于成员变量初始化顺序，几个有依赖关系的成员变量要初始化，让写出构造函数。</strong></span><span> </span></p>
<p>在初始化列表中，成员变量的初始化顺序是其在类中声明顺序，而非列表中的顺序。<br />
</p>
<p><strong><span>3. </span><span>写一个双链表。</span></strong><span> <br />
</span></p>
<p>Struct&nbsp;ListNode</p>
<p>{</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>int nData;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>ListNode* pPreviousNode;</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>ListNode* pNextNode;</p>
<p>}</p>
<p><span>一般链表都会有一个表头节点与指向表头节点的头指针，</span><span> </span><span>应该会提供列表接口，</span><span> </span><span>按此数据结构实现即可。</span></p>
<p><strong><span>4. </span><span>写个</span><span>is-a</span><span>和</span><span>has-a</span><span>。</span></strong><span> </span></p>
<p>这个比较简单</p>
<p>Class Pet{};</p>
<p>Class Dog: public Pet{};</p>
<p>Class Boy{Pet* m_pPet;};</p>
<p><strong>5. struct vs. class.</strong></p>
<p><span>1)</span><span>默认访问属性，</span><span> struct</span><span>为</span><span>public, class</span><span>为</span><span>private<br />
</span></p>
<p><span>2) 默认继承属性，struct<span>为</span><span>public, class</span><span>为</span><span>private</span><br />
3)class</span><span>可以用来声明模板参数，而</span><span>struct</span><span>不能</span><span> </span></p>
<p><strong><span>6. </span><span>称</span><span>8</span><span>个小球的问题</span><span> </span></strong></p>
<p>没题</p>
<p><strong><span>7. stl </span><span>里面</span><span>vector</span><span>的实现（内部空间的申请与分配）</span><span> </span></strong></p>
<p><span>Vector</span><span>中文名字是动态数组，</span><span> </span><span>其内部数据结构就是一个数组，</span><span> </span><span>但是在数组元素不够用的时候，就要动态的重新分配，</span><span> </span><span>一般是现在大小的两倍，</span><span> </span><span>然后把原数组的内容拷贝过去。所以，</span><span> </span><span>在一般情况下，</span><span> </span><span>其访问速度同一般数组，</span><span> </span><span>只有在重新分配发生时，</span><span> </span><span>其性能才会下降</span></p>
<p><strong><span>8. struct /class</span><span>的区别</span><span> </span></strong></p>
<p>重复了</p>
<p><strong><span>9. </span><span>为什么要用</span><span>struct </span></strong></p>
<p><span>成员的默认属性不同，用</span><span>struct</span><span>的话，主要是作为数据的集合。</span><span> </span></p>
<p><strong><span>10. </span><span>怎样使一个</span><span>class</span><span>不能被实例化</span></strong></p>
<p><span>1</span><span>，构造函数私有化，</span><span>2</span><span>，抽象类</span><span> </span></p>
<p><strong><span>11. </span><span>私有继承和</span><span>public</span><span>继承的区别。</span></strong><span> </span></p>
<p><span>私有继承：</span><span> </span><span>只继承实现，不继承实现</span><span> has-a</span></p>
<p><span>公有继承：继承接口与实现</span><span><span>&nbsp;&nbsp;&nbsp; </span>is-a</span></p>
<p><strong><span>12. void *p</span><span>的问题</span><span> </span></strong></p>
<p><span>不能</span><span>++</span><span> </span></p>
<p><strong><span>13. </span><span>引用和指针的区别与联系。引用是否可以更改</span><span> </span></strong></p>
<p><span>联系：</span><span> </span><span>支持多态，可以用来引用同一对象</span></p>
<p><span>区别：指针可以为</span><span>NULL</span><span>，</span><span> </span><span>引用不可以；</span><span> </span><span>指针可以重赋值，</span><span> </span><span>引用不可以；</span></p>
<p><strong><span>14. windows</span><span>编程基础，线程与进程的区别</span><span> </span></strong></p>
<p>程序是一系列静态的指令序列</p>
<p><span>进程是程序的一次动态执行，进程其实是一个资源的容器，包括一个私有的虚拟地址空间，一些初始的代码与数据，</span><span> </span><span>一些系统资源的句柄等</span></p>
<p><span>线程是一个进程中的执行体，</span><span> </span><span>一般包括</span><span>CPU</span><span>寄存器状态，两个栈（内核模式，用户模式）以及一个</span><span>TLS(Thread-Local Storage)</span><span>等</span></p>
<p><strong><span>15. com+</span><span>是否熟悉</span><span> </span></strong></p>
<p><span>COM+</span><span>是</span><span>COM</span><span>技术的延伸与发展，</span><span> </span><span>它包括了所有</span><span>COM</span><span>的基本功能（基于接口的编程模型，基本组件服务），并组合了</span><span>DCOM</span><span>（使组件技术延伸到了分布式领域）和</span><span>MTS-Microsoft Transaction Server</span><span>（提供了服务器端的组件管理与配置管理），并新增了一些服务：负载平衡，内存数据库，事件模型，队列服务等，主要用于</span><span>Windows DNA(Distributed interNet Application Architecture)</span><span>三层结构的中间层。</span></p>
<p><strong><span>16. </span><span>简述一下</span><span>hash</span><span>算法</span><span> </span></strong></p>
<p><span>哈希表的目的是表查询插入修改能够达到</span><span>O(1)</span><span>的算法复杂度，</span><span> </span><span>通过对</span><span>key</span><span>编码来确定其存储地址来实现，</span><span> </span><span>当不同的</span><span>key</span><span>得到相同的编码时，便需要进行冲突检测与处理，一般方法有除留余数法，</span><span> </span><span>线性探测法，平方探测法，</span><span> </span><span>这使其无法真正达到</span><span>O(1)</span></p>
<p><strong><span>17. </span><span>一个</span><span>32</span><span>位的数据，怎样找到最左边的一个</span><span>1</span><span>？</span></strong></p>
<p><span>如果是在最左位，这个数是负数，否则的话，左移一位，看是否变成负数，这是</span><span>O(n)</span><span>的算法</span><span>，</span><span> </span><span>也可以用一个模板去与，并不断改变这个模板</span></p>
<p><span>O(n/2)</span><span>的算法：二分方式查找</span><span> </span><span>？？？</span></p>
<p><strong><span>18. </span><span>一个</span><span>4*4</span><span>的格子，填入</span></strong><span><strong>1~15 然后给个目标状态，怎样去搜索。<br />
</strong></span><span><strong>比如：<br />
&nbsp;1&nbsp;&nbsp; 2&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;6 <br />
&nbsp;0&nbsp;&nbsp; 4&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;7 <br />
&nbsp;8&nbsp;&nbsp; 9&nbsp; 10 11 <br />
12 13 14 14 <br />
<br />
再给出个最终的状态 （随便都可以） <br />
0 表示一个空格，可以移动，有点像拼图；</strong>&nbsp;<br />
</span></p>
<p>人工智能的教材上用的应该就是这个例子，用A*算法，它既不是广度搜索，也不是深度搜索，而是一种启发式搜索，在进行下一步搜索之前，会用一个估价函数来对后面的节点评分， 取评分最优的进行下一步搜索，如果找不到结果，回溯。对于本题，用曼哈顿距离作为评分标准是个不错的选择。</p>
<p><strong><span>19. </span><span>给你</span><span>100</span><span>万个数据，数据的值在</span><span>0~65535</span><span>之间</span><span> </span><span>用最快的速度排序</span><span> </span></strong></p>
<p><span>多关键字基数排序</span><span>MSD(MOST SIGNIFICANT DIGIT FIRST)</span></p>
<p><strong><span>20. </span><span>如果我们的一个软件产品，用户回复说：运行速度很慢，你怎么处理？</span><span> </span></strong></p>
<p><span>询问其</span><span>Workflow, </span><span>用户的硬件环境</span></p>
<p><span>21. </span><strong><span>八皇后问题，详述解法</span><span> </span><span>（</span><span>八皇后问题说的是在</span><span>8*8</span><span>国际象棋棋盘上</span><span>,</span><span>要求在每一行放置一个皇后</span><span>,</span><span>且能做到在竖方向</span><span>,</span><span>斜方向都没有冲突</span><span>）</span></strong></p>
<p>回溯法</p>
<p><strong><span>22. kmp</span><span>快速匹配算法</span><span> ---</span><span>不算轻松的搞定</span><span> </span></strong></p>
<p>普通的模式匹配算法，一旦不匹配，模式串右移一位；但是其实根据一直条件，我们可以算出应该向右移几位以避免不必要的比较；算法实现比较曲折</p>
<p><strong><span>23. </span><span>无向图中两点间最短路问题</span><span> ---</span><span>伟大的迪杰克斯拉算法</span><span> </span></strong></p>
<p><span>假设一共有</span><span>N</span><span>个节点，</span><span> </span><span>需要一个一维数组</span><span>Previous[N]</span><span>来记录前一个节点序号；一个一维数组</span><span>TotalLength[N]</span><span>来记录从原点到当前节点最短路径；一个二维数组</span><span>Weights[N][N]</span><span>来记录各点之间边的权重</span><span>(</span><span>如果存在</span><span>)</span><span>，</span><span> </span><span>然后从源点到终点进行深度搜索或广度搜索，</span><span> </span><span>按以下规则：搜索到某个节点</span><span>b</span><span>时，假设其前一个节点为</span><span>a, </span><span>把</span><span>TotalLength[a] + Weights[a][b]</span><span>与</span><span>TotalLength[b]</span><span>相比较，如果小于</span><span>TotalLength[b]</span><span>，</span><span> </span><span>则</span><span>TotalLength[b] = TotalLength[a] + Weights[a][b],&nbsp;Previous[b] = a; </span><span>反之则不做任何操作。这样到搜索结束后，</span><span> </span><span>从</span><span>Previous[N]</span><span>数组中就能得到整条最短路径了</span></p>
<p><strong><span>24. </span><span>空间中任意给两个向量，求角平分线</span><span> </span></strong></p>
<p><span>先单位化，</span><span> </span><span>假设单位化后结果为</span><span>nv1, nv2, </span><span>则角平分线为</span><span>(nv1+nv2) / 2</span></p>
<p><strong><span>25. </span><span>什么是平衡树</span><span> </span></strong></p>
<p><span>左右子树都是平衡树，且高度相差不超过</span><span>1</span><span>的有序二叉树</span></p>
<p><strong><span>26. </span><span>哈夫曼编码问题</span><span> </span></strong></p>
<p><span>理论基础</span><span>:</span><span>霍夫曼树是带权路径长度（</span><span>WPL</span><span>：</span><span>Weighted Path Length</span><span>）最小的二叉树，它不一定是完全二叉树，应该是权值大的外结点离根节点最近的扩充二叉树。霍夫曼编码是为了实现数据的最小冗余编码，是数据压缩学的基础。</span><span> </span><span>它根据字符在电文中出现的频率为权值，构造霍夫曼树，左为</span><span>0</span><span>，</span><span> </span><span>右为</span><span>1. </span><span>其有两个效果，一是保证电文有最短的编码，二是字符间不需要分隔符，因为不同的字符必定有不同的开头（成为前缀编码）。</span></p>
<p><strong><span>27. </span><span>有向图求环</span><span> </span></strong></p>
<p>以该节点为源点与终点吗进行深度优先或广度优先搜索</p>
<p><strong><span>28. .</span><span>给</span><span>n</span><span>个点，求凸包问题</span><span> </span></strong></p>
<p><span>凸包</span><span>(convex hull)</span><span>是指一个最小凸多边形，满足这</span><span>N</span><span>个点都在多边形上，或其内。算法描述：</span></p>
<p><span>求出最右的那个点作为凸多边形的一个顶点</span><span>(P0)</span><span>，遍历其他所有点</span><span>(Pi)</span><span>，</span><span> </span><span>如果其他点都在向量</span><span>P0Pi</span><span>的同一侧，则</span><span>Pi</span><span>也为凸多边形的顶点。</span></p>
<p><strong><span>29. </span><span>四则运算（给一个前缀表达式（波兰式）或后缀表达式</span><span>(</span><span>逆波兰式</span><span>)</span><span>，然后求解；给一个中缀表达式）</span><span> </span></strong></p>
<p><span>+*-CDBA -/EF---------------------&gt;&nbsp;A+B*(C-D)-E/F<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>前缀</span><span>-</span><span>中缀</span><span> </span></p>
<p><span>操作符进栈，一个变量</span><span>tmp</span><span>放上一个中间操作数（运算结果），遇到操作数检查</span><span>tmp</span><span>是否为空，</span><span> </span><span>空的话取两个操作数，不空的话取一个操作数，另一个就是</span><span>tmp</span><span>了，操作符出栈运算，结果放入</span><span>tmp</span><span>中，如果是操作符，</span><span>tmp</span><span>清空</span></p>
<p><span>&nbsp;ABCD-*+EF/-&nbsp;---------------------&gt;&nbsp;A+B*(C-D)-E/F<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>后缀</span><span>-</span><span>中缀</span></p>
<p>操作数进栈，遇到操作符，两个操作数出栈，计算结果入栈</p>
<p><strong><span>30. STL</span><span>中</span><span>container</span><span>有哪些？</span><span> </span></strong></p>
<p><span>序列容器：</span><span> vector, list, deque, bitset</span></p>
<p><span>关联容器</span><span>:<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>set, multiset, map, multimap</span></p>
<p><span>适配容器：</span><span>stack, queue, priority_queue</span></p>
<p><span>类容器</span><span>:<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>string, valarray, bitset</span></p>
<p><span>扩展容器：</span><span>hash_set, hash_multiset, hash_map, hash_multimap</span></p>
<p><strong><span>31. map</span><span>中的数据存储方式是什么？</span><span> </span></strong></p>
<p><span>红黑树，</span><span> </span><span>是一种平衡二叉搜索树，</span><span> </span><span>具有良好的最坏情况运行时间（统计性能好与</span><span>AVL</span><span>树）</span></p>
<p><strong><span>32. map</span><span>和</span><span>hashmap</span><span>有什么区别？</span><span> </span></strong></p>
<p><span>内部数据结构不同，</span><span> map</span><span>是红黑树，</span><span>hashmap</span><span>是哈希表</span></p>
<p><strong><span>33. hashmap</span><span>是标准库中的吗？</span><span> </span></strong></p>
<p><span>不是的，但在</span><span>SGI stl</span><span>与</span><span>vc2005</span><span>中都提供了。</span></p>
<p><strong><span>34. vector</span><span>中的</span><span>erase</span><span>方法跟</span><span>algorithm</span><span>的</span><span>remove</span><span>有什么区别？</span><span> </span></strong></p>
<p><span>vector</span><span>中</span><span>erase</span><span>是真正删除了元素，</span><span> </span><span>迭代器访问不到了。</span><span> algorithm</span><span>中的</span><span>remove</span><span>只是简单的把要</span><span>remove</span><span>的元素移到了容器最后面，迭代器还是可以访问到的。因为</span><span>algorithm</span><span>通过迭代器操作，不知道容器的内部结构，所以无法做到真正删除。</span></p>
<p><strong><span>35. object</span><span>是什么？</span></strong></p>
<p><span>具有内部状态，以及操作的</span><span> </span><span>软件构造，用来表示真实存在（物理上或概念上）的对象</span></p>
<p><strong><span>36. C++</span><span>中如何阻止一个类被实例化？</span><span> </span></strong></p>
<p>纯虚函数；构造函数私有化（友元）</p>
<p><strong><span>37. </span><span>一般在什么时候构造函数被声明成</span><span>private</span><span>呢？</span></strong></p>
<p><span>&nbsp;singleton</span><span>模式；</span><span> </span><span>阻止某些操作（如阻止拷贝构造</span><span>）</span></p>
<p><strong><span>38. </span><span>什么时候编译器会生成默认的</span><span>copy constructor</span><span>呢？</span></strong></p>
<p><span>用户没有自定义</span><span>copy constructor</span><span>；在代码中使用到了</span><span>copy constructor;</span></p>
<p><strong><span>39. </span><span>如果你已经写了一个构造函数，编译器还会生成</span><span>copy constructor</span><span>吗？</span><span> </span></strong></p>
<p><span>如果我写的是</span><span>copy constructor, </span><span>不会</span></p>
<p><span>如果我写的不是</span><span>copy constructor, </span><span>同</span><span>38</span></p>
<p><strong><span>40. </span><span>为什么说如果一个类作为基类，则它的析构函数要声明成</span><span>virtual</span><span>的？</span><span> </span></strong></p>
<p><span>因为，如果</span><span>delete</span><span>一个基类的指针时，</span><span> </span><span>如果它指向的是一个子类的对象，那么析构函数不为虚就会导致无法调用子类析构函数，从而导致资源泄露。</span><span> </span><span>当然，另一种做法是将基类析构函数设为</span><span>protected.</span></p>
<p><strong><span>41. inline</span><span>的函数和</span><span>#define</span><span>有什么区别？什么时候会真的被</span><span>inline</span><span>，什么时候不会呢？</span><span> </span></strong></p>
<p><span>1) </span><span>宏是在预编译阶段简单文本替代，</span><span> inline</span><span>在编译阶段实现展开</span></p>
<p><span>2)</span><span>宏肯定会被替代，而复杂的</span><span>inline</span><span>函数不会被展开</span></p>
<p><span>3)</span><span>宏容易出错（运算顺序），且难以被调试</span><span>,inline</span><span>不会</span></p>
<p><span>4)</span><span>宏不是类型安全，而</span><span>inline</span><span>是类型安全的，会提供参数与返回值的类型检查</span></p>
<p><span>当出现以下情况时</span><span>inline</span><span>失败</span></p>
<p><span>函数</span><span>size</span><span>太大</span></p>
<p><span>inline</span><span>虚函数</span></p>
<p>函数中存在循环或递归</p>
<p><span>函数调用其他</span><span>inline</span><span>函数</span></p>
<p><strong><span>42. </span><span>如果把一个类的成员函数写在类的声明中是什么意思？</span><span> </span></strong></p>
<p><span>i</span><span>nline</span><span>此函数</span><span> </span><span>（</span><span>inline</span><span>与</span><span>template</span><span>类似，</span><span> </span><span>必须在</span><span>.h</span><span>中实现）</span></p>
<p><strong><span>43. public</span><span>继承和</span><span>private</span><span>继承有什么架构上的区别？</span></strong></p>
<p><span>public</span><span>是</span><span>is-a</span><span>的关系，</span><span>继承接口与实现</span></p>
<p><span>private</span><span>是</span><span>has-a</span><span>的关系</span><span> </span><span>，只继承实现</span></p>
<p><strong><span>44. </span><span>在多继承的时候，如果一个类继承同时继承自</span><span>class A</span><span>和</span><span>class B</span><span>，而</span><span>class A</span><span>和</span><span>B</span><span>中都有一个函数叫</span><span>foo()</span><span>，如何明确的在子类中指出</span><span>override</span><span>哪个父类的</span><span>foo()</span><span>？</span></strong><span> </span></p>
<p><span>首先，</span><span>foo</span><span>在</span><span>A,B</span><span>总应该都是虚函数，否则就直接覆盖了，就没有这个问题了；其次，这个问题从语法角度来看似乎是无法解决。因为我们不能改原有设计（不然也没这个问题了</span><span>:)</span><span>）</span><span>,</span><span>所有只好从</span><span>extend</span><span>来考虑：</span></p>
<p>class EA: public class A</p>
<p>{</p>
<p>public:</p>
<p><span>&nbsp;&nbsp; </span>virtual void foo(){fooA();}</p>
<p>private:</p>
<p><span>&nbsp;&nbsp; </span>virtual void fooA() = 0;</p>
<p>}</p>
<p>&nbsp;</p>
<p>class EB: public class B</p>
<p>{</p>
<p>public:</p>
<p><span>&nbsp;&nbsp; </span>virtual void foo(){fooB();}</p>
<p>private:</p>
<p><span>&nbsp;&nbsp; </span>virtual void fooB() = 0;</p>
<p>}</p>
<p>&nbsp;</p>
<p><span>这样，</span><span> </span><span>我就可以</span><span>override</span><span>不同的函数来达到这个目的了</span></p>
<p>class AB: public EA, pubic EB</p>
<p>{</p>
<p>private:</p>
<p>virtual void fooA(){}</p>
<p>virtual void fooB(){}</p>
<p>}</p>
<p><strong><span>45. </span><span>虚拟继承的语法是什么？</span></strong><span> </span></p>
<p><span>&nbsp;&nbsp;&nbsp; </span>A</p>
<p>&nbsp;/<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>\</p>
<p>B<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>C</p>
<p><span>&nbsp;&nbsp; </span>\&nbsp;/</p>
<p><span>&nbsp;&nbsp;&nbsp; </span>D</p>
<p>class A{};</p>
<p>class B: virtual public A{};</p>
<p>class C: virtual public A{};</p>
<p>class D: public B, public C{};</p>
<p><strong><span>46. </span><span>部分模版特例化和全部模版特例化有什么区别？</span><span> </span></strong></p>
<p>偏特化只使用于类模板，而全特化适用与函数模板，类模板。</p>
<p>偏特化的结果还是一个模板，而全特化的结果是一个具体的类型。</p>
<p><strong><span>47. </span><span>编一个函数，使一个单项链表转置。</span><span> </span></strong></p>
<p>应该是逆序吧</p>
<p>这个小算法竟然花了我不少时间，没有测试过的：</p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">struct</span><span style="color: #000000">&nbsp;ListNode<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;data;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ListNode</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;next;<br />
};<br />
<br />
</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;ReverseList(ListNode</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;p)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;ListNode</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;p0&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;NULL;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ListNode</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;p1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ListNode</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;p2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p1&nbsp;</span><span style="color: #000000">?</span><span style="color: #000000">&nbsp;p1</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next&nbsp;:&nbsp;NULL;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;三个指针，分别表示当前处理节点，前一节点与后一节点<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;复用头节点的next来保存节点</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">while</span><span style="color: #000000">&nbsp;(NULL&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;p2)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p2</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">暂存</span><span style="color: #008000"><br />
</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p1</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">逆转</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p2</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p1;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p0&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">往下一个节点</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;p</span><span style="color: #000000">-&gt;</span><span style="color: #000000">next&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;p1;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">p1末元素变为首元素，链到头节点上</span><span style="color: #008000"><br />
</span><span style="color: #000000">}</span></div>
<p>&nbsp;</p>
<p><strong><span>48. </span><span>拆解一个整数，比如</span><span>4,</span><span>可以拆解成</span><span>4=3+1</span><span>；</span><span>4=2+2</span><span>；</span><span>4=2+1+1</span><span>；</span><span>4=1+1+1+1 </span></strong></p>
<p><span>首先，对一个数进行拆分后，可能又要对最后一个因子进行拆分，所以要用递归；其次，第</span><span>n+1</span><span>个因子是小于等于第</span><span>n</span><span>个因子的；再者，对最后一个因子，我可以直接输出，也可以继续拆分。</span></p>
<p>算法如下：<br />
</p>
<p></p>
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;print(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;res[],&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;num)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;num;&nbsp;</span><span style="color: #000000">++</span><span style="color: #000000">i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000">"</span><span style="color: #000000">%d&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">,&nbsp;res[i]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000">"</span><span style="color: #000000">\n</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
}<br />
</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;n表示总数，m表示最大因子</span><span style="color: #008000"><br />
</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;split(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;n,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;m)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;res[</span><span style="color: #000000">100</span><span style="color: #000000">];&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">保存结果</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">static</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;num&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">当前因子下标</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;num</span><span style="color: #000000">++</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">递归终止条件，为0不可再分，直接输出</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(</span><span style="color: #000000">0</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;n)&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(res,&nbsp;num</span><span style="color: #000000">+</span><span style="color: #000000">1</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num</span><span style="color: #000000">--</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(n&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;m)&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;不拆，直接输出</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res[num]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;m;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(res,num</span><span style="color: #000000">+</span><span style="color: #000000">1</span><span style="color: #000000">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num</span><span style="color: #000000">--</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;拆分出第一个</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res[num]&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;m;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;n</span><span style="color: #000000">-</span><span style="color: #000000">m;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">最大因子不可能大于总数</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(m</span><span style="color: #000000">&gt;</span><span style="color: #000000">n)&nbsp;m&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;n;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;循环，第二个因子可以继续拆分，而且按照最大因子不同可以拆分成多个</span><span style="color: #008000"><br />
</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;m;&nbsp;i</span><span style="color: #000000">&gt;=</span><span style="color: #000000">1</span><span style="color: #000000">;&nbsp;</span><span style="color: #000000">--</span><span style="color: #000000">i)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split(n,&nbsp;i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num</span><span style="color: #000000">--</span><span style="color: #000000">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Split(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;n)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;n</span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">;&nbsp;i</span><span style="color: #000000">&gt;=</span><span style="color: #000000">1</span><span style="color: #000000">;&nbsp;i</span><span style="color: #000000">--</span><span style="color: #000000">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;split(n,&nbsp;i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<p><br />
唉，老了，这个小东西搞了我<span>N</span><span>久的。。。。</span></p>
<p><strong><span>49. </span><span>不用库函数，实现</span><span>strcpy</span><span>或者</span><span>memcpy</span><span>等函数</span><span> </span></strong></p>
<p>一个字节一个字节的拷过去吧，但是要考虑源内存与目标内存的重叠。</p>
<p><strong><span>50. </span><span>内联函数的作用和缺点</span><span> </span></strong></p>
<p><span>把代码直接插入到调用的地方，可以减少函数调用的次数，但是会增加代码的</span><span>size</span><span>，还有，如果内联失败，在每个调用的</span><span>obj</span><span>里，都会产生一份该函数的拷贝，这样既没有怎么减少代码的</span><span>size</span><span>，又没有减少函数的调用，赔了夫人又折兵。。。</span></p>
<p><strong><span>51. </span><span>指针和引用的区别</span><span> </span></strong></p>
<p>指针可以不初始化，引用必须初始化</p>
<p><span>指针可以是</span><span>NULL</span><span>，而引用必须引用一个实在的对象</span></p>
<p>指针可以重指向其他对象，引用一旦初始化，便不再改变</p>
<p><strong><span>52. </span><span>友元的意义</span><span> </span></strong></p>
<p><span>使被声明为友元的函数或类可以访问某个类的非共有成员</span>。</p>
<p><strong><span>53. </span><span>虚函数的意义</span><span> </span></strong></p>
<p>实现多态</p>
<p><strong><span>54. Overload, Overwrite, Override </span><span>各自的特点和意义</span><span> </span></strong></p>
<p><span>Overload: </span><span>函数重载</span><span>(</span><span>名字相同，参数不同</span><span>)</span></p>
<p><span>Overwrite</span><span>：覆盖</span></p>
<p><span>Override: </span><span>虚函数重载</span></p>
<p><strong><span>55. </span><span>头文件中的</span><span>ifndef/define/endif </span><span>干什么用？</span></strong></p>
<p><span>防止该头文件被重复引用</span><span>。</span><span> </span></p>
<p><strong><span>56.</span><span> </span><span>＃</span><span>i nclude &lt;filename.h&gt; </span><span>和＃</span><span>i nclude &#8220;filename.h&#8221; </span><span>有什么区别？</span><span> </span></strong></p>
<p><span>＃</span><span>i nclude &lt;filename.h&gt;</span><span>：</span><span> </span><span>从标准库路径去寻找该文件，对于</span><span>VC</span><span>来说，应该还包括</span><span>VC</span><span>环境设置选项中的包含目录以及工程属性中指定的目录</span></p>
<p><span>＃</span><span>i nclude &#8220;filename.h&#8221;</span><span>：先在当前目录查找，如果找不到，按上面那种方式寻找</span></p>
<p><strong><span>57. </span><span>在</span><span>C++ </span><span>程序中调用被</span><span>C </span><span>编译器编译后的函数，为什么要加</span><span>extern &#8220;C&#8221;</span><span>？</span></strong></p>
<p><span>C++</span><span>语言支持函数重载，</span><span>C </span><span>语言不支持函数重载。函数被</span><span>C++</span><span>编译后在库中的名字与</span><span>C </span><span>语言的不同。</span><span>C++</span><span>提供了</span><span>C </span><span>连接交换指定符号</span><span>extern&#8220;C&#8221;</span><span>来解决名字匹配问题</span><span> </span></p>
<p><strong><span>58. </span><span>一个类有基类、内部有一个其他类的成员对象，构造函数的执行顺序是怎样的？</span></strong></p>
<p><span>先执行基类的（如果基类当中有虚基类，要先执行虚基类的，其他基类则按照声明派生类时的顺序依次执行），再执行成员对象的，最后执行自己的。</span><span> </span></p>
<p><strong><span>59. </span><span>请描述一个你熟悉的设计模式</span><span> </span></strong></p>
<p><span>这个看你熟悉什么了。</span><span>singleton</span><span>最简单了，</span><span>template method</span><span>用的最多了，</span><span>bridge</span><span>挺炫的，</span><span>command</span><span>吹吹</span><span>undo,redo</span><span>也不错。。。。。</span></p>
<p><strong><span>60. </span><span>在</span><span>UML </span><span>中，聚合</span><span>(aggregation)</span><span>和组合</span><span>(composition)</span><span>有什么区别？</span><span> </span></strong></p>
<p>其实从名字就能分别出来了。</p>
<p>聚合表示只是简单的聚聚，没什么本质的联系，所以这些对象的生存时间也就没什么关系了；</p>
<p>组合表示了更加紧密的一种关系，这些对象有着共同的生存期。</p>
<p>一个典型的例子是孙悟空，手臂，金箍棒的关系。。。。</p>
<p><strong><span>61. C#</span><span>和</span><span>C++</span><span>除了语法上的差别以外，有什么不同的地方？</span><span> </span></strong></p>
<p><span>C++</span><span>是直接生成可执行代码，而</span><span>C#</span><span>是先生成中间代码，等到第一次执行时，才由</span><span>JIT</span><span>（</span><span>Just In Time</span><span>）生成可执行的机器码。</span></p>
<p><span>还有就是</span><span>(1) c#</span><span>有垃圾自动回收机制，程序员不用担心对象的回收。</span><span>(2)c#</span><span>严禁使用指针，只能处理对象。如果希望使用指针，则仅可在</span><span>unsafe </span><span>程序块中能使用指针。</span><span>(3)c#</span><span>只能单继承。</span><span>(4)</span><span>必须通过类名访问静态成员。不能像</span><span>C++</span><span>中那样，通过对象访问静态成员。</span><span>(5)</span><span>在子类中</span><span>重写</span><span>父类的虚函数时必须用关键字</span><span>override,</span><span>覆盖父类的方法要用关键字</span><span>new </span></p>
<p><strong><span>62. New delete</span><span>与</span><span>malloc free </span><span>的区别</span><span> </span></strong></p>
<p><span>对于类，</span><span>New </span><span>和</span><span>delete</span><span>会调用构造，析构函数</span></p>
<p><span>new</span><span>，</span><span>delete</span><span>都是能感知到类型的。</span><span>new</span><span>返回一个制定的类型，</span><span>delete</span><span>删除一个指定的类型，从而不用给定</span><span>size</span><span>。而</span><span>malloc</span><span>与</span><span>free</span><span>都是处理</span><span>void</span><span>类型的。用时时必须经过强制类型转换。</span></p>
<p><strong><span>63. #define DOUBLE(x) x+x</span><span>，</span><span>i = 5*DOUBLE(10)</span><span>；</span><span>i</span><span>是多少？正确的声明是什么？</span><span> </span></strong></p>
<p>I = 5*10+10 = 60 60</p>
<p>正确的声明是：</p>
<p>#define DOUBLE(x) ((x)+(x))</p>
<p><strong><span>64. </span><span>有哪几种情况只能用</span><span>intialization list </span><span>而不能用</span><span>assignment? </span></strong></p>
<p><span>当类中含有</span><span>const</span><span>、</span><span>reference </span><span>成员变量；基类的构造函数都需要参数；类中含有其他类的成员对象，而该类的构造函数都需要参数。</span><span> </span></p>
<p><strong><span>65. C++</span><span>是不是类型安全的？</span></strong></p>
<p><span>不是。两个不同类型的指针之间可以强制转换。</span><span>C#</span><span>是类型安全的。</span><span> </span></p>
<p><strong><span>66. main </span><span>函数执行以前，还会执行什么代码？</span></strong></p>
<p><span>全局对象的构造函数会在</span><span>main </span><span>函数之前执行。</span><span> </span></p>
<p><strong><span>67. </span><span>描述内存分配方式以及它们的区别。</span></strong></p>
<p><span>（</span><span>1</span><span>）从静态存储区域分配。内存在程序编译的时候就已经分配好，这块内存在程序的整个运行期间都存在。例如全局变量，</span><span>static </span><span>变量。</span></p>
<p><span>（</span><span>2</span><span>）</span><span> </span><span>在栈上创建。在执行函数时，函数内局部变量的存储单元都可以在栈上创建，函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。</span><span>用的是</span><span>cache</span><span>，速度较快但容量较小。</span></p>
<p><span>（</span><span>3</span><span>）</span><span> </span><span>从堆上分配，亦称动态内存分配。程序在运行的时候用</span><span>malloc </span><span>或</span><span>new </span><span>申请任意多少的内存，程序员自己负责在何时用</span><span>free </span><span>或</span><span>delete </span><span>释放内存。动态内存的生存期由我们决定，使用非常灵活，但问题也最多。</span></p>
<p><span>&nbsp;（4）文字常量区， 如char* p = "hello, world"就是一个例子，其内存也</span><span>在程序编译的时候就已经分配好？</span></p>
<p><span>&nbsp; 一个程序除了上面这些，还有一个(5)程序代码区了。<br />
</span></p>
<p><strong><span>68. </span><span>比较一下</span><span>C++</span><span>中</span><span>static_cast </span><span>和</span><span> dynamic_cast </span><span>的区别。</span></strong><span> </span></p>
<p><span>Static_cast</span><span>可以显式的做一些自动转换，如一些</span><span>int, char</span><span>一些基础类型的转换，以及指针之间的转换。但是其不保证安全性。</span><span>Dynamic_cast</span><span>主要作用其实在于把一个基类指针转化为子类指针，因为这个基类指针真正指向的不一定是我们想转换的类型的对象，所以转换可能失败，</span><span>dynamic_cast</span><span>能够知道失败而返回</span><span>NULL</span><span>，而</span><span>static_cast</span><span>就没那么聪明了，原因是</span><span>dynamic_cast</span><span>会利用</span><span>rtti</span><span>去查找该转换是否可行</span><span>.(</span><span>耗费时间多点。</span><span>)</span></p>
<p><strong><span>69. </span><span>当一个类</span><span>A </span><span>中没有生命任何成员变量与成员函数</span><span>,</span><span>这时</span><span>sizeof(A)</span><span>的值是多少，如果不是零，请解释一下编译器为什么没有让它为零。</span></strong></p>
<p><span>不为零，不同的对象应该有不同的地址，假设我声明一个</span><span>A</span><span>的数组</span><span>A a[2]</span><span>，如果为零，那么</span><span>a[0]</span><span>和</span><span>a[1]</span><span>的地址岂不相同了</span></p>
<p><strong><span>70. </span><span>已知两个链表</span><span>head1 </span><span>和</span><span>head2</span><span>各自有序，请把它们合并成一个链表依然有序，要求用递归方法进行。</span></strong><span> </span></p>
<p>归并排序，应该比较简单。要注意的是如果一个链表为空，那么可以简单的把另一个直接链过去了。<br />
</p>
 <img src ="http://www.blogjava.net/morphis/aggbug/143698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-09-08 23:35 <a href="http://www.blogjava.net/morphis/archive/2007/09/08/143698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>some english</title><link>http://www.blogjava.net/morphis/archive/2007/06/14/124400.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Thu, 14 Jun 2007 15:08:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/06/14/124400.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/124400.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/06/14/124400.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/124400.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/124400.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp; (1) I love you not because of who you are, but because of who I am when I am with you.</p>
<p>&nbsp;&nbsp;&nbsp; 我爱你，不是因为你是一个怎样的人，而是因为我喜欢与你在一起时的感觉。</p>
<p>&nbsp;&nbsp;&nbsp; (2) No man or woman is worth your tears, and the one who is, won&#8216;t make you cry.</p>
<p>&nbsp;&nbsp;&nbsp; 没有人值得你流泪，值得让你这么做的人不会让你哭泣。</p>
<p>&nbsp;&nbsp;&nbsp; (3) The worst way to miss someone is to be sitting right beside them knowing you can&#8216;t have them.</p>
<p>&nbsp;&nbsp;&nbsp; 失去某人，最糟糕的莫过于，他近在身旁，却犹如远在天边。</p>
<p>&nbsp;&nbsp;&nbsp; (4) Never frown, even when you are sad, because you never know who is falling in love with your smile.</p>
<p>&nbsp;&nbsp;&nbsp; 纵然伤心，也不要愁眉不展，因为你不知是谁会爱上你的笑容。l+cvz</p>
<p>&nbsp;&nbsp;&nbsp; (5) To the world you may be one person, but to one person you may be the world.</p>
<p>&nbsp;&nbsp;&nbsp; 对于世界而言，你是一个人；但是对于某个人，但是对于某个人，你是他的整个世界。</p>
<p>&nbsp;&nbsp;&nbsp; (6) Don&#8216;t waste your time on a man/woman, who isn&#8216;t willing to waste their time on you.</p>
<p>&nbsp;&nbsp;&nbsp; 不要为那些不愿在你身上花费时间的人而浪费你的时间。</p>
<p>&nbsp;&nbsp;&nbsp; (7) Just because someone doesn&#8217;t&#8216;t love you the way you want them to, doesn&#8217;t&#8216;t mean they don&#8216;t love you with all they have.</p>
<p>&nbsp;&nbsp;&nbsp; 爱你的人如果没有按你所希望的方式来爱你，那并不代表他们没有全心全意地爱你。</p>
<p>&nbsp;&nbsp;&nbsp; (8) Don&#8216;t try so hard, the best things come when you least expect them to.f.H0</p>
<p>&nbsp;&nbsp;&nbsp; 不要着急，最好的总会在最不经意的时候出现。</p>
<p>&nbsp;&nbsp;&nbsp; (9) Maybe God wants us to meet a few wrong people before meeting the right one, so that when we finally meet the person, we will know how to be grateful.;</p>
<p>&nbsp;&nbsp;&nbsp; 在遇到梦中人之前，上天也许会安排我们先遇到别的人；在我们终于遇见心仪的人时/<a href="http://www.haoquchu.cn/"><font color=#000000>数据恢复</font></a>，便应当心存感激。</p>
<p>&nbsp;&nbsp;&nbsp; (10) Don&#8216;t cry because it is over, smile because it happened.</p>
<p>&nbsp;&nbsp;&nbsp; 不要因为结束而哭泣，微笑吧，为你的曾经拥有。 </p>
<img src ="http://www.blogjava.net/morphis/aggbug/124400.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-06-14 23:08 <a href="http://www.blogjava.net/morphis/archive/2007/06/14/124400.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何阅读别人代码 [转贴] </title><link>http://www.blogjava.net/morphis/archive/2007/06/14/124397.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Thu, 14 Jun 2007 15:05:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/06/14/124397.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/124397.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/06/14/124397.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/124397.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/124397.html</trackback:ping><description><![CDATA[<p>code reading<br><br>++++++++++++<br><br>第一章: 导论<br><br>++++++++++++<br><br><br><br>1.要养成一个习惯, 经常花时间阅读别人编写的高品质代码.<br><br>2.要有选择地阅读代码, 同时, 还要有自己的目标. 您是想学习新的模式|编码风格|还是满足某些需求的方法.<br><br>3.要注意并重视代码中特殊的非功能性需求, 这些需求也许会导致特殊的实现风格.<br><br>4.在现有的代码上工作时, 请与作者和维护人员进行必要的协调, 以避免重复劳动或产生厌恶情绪.<br><br>5.请将从开放源码软件中得到的益处看作是一项贷款, 尽可能地寻找各种方式来回报开放源码社团.<br><br>6.多数情况下, 如果您想要了解"别人会如何完成这个功能呢?", 除了阅读代码以外, 没有更好的方法.<br><br>7.在寻找bug时, 请从问题的表现形式到问题的根源来分析代码. 不要沿着不相关的路径(误入歧途).<br><br>8.我们要充分利用调试器|编译器给出的警告或输出的符号代码|系统调用跟踪器|数据库结构化查询语言的日志机制|包转储工具和Windows的消<br><br>息侦查程序, 定出的bug的位置.<br><br>9.对于那些大型且组织良好的系统, 您只需要最低限度地了解它的全部功能, 就能够对它做出修改.<br><br>10.当向系统中增加新功能时, 首先的任务就是找到实现类似特性的代码, 将它作为待实现功能的模板.<br><br>11.从特性的功能描述到代码的实现, 可以按照字符串消息, 或使用关键词来搜索代码.<br><br>12.在移植代码或修改接口时, 您可以通过编译器直接定位出问题涉及的范围, 从而减少代码阅读的工作量.<br><br>13.进行重构时, 您从一个能够正常工作的系统开始做起, 希望确保结束时系统能够正常工作. 一套恰当的测试用例(test case)可以帮助您满<br><br>足此项约束.<br><br>14.阅读代码寻找重构机会时, 先从系统的构架开始, 然后逐步细化, 能够获得最大的效益.<br><br>15.代码的可重用性是一个很诱人, 但难以理解与分离, 可以试着寻找粒度更大一些的包, 甚至其他代码.<br><br>16.在复查软件系统时, 要注意, 系统是由很多部分组成的, 不仅仅只是执行语句. 还要注意分析以下内容: 文件和目录结构|生成和配置过程|<br><br>用户界面和系统的文档.<br><br>18.可以将软件复查作为一个学习|讲授|援之以手和接受帮助的机会.<br>&amp;&lt;60;&amp;&lt;60; &amp;&lt;60;<br><br>++++++++++++++++++++<br><br>第二章: 基本编程元素<br><br>++++++++++++++++++++<br><br><br><br>19.第一次分析一个程序时, main是一个好的起始点.<br><br>20.层叠if-else if-...-else序列可以看作是由互斥选择项组成的选择结构.<br><br>21.有时, 要想了解程序在某一方面的功能, 运行它可能比阅读源代码更为恰当.<br><br>22.在分析重要的程序时, 最好首先识别出重要的组成部分.<br><br>23.了解局部的命名约定, 利用它们来猜测变量和函数的功能用途.<br><br>24.当基于猜测修改代码时, 您应该设计能够验证最初假设的过程. 这个过程可能包括用编译器进行检查|引入断言|或者执行适当的测试用例.<br><br>25.理解了代码的某一部分, 可能帮助你理解余下的代码.<br><br>26.解决困难的代码要从容易的部分入手.<br><br>27.要养成遇到库元素就去阅读相关文档的习惯; 这将会增强您阅读和编写代码的能力.<br><br>28.代码阅读有许多可选择的策略: 自底向上和自顶向下的分析|应用试探法和检查注释和外部文档, 应该依据问题的需要尝试所有这些方法.<br><br>29.for (i=0; i&lt;n; i++)形式的循环执行n次; 其他任何形式都要小心.<br><br>30.涉及两项不等测试(其中一项包括相等条件)的比较表达式可以看作是区间成员测试.<br><br>31.我们经常可以将表达式应用在样本数据上, 借以了解它的含义.<br><br>32.使用De Morgan法则简化复杂的逻辑表达式.<br><br>33.在阅读逻辑乘表达式时, 问题可以认为正在分析的表达式以左的表达式均为true; 在阅读逻辑和表达式时, 类似地, 可以认为正在分析的表<br><br>达式以左的表达式均为false.<br><br>34.重新组织您控制的代码, 使之更为易读.<br><br>35.将使用条件运行符? :的表达式理解为if代码.<br><br>36.不需要为了效率, 牺牲代码的易读性.<br><br>37.高效的算法和特殊的优化确实有可能使得代码更为复杂, 从而更难理解, 但这并不意味着使代码更为紧凑和不易读会提高它的效率.<br><br>38.创造性的代码布局可以用来提高代码的易读性.<br><br>39.我们可以使用空格|临时变量和括号提高表达式的易读性.<br><br>40.在阅读您所控制的代码时, 要养成添加注释的习惯.<br><br>41.我们可以用好的缩进以及对变量名称的明智选择, 提高编写欠佳的程序的易读性.<br><br>42.用diff程序分析程序的修订历史时, 如果这段历史跨越了整体重新缩排, 常常可以通过指定-w选项, 让diff忽略空白差异, 避免由于更改了<br><br>缩进层次而引入的噪音.<br><br>43.do循环的循环体至少执行一次.<br><br>44.执行算术运算时, 当b=2n-1时, 可以将a&amp;b理解为a%(b+1).<br><br>45.将a&lt;&lt;n理解为a*k, k=2n.<br><br>46.将a&gt;&gt;n理解为a/k, k=2n.<br><br>47.每次只分析一个控制结构, 将它的内容看作是一个黑盒.<br><br>48.将每个控制结构的控制表达式看作是它所包含代码的断言.<br><br>49.return, goto, break和continue语句, 还有异常, 都会影响结构化的执行流程. 由于这些语句一般都会终止或重新开始正在进行的循环, <br><br>因此要单独推理它们的行为.<br><br>50.用复杂循环的变式和不变式, 对循环进行推理.<br><br>51.使用保持含义不变的变换重新安排代码, 简化代码的推理工作.<br><br><br><br>+++++++++++++++++++<br><br>第三章: 高级C数据类型<br><br>+++++++++++++++++++<br><br><br><br>52.了解特定语言构造所服务的功能之后, 就能够更好地理解使用它们的代码.<br><br>53.识别并归类使用指针的理由.<br><br>54.在C程序中, 指针一般用来构造链式数据结构|动态分配的数据结构|实现引用调用|访问和迭代数据元素|传递数组参数|引用函数|作为其他<br><br>值的别名|代表字符串|以及直接访问系统内存.<br><br>55.以引用传递的参数可以用来返回函数的结果, 或者避免参数复制带来的开销.<br><br>56.指向数组元素地址的指针, 可以访问位于特定索引位置的元素.<br><br>57.指向数组元素的指针和相应的数组索引, 作用在二者上的运算具有相同的语义.<br><br>58.使用全局或static局部变量的函数大多数情况都不可重入(reentrant).<br><br>59.字符指针不同于字符数组.<br><br>60.识别和归类应用结构或共用体的每种理由.<br><br>61.C语言中的结构将多个数据元素集合在一起, 使得它们可以作为一个整体来使用, 用来从函数中返回多个数据元素|构造链式数据结构|映射<br><br>数据在硬件设备|网络链接和存储介质上的组织方式|实现抽象数据类型|以及以面向对象的方式编程.<br><br>62.共用体在C程序中主要用于优化存储空间的利用|实现多态|以及访问数据不同的内部表达方式.<br><br>63.一个指针, 在初始化为指向N个元素的存储空间之后, 就可以作为N个元素的数组来使用.<br><br>64.动态分配的内在块可以电焊工地释放, 或在程序结束时释放, 或由垃圾回收器来完成回收; 在栈上分配的内存块当分配它的函数退出后释放<br><br>.<br><br>65.C程序使用typedef声明促进抽象, 并增强代码的易读性, 从而防范可移植性问题, 并模拟C++和Java的类声明行为.<br><br>66.可以将typedef声明理解成变量定义: 变量的名称就是类型的名称; 变量的类型就是与该名称对应的类型.<br>&amp;&lt;60;&amp;&lt;60;&amp;&lt;60; <br><br><br><br>&amp;&lt;60; <br>+++++++++++++++<br><br>第四章: C数据结构<br><br>+++++++++++++++<br><br><br><br>67.根据底层的抽象数据类型理解显式的数据结构操作.<br><br>68.C语言中, 一般使用内建的数组类型实现向量, 不再对底层实现进行抽象.<br><br>69.N个元素的数组可以被序列for (i=0; i&lt;N; i++)完全处理; 所有其他变体都应该引起警惕.<br><br>70.表达式sizeof(x)总会得到用memset或memcpy处理数组x(不是指针)所需的正确字节数.<br><br>71.区间一般用区间内的第一个元素和区间后的第一个元素来表示.<br><br>72.不对称区间中元素的数目等于高位边界与低位边界的差.<br><br>73.当不对称区间的高位边界等于低位边界时, 区间为空.<br><br>74.不对称区间中的低位边界代表区间的第一个元素; 高位边界代表区间外的第一个元素.<br><br>75.结构的数组常常表示由记录和字段组成的表.<br><br>76.指向结构的指针常常表示访问底层记录和字段的游标.<br><br>77.动态分配的矩阵一般存储为指向数组列的指针或指向元素指针的指针; 这两种类型都可以按照二维数组进行访问.<br><br>78.以数组形式存储的动态分配矩阵, 用自定义访问函数定位它们的元素.<br><br>79.抽象数据类型为底层实现元素的使用(或误用)方式提供一种信心的量度.<br><br>80.数组用从0开始的顺序整数为键, 组织查找表.<br><br>81.数组经常用来对控制结构进行高效编码, 简化程序的逻辑.<br><br>82.通过在数组中每个位置存储一个数据元素和一个函数指针(指向处理数据元素的函数), 可以将代码与数据关联起来.<br><br>83.数组可以通过存储供程序内的抽象机(abstract machine)或虚拟机(virtual machine)使用的数据或代码, 控制程序的运作.<br><br>84.可以将表达式sizeof(x) / sizeof(x[0])理解为数组x中元素的个数.<br><br>85.如果结构中含有指向结构自身|名为next的元素, 一般说来, 该结构定义的是单向链表的结点.<br><br>86.指向链表结点的持久性(如全局|静态或在堆上分配)指针常常表示链表的头部.<br><br>87.包含指向自身的next和prev指针的结构可能是双向链表的结点.<br><br>88.理解复杂数据结构的指针操作可以将数据元素画为方框|指针画为箭头.<br><br>89.递归数据结构经常用递归算法来处理.<br><br>90.重要的数据结构操作算法一般用函数参数或模板参数来参数化.<br><br>91.图的结点常常顺序地存储在数组中, 链接到链表中, 或通过图的边链接起来.<br><br>92.图中的边一般不是隐式地通过指针, 就是显式地作为独立的结构来表示.<br><br>93.图的边经常存储为动态分配的数组或链表, 在这两种情况下, 边都锚定在图的结点上.<br><br>94.在无向图中, 表达数据时应该将所有的结点看作是等同的, 类似地, 进行处理任务的代码也不应该基于它们的方向来区分边.<br><br>95.在非连通图中, 执行遍历代码应该能够接通孤立的子图.<br><br>96.处理包含回路的图时, 遍历代码应该避免在处理图的回路进入循环.<br><br>97.复杂的图结构中, 可能隐藏着其他类型的独立结构.<br><br><br><br>+++++++++++++++++<br><br>第五章: 高级控制流程<br><br>+++++++++++++++++<br><br><br><br>98.采用递归定义的算法和数据结构经常用递归的函数定义来实现.<br><br>99.推理递归函数时, 要从基准落伍测试开始, 并认证每次递归调用如何逐渐接近非递归基准范例代码.<br><br>100.简单的语言常常使用一系列遵循该语言语法结构的函数进行语法分析.<br><br>101.推理互递归函数时, 要基于底层概念的递归定义.<br><br>102.尾递归调用等同于一个回到函数开始处的循环.<br><br>103.将throws子句从方法的定义中移除, 然后运行Java编译器对类的源代码进行编译, 就可以容易地找到那些可能隐式地生成异常的方法.<br><br>104.在多处理器计算机上运行的代码常常围绕进程或线程进行组织.<br><br>105.工作群并行模型用于在多个处理器间分配工作, 或者创建一个任务池, 然后将大量需要处理标准化的工作进行分配.<br><br>106.基于线程的管理者/工人并行模型一般将耗时的或阻塞的操作分配给工人子任务, 从而维护中心任务的响应性.<br><br>107.基于进程的管理者/工人并行模型一般用来重用现有的程序, 或用定义良好的接口组织和分离粗粒度的系统模块.<br><br>108.基于流水线的并行处理中, 每个任务都接收到一些输入, 对它们进行一些处理, 并将生成的输出传递给下一个任务, 进行不同的处理.<br><br>109.竞争条件很难捉摸, 相关的代码常常会将竞争条件扩散到多个函数或模块; 因而, 很难隔离由于竞争条件导致的问题.<br><br>110.对于出现在信号处理器中的数据结构操作代码和库调用要保持高度警惕.<br><br>111.在阅读包含宏的代码时, 要注意, 宏既非函数, 也非语句.<br><br>112.do&#8230;while(0)块中的宏等同于控制块中的语句.<br><br>113.宏可以访问在它的使用点可见的所有局部变量.<br><br>114.宏调用可改变参数的值<br><br>115.基于宏的标记拼接能够创建新的标记符.<br>&amp;&lt;60;&amp;&lt;60;&amp;&lt;60; <br><br><br>+++++++++++++++++<br><br>第六章: 应对大型项目<br><br>+++++++++++++++++<br><br><br><br>116.我们可以通过浏览项目的源代码树—包含项目源代码的层次目录结构, 来分析一个项目的组织方式. 源码树常常能够反映出项目在构架和<br><br>软件过程上的结构.<br><br>117.应用程序的源代码树经常是该应用程序的部署结构的镜像.<br><br>118.不要被庞大的源代码集合吓倒; 它们一般比小型的专门项目组织得更出色.<br><br>119.当您首次接触一个大型项目时, 要花一些时间来熟悉项目的目录树结构.<br><br>120.项目的源代码远不只是编译后可以获得可执行程序的计算机语言指令; 一个项目的源码树一般还包括规格说明|最终用户和开发人员文档|<br><br>测试脚本|多媒体资源|编译工具|例子|本地化文件|修订历史|安装过程和许可信息.<br><br>121.大型项目的编译过程一般声明性地借助依赖关系来说明. 依赖关系由工具程序, 如make及其派生程序, 转换成具体的编译行动.<br><br>122.大型项目中, 制作文件常常由配置步骤动态地生成; 在分析制作文件之前, 需要先执行项目特定的配置.<br><br>123.检查大型编译过程的各个步骤时, 可以使用make程序的-n开关进行预演.<br><br>124.修订控制系统提供从储存库中获取源代码最新版本的方式.<br><br>125.可以使用相关的命令, 显示可执行文件中的修订标识关键字, 从而将可执行文件与它的源代码匹配起来.<br><br>126.使用修订日志中出现的bug跟踪系统内的编号, 可以在bug跟踪系统的数据库中找到有关的问题的说明.<br><br>127.可以使用修订控制系统的版本储存库, 找出特定的变更是如何实现的.<br><br>128.定制编译工具用在软件开发过程的许多方面, 包括配置|编译过程管理|代码的生成|测试和文档编制.<br><br>129.程序的调试输出可以帮助我们理解程序控制流程和数据元素的关键部分.<br><br>130.跟踪语句所在的地点一般也是算法运行的重要部分.<br><br>131.可以用断言来检验算法运作的步骤|函数接收的参数|程序的控制流程|底层硬件的属性和测试用例的结果.<br><br>132.可以使用对算法进行检验的断言来证实您对算法运作的理解, 或将它作为推理的起点.<br><br>133.对函数参数和结果的断言经常记录了函数的前置条件和后置条件.<br><br>134.我们可以将测试整个函数的断言作为每个给定函数的规格说明.<br><br>135.测试用例可以部分地代替函数规格说明.<br><br>136.可以使用测试用例的输入数据对源代码序列进行预演.<br><br><br><br>+++++++++++++++++++<br><br>第七章: 编码规范和约定<br><br>+++++++++++++++++++<br><br><br><br>137.了解了给定代码库所遵循的文件组织方式后, 就能更有效率地浏览它的源代码.<br><br>138.阅读代码时, 首先要确保您的编辑器或优美打印程序的tab设置, 与代码遵循的风格规范一致.<br><br>139.可以使用代码块的缩进, 快速地掌握代码的总体结构.<br><br>140.对编排不一致的代码, 应该立即给予足够的警惕.<br><br>141.分析代码时, 对标记为XXX, FIXME和TODO的代码序列要格外注意: 错误可能就潜伏在其中.<br><br>142.常量使用大写字母命名, 单词用下划线分隔.<br><br>143.在遵循Java编码规范的程序中, 包名(package name)总是从一个顶级的域名开始(例如, org, com), 类名和接口名由大写字母开始, 方法<br><br>和变量名由小写字母开始.<br><br>144.用户界面控件名称之前的匈牙利记法的前缀类型标记可以帮助我们确定它的作用.<br><br>145.不同的编程规范对可移植构造的构成有不同的主张.<br><br>146.在审查代码的可移植性, 或以某种给定的编码规范作为指南时, 要注意了解规范对可移植性需求的界定与限制.<br><br>147.如果GUI功能都使用相应的编程结构来实现, 则通过代码审查可以轻易地验证给定用户界面的规格说明是否被正确地采用.<br><br>148.了解项目编译过程的组织方式与自动化方式之后, 我们就能够快速地阅读与理解对应的编译规则.<br><br>149.当检查系统的发布过程时, 常常可以将相应发行格式的需求作为基准.<br><br>&amp;&lt;60;<br>&amp;&lt;60; <br>++++++++++++<br><br>第八章： 文档<br><br>++++++++++++<br><br><br><br>150.阅读代码时, 应该尽可能地利用任何能够得到的文档.<br><br>151.阅读一小时代码所得到的信息只不过相当于阅读一分钟文档.<br><br>152.使用系统的规格说明文档, 了解所阅读代码的运行环境.<br><br>153.软件需求规格说明是阅读和评估代码的基准.<br><br>154.可以将系统的设计规格说明作为认知代码结构的路线图, 阅读具体代码的指引.<br><br>155.测试规格说明文档为我们提供可以用来对代码进行预演的数据.<br><br>156.在接触一个未知系统时, 功能性的描述和用户指南可以提供重要的背景信息,从而更好地理解阅读的代码所处的上下文.<br><br>157.从用户参考手册中, 我们可以快速地获取, 应用程序在外观与逻辑上的背景知识, 从管理员手册中可以得知代码的接口|文件格式和错误消<br><br>息的详细信息.<br><br>158.利用文档可以快捷地获取系统的概况, 了解提供特定特性的代码.<br><br>159.文档经常能够反映和提示出系统的底层结构.<br><br>160.文档有助于理解复杂的算法和数据结构.<br><br>161.算法的文字描述能够使不透明(晦涩, 难以理解)的代码变得可以理解.<br><br>162.文档常常能够阐明源代码中标识符的含义.<br><br>163.文档能够提供非功能性需求背后的理论基础.<br><br>164.文档还会说明内部编程接口.<br><br>165.由于文档很少像实际的程序代码那样进行测试, 并受人关注, 所以它常常可能存在错误|不完整或过时.<br><br>166.文档也提供测试用例, 以及实际应用的例子.<br><br>167.文档常常还会包括已知的实现问题或bug.<br><br>168.环境中已知的缺点一般都会记录在源代码中.<br><br>169.文档的变更能够标出那些故障点.<br><br>170.对同一段源代码重复或互相冲突的更改, 常常表示存在根本性的设计缺陷, 从而使得维护人员需要用一系列的修补程序来修复.<br><br>171.相似的修复应用到源代码的不同部分, 常常表示一种易犯的错误或疏忽, 它们同样可能会在其他地方存在.<br><br>172.文档常常会提供不恰当的信息, 误导我们对源代码的理解.<br><br>173.要警惕那些未归档的特性: 将每个实例归类为合理|疏忽或有害, 相应地决定是否应该修复代码或文档.<br><br>174.有时, 文档在描述系统时, 并非按照已完成的实现, 而是系统应该的样子或将来的实现.<br><br>175.在源代码文档中, 单词gork的意思一般是指&#8221;理解&#8221;.<br><br>176.如果未知的或特殊用法的单词阻碍了对代码的理解, 可以试着在文档的术语表(如果存在的话)|New Hacker&#8217;s Dictionary[Ray96]|或在<br><br>Web搜索引擎中查找它们.<br><br>177.总是要以批判的态度来看待文档, 注意非传统的来源, 比如注释|标准|出版物|测试用例|邮件列表|新闻组|修订日志|问题跟踪数据库|营<br><br>销材料|源代码本身.<br><br>178.总是要以批判的态度来看待文档; 由于文档永远不会执行, 对文档的测试和正式复查也很少达到对代码的同样水平, 所以文档常常会误导<br><br>读者, 或者完全错误.<br><br>179.对于那些有缺陷的代码, 我们可以从中推断出它的真实意图.<br><br>180.在阅读大型系统的文档时, 首先要熟悉文档的总体结构和约定.<br><br>181.在对付体积庞大的文档时, 可以使用工具, 或将文本输出到高品质输出设备上, 比如激光打印机, 来提高阅读的效率.<br><br><br><br>++++++++++++++<br><br>第九章: 系统构架<br><br>++++++++++++++<br><br><br><br>182.一个系统可以(在重大的系统中也确实如此)同时出多种不同的构架类型. 以不同的方式检查同一系统|分析系统的不同部分|或使用不同级<br><br>别的分解, 都有可能发现不同的构架类型.<br><br>183.协同式的应用程序, 或者需要协同访问共享信息或资源的半自治进程, 一般会采用集中式储存库构架.<br><br>184.黑板系统使用集中式的储存库, 存储非结构化的键/值对, 作为大量不同代码元件之间的通信集线器.<br><br>185.当处理过程可以建模|设计和实现成一系列的数据变换时, 常常会使用数据流(或管道—过滤器)构架.<br><br>186.在批量进行自动数据处理的环境中, 经常会采用数据流构架, 在对数据工具提供大量支持的平台上尤其如此.<br><br>187.数据流构架的一个明显征兆是: 程序中使用临时文件或流水线(pipeline)在不同进程间进行通信.<br><br>188.使用图示来建模面向对象构架中类的关系.<br><br>189.可以将源代码输入到建模工具中, 逆向推导出系统的构架.<br><br>190.拥有大量同级子系统的系统, 常常按照分层构架进行组织.<br><br>191.分层构架一般通过堆叠拥有标准化接口的软件组件来实现.<br><br>192.系统中每个层可以将下面的层看作抽象实体, 并且(只要该层满足它的需求说明)不关心上面的层如何使用它.<br><br>193.层的接口既可以是支持特定概念的互补函数族, 也可以是一系列支持同一抽象接口不同底层实现的可互换函数.<br><br>194.用C语言实现的系统, 常常用函数指针的数组, 表达层接口的多路复用操作.<br><br>195.用面向对象的语言实现的系统, 使用虚方法调用直接表达对层接口的多嘴复用操作.<br><br>196.系统可以使用不同的|独特的层次分解模型跨各种坐标轴进行组织.<br><br>197.使用程序切片技术, 可以将程序中的数据和控制之间依赖关系集中到一起.<br><br>198.在并发系统中, 一个单独的系统组件起到集中式管理器的作用, 负责启动|停止和协调其他系统进程和任务的执行.<br><br>199.许多现实的系统都会博采众家之长. 当处理此类系统时, 不要徒劳地寻找无所不包的构架图; 应该将不同构架风格作为独立但相关的实体<br><br>来进行定位|识别并了解.<br><br>200.状态变迁图常常有助于理清状态机的动作.<br><br>201.在处理大量的代码时, 了解将代码分解成单独单元的机制极为重要.<br><br>202.大多数情况下, 模块的物理边界是单个文件|组织到一个目录中的多个文件或拥有统一前缀的文件的集合.<br><br>203.C中的模块, 由提供模块公开接口的头文件和提供对应实现的源文件组成.<br><br>204.对象的构造函数经常用来分配与对象相关的资源, 并初始化对象的状态. 函数一般用来释放对象在生命期中占用的资源.<br><br>205.对象方法经常使用类字段来存储控制所有方法运作的数据(比如查找表或字典)或维护类运作的状态信息(例如, 赋给每个对象一个标识符的<br><br>计数器).<br><br>206.在设计良好的类中, 所有的字段都应在声明为private, 并用公开的访问方法提供对它们的访问.<br><br>207.在遇到friend声明时, 要停下来分析一下, 看看绕过类封装在设计上的理由.<br><br>208.可以有节制地用运算符增强特定类的可用性, 但用运算符重载, 将类实现为拥有内建算术类型相关的全部功能的类实体, 是不恰当的.<br><br>209.泛型实现不是在编译期间通过宏替换或语言所支持的功能(比如C++模板和Ada的泛型包)来实现, 就是在运行期间通过使用数据元素的指针<br><br>和函数的指针|或对象的多态性实现.<br><br>210.抽象数据类型经常用来封装常用的数据组织方案(比如树|列表或栈), 或者对用户隐藏数据类型的实现细节.<br><br>211.使用库的目的多种多样: 重用源代码或目标代码, 组织模块集合, 组织和优化编译过程, 或是用来实现应用程序各种特性的按需载入.<br><br>212.大型的|分布式的系统经常实现为许多互相协作的进程.<br><br>213.对于基于文本的数据储存库, 可以通过浏览存储在其中的数据, 破译出它的结构.<br><br>214.可以通过查询数据字典中的表, 或使用数据库专有的SQL命令, 比如show table, 来分析关系型数据库的模式.<br><br>215.识别出重用的构架元素后, 可以查找其最初的描述, 了解正确地使用这种构架的方式, 以及可能出现的误用.<br><br>216.要详细分析建立在某种框架之上的应用程序, 行动的最佳路线就是从研究框架自身开始.<br><br>217.在阅读向导生成的代码时, 不要期望太高, 否则您会感到失望.<br><br>218.学习几个基本的设计模式之后, 您会发现, 您查看代码构架的方式会发生改变: 您的视野和词汇将会扩展到能够识别和描述许多通用的形<br><br>式.<br><br>219.频繁使用的一些模式, 但并不显式地指出它们的名称, 这是由于构架性设计的重用经常先于模式的形成.<br><br>220.请试着按照底层模式来理解构架, 即使代码中并没有明确地提及模式.<br><br>221.大多数解释器都遵循类似的处理构架, 围绕一个状态机进行构建, 状态机的操作依赖于解释器的当前状态|程序指令和程序状态.<br><br>222.多数情况下, 参考构架只是为应用程序域指定一种概念性的结构, 具体的实现并非必须遵照这种结构.<br><br><br>+++++++++++++++++<br><br>第十章: 代码阅读工具<br><br>+++++++++++++++++<br><br><br><br>223.词汇工具可以高效地在一个大代码文件中或者跨多个文件查找某种模式.<br><br>224.使用程序编辑器和正则表达式查找命令, 浏览庞大的源代码文件.<br><br>225.以只读方式浏览源代码文件.<br><br>226.使用正则表达式 ^function name 可以找出函数的定义.<br><br>227.使用正则表达式的字符类, 可以查找名称遵循特定模式的变量.<br><br>228.使用正则表达式的否定字符类, 可以避免非积极匹配.<br><br>229.使用正则表达式 symbol-1. *symbol-2, 可以查找出现在同一行的符号.<br><br>230.使用编辑器的 tags 功能, 可以快速地找出实体的定义.<br><br>231.可以用特定的 tag 创建工具, 增加编辑器的浏览功能.<br><br>232.使用编辑器的大纲视图, 可以获得源代码结构的鸟瞰图.<br><br>233.使用您的编辑器来检测源代码中圆括号|方括号和花括号的匹配.<br><br>234.使用 grep 跨多个文件查找代码模式.<br><br>235.使用 grep 定位符号的声明|定义和应用.<br><br>236.当您不能精确地表述要查找的内容时, 请使用关键单词的词干对程序的源代码进行查找.<br><br>237.用 grep 过滤其他工具生成的输出, 分离出您要查找的项.<br><br>238.将 grep 的输出输送到其他工具, 使复杂处理任务自动化.<br><br>239.通过对 grep 的输出进行流编辑, 重用代码查找的结果.<br><br>240.通过选取与噪音模式不匹配的输出行(grep-v), 过滤虚假的 grep 输出.<br><br>241.使用 fgrep 在源代码中查找字符串列表.<br><br>242.查找注释, 或标识符大小写不敏感的语言编写的代码时, 要使用大小写不敏感的模式匹配(grep -i).<br><br>243.使用 grep &#8211;n 命令行开关, 可以创建与给定正则表达式匹配的文件和行号的检查表.<br><br>244.可以使用 diff 比较文件或程序不同版本之间的差别.<br><br>245.在运行 diff 命令时, 可以使用 diff &#8211;b, 使文件比较算法忽略结尾的空格, 用 &#8211;w 忽略所有空白区域的差异, 用 &#8211;i 使文件比较对大<br><br>小写不敏感.<br><br>246.不要对创建自己的代码阅读工具心存畏惧.<br><br>247.在构建自己的代码阅读工具时: 要充分利用现代快速原型语言所提供的能力; 从简单开始, 根据需要逐渐改进; 使用利用代码词汇结构的<br><br>各种试探法; 要允许一些输出噪音或寂静(无关输出或缺失输出); 使用其他工具对输入进行预处理, 或者对输出进行后期处理.<br><br>248.要使编译器成为您的: 指定恰当级别的编译器警告, 并小心地评估生成的结果.<br><br>249.使用C预处理器理清那些滥用预处理器特性的程序.<br><br>250.要彻底地了解编译器如何处理特定的代码块, 需要查看生成的符号(汇编)代码.<br><br>251.通过分析相应目标文件中的符号, 可以清晰地了解源文件的输入和输出.<br><br>252.使用源代码浏览器浏览大型的代码集合以及对象类型.<br><br>253.要抵制住按照您的编码规范对外部代码进行美化的诱惑; 不必要的编排更改会创建不同的代码, 并妨碍工作的组织.<br><br>254.优美打印程序和编辑器语法着色可以使得程序的源代码为易读.<br><br>255.cdecl 程序可以将难以理解的C和C++类型声明转换成纯英语(反之亦然).<br><br>256.实际运行程序, 往往可以更深刻地理解程序的动作.<br><br>257.系统调用|事件和数据包跟踪程序可以增进对程序动作的理解.<br><br>258.执行剖析器可以找出需要着重优化的代码, 验证输入数据的覆盖性, 以及分析算法的动作.<br><br>259.通过检查从未执行的代码行, 可以找出测试覆盖的弱点, 并据此修正测试数据.<br><br>260.要探究程序动态动作时的每个细节, 需要在调试器中运作它.<br><br>261.将您觉得难以理解的代码打印到纸上.<br><br>262.可以绘制图示来描绘代码的动作.<br><br>263.可以试着向别人介绍您在阅读的代码, 这样做一般会增进您对代码的理解.<br><br>264.理解复杂的算法或巧妙的数据结构, 要选择一个安静的环境, 然后聚精会神地考虑, 不要借助于任何计算机化或自动化的帮助.<br><br><br><br>+++++++++++++++++++++<br><br>第十一章: 一个完整的例子<br><br>+++++++++++++++++++++<br><br><br><br>265.模仿软件的功能时, 要依照相似实体的线路(类|函数|模块). 在相似的现有实体中, 为简化对源代码库的文本查找, 应选取比较罕见的名<br><br>称.<br><br>266.自动生成的文件常常会在文件的开关有一段注释, 说明这种情况.<br><br>267.如果试图精确地分析代码, 一般会陷入数量众多的类|文件和模块中, 这些内容会很快将我们淹没; 因此, 我们必须将需要理解的代码限定<br><br>在绝对必需的范围之内.<br><br>268.采用一种广度优先查找策略, 从多方攻克代码阅读中存在的问题, 进到找出克服它们的方法为止. <br></p>
<img src ="http://www.blogjava.net/morphis/aggbug/124397.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-06-14 23:05 <a href="http://www.blogjava.net/morphis/archive/2007/06/14/124397.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【ZZ】永远不要因为工作不好而辞职</title><link>http://www.blogjava.net/morphis/archive/2007/06/10/123172.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Sun, 10 Jun 2007 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/06/10/123172.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/123172.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/06/10/123172.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/123172.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/123172.html</trackback:ping><description><![CDATA[<p><font color=#ffff00>永远不要因为这个工作不好而辞职。一定要因为另一个工作更好而辞职。</font> </p>
<p><font color=#ffff00>&nbsp; &nbsp;&nbsp;人所拥有的「最后的」（last）自由是，我们可以选择我们的态度。</font>
<p>&nbsp;&nbsp;&nbsp; 有一位老人，独自住在家里。他的儿女轮流回来照顾他。后来觉得最好还是住到老人院去比较好，因为他的眼睛已经完全看不见了。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;迁入老人院的那一天，服务员牵着他的手告诉他，房间的样子，墙上的壁画，窗户外面是一大片草地，还有水池，这位老人回答说，真的好美，我想我在这里会很开心。服务员瞪着他，一脸讶异的说，你什么都看不见，你怎么知道美不美呢？&nbsp;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;讲到这里，你大概已经知道这故事想要说的是什么了？&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;我们比那位老人的情况好多了。我们每天早上起来的时候有没有这么振奋，这么积极？&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;办公室里的事好像永远都做不完。烦恼的事不知道为什么总是那么多。房子、车子、小孩的学业，今天的早饭该吃什么，这些事从未间断过，就待会儿出门，从车子开出去到抵达停车场，至少会发三次火：有人换车道没打信号灯；某段路塞车因为有人在路边并排停车；再有就是乱按喇叭。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;想到这里，怪不得我们真的要做一选择。选择今天我要找到美好的事，还是要专注于烦恼的事。我们要选择感恩、宽容，抑或是要让抱怨、愤怒来折磨我。我们甚至可以在今天选择关心他人，对他人感兴趣的机会，而不要让冷漠习惯性的在心头。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;30年前，我对当时的工作非常不满，时常抱怨，也多次口头叫嚷要辞职。有一天一位其它部门的年长主管跟我说，永远不要因为这个工作不好而辞职，一定要因为另一个工作更好而辞职。<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;这二句话对我很重要。影响也很大。卅年后的今天，回想起来，他说的真的很有道理。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;现在的公司制度不好，下一个工作机构的体制多半也有缺陷。现在的公司不公平，谁能保证新的公司一切都很合理公道。现在的公司有派系，天知道多少公司有同样的权力斗争问题。跟现在的主管处不好，新工作的主管就一定处得好吗？&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;因而换工作不是解决办法。<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;根本的办法是改变态度。曾在集中营里住过，遭受过人类最悲惨的折磨的奥地利心理学家Victor&nbsp;Frankel就认为，人所拥有的「最后的」（last）自由是，我们可以选择我们的态度。遭遇同样的打击，有的人选择的是绝望，有的人却选择了希望。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;朋友，你选择的是什么？你准备怎样过这一天？</p>
<img src ="http://www.blogjava.net/morphis/aggbug/123172.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-06-10 12:36 <a href="http://www.blogjava.net/morphis/archive/2007/06/10/123172.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>35岁以前需要做的十件事</title><link>http://www.blogjava.net/morphis/archive/2007/06/10/123170.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Sun, 10 Jun 2007 04:26:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/06/10/123170.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/123170.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/06/10/123170.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/123170.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/123170.html</trackback:ping><description><![CDATA[<p>35岁是青春的后期，35岁以后是收获的季节，如果你没有资格说这句话，你将会憎恨自己。所以在35岁以前，在烂漫蓬勃的青春年华里，你最好把下面十件事做好： <br>　　<br>　　第一，学会本行业所需要的一切知识并有所发展。已故零件大王布鲁丹在他35岁时，已经成为零件行业的领袖，并且组建了年收入达千万美元的海湾与西部工业公司。每个人在年轻时都可能有过彻夜不眠、刻苦攻读，这在20岁甚或30岁都没有问题，但到了35岁，就不应该再为学习基本技能而大伤脑筋了。35岁之前是一个人从事原始积累的阶段，35岁之后就应该勃发了。 <br>　　<br>　　第二，养成个人风格。在35岁以前，找出你所喜欢的，不论是衣着或是爱好，哪怕是与众不同的小习惯也好。20岁、30岁时你可以不断尝试、不断改变，但是到了35岁，你便要明确地建立个人风格。一位男士或女士在事业中途改变自己的形象，就会让人觉得很不可靠。你喜欢穿西装吗？好！就把西装当作你的商标吧！办公桌上摆些鲜花会令你工作更有效率吗？那就每天都摆些鲜花吧！ <br>　　<br>　　第三，在感情生活方面平和安定。在攀登事业的高峰时，如果私人生活不愉快，陷入感情危机，对你会产生很大的干扰，甚至会逐渐令你对别的事物失去兴趣。那些在35岁之前私人生活已经平和安定的人，一般都比生活动荡不安的人有更大的机会获得成功。因此，如果你想结束一段没有结果的恋情，或者你想和女友结婚，那就赶快行动吧，免得把问题拖到生命的第35个春秋。在35岁以后，你应该专注地看着你对事业的投资开始获利。 <br>　　<br>　　第四，明白自己的短处。承认有些事情你的确做不好，或者不愿做。如果你讨厌数字而喜欢创作，那就不要因为待遇高或顺从别人的期望而强迫自己做数字工作。在35岁之前，一定要投入你所喜爱、所擅长的那种工作。否则，35岁之后必然会有一段郁郁不乐的曰子。而且，真正的成功可能因为活力的消退而丧失。 <br>　　<br>　　第五，知道自己的长处。你应该知道自己擅长什么，并且清楚你所喜欢做而又做得比别人好的事情。不管你目前担任什么样的角色，知道自己的长处对成功都很重要。 <br>　　<br>　　第六，储备辞职另谋生路的钱。在这个多变的职业世界里，你也许不会永远在一个地方工作，或者永远在一个位置上淋漓尽致地发挥自己，当你感到无法施展时，你很可能会想到辞职，或者开辟第二职业，如果你事先储蓄了足够的钱，你便有了一个安全的后盾。 <br>　　<br>　　第七，建立人际关系网。如果到了35岁你仍未建立起牢固的人际关系网，那你就有麻烦了。这个人际关系网包括你的朋友、亲人，最低限度包括所有可以互相帮助的人。这些人有的是你的同事，有的受过你的恩惠，有的你倾听过他们的问题，有的你和他有着相同的爱好。人际关系网不是一朝一夕就能建立起来的，它需要几年甚至十几年的培养。一个人在事业上、生活上的成功其实如同一个政党的成功，你要有许多人散布在适当的地方，你可以依赖他们，他们也可以依赖你。 <br>　　<br>　　第八，学会授权他人。许多人不肯或不能这样做，因此始终被钉在从属的职位上。授权他人是成功的一半，一个事无巨细，不能将工作授权别人的人，注定会遇到极大的障碍。到了35岁，你最好已成为这方面的专家。换言之，你懂得挑选合适的人并信任他们。 <br>　　<br>　　第九，学会在什么时候三缄其口。因说话不小心而自毁前程的人，比因为任何其他原因丧失成功的人都多。要学会保持沉默而且看起来机智--别人自然以为你知道的比实际还多。别讲别人的闲话，别谈论你自己的大计，守口如瓶所赢得的声誉，远比讲人闲话所带来的东西更加珍贵。你在事业上越成功，这一点就越重要。 <br>　　<br>　　第十，对人要忠诚。如果你到了35岁仍未能建立起坚如磐石的忠诚信誉，这一缺点将会困扰你一生。不忠诚的恶名必然会使你在事业上到处不受欢迎。你不能靠暗箭伤人爬到事业的顶峰，而要靠在早期树立起来的真诚刚直和不可动摇的声誉。35岁以前，忠诚只是投资；35岁以后，你会作为一个可以信赖的人收到忠诚的回报。 </p>
<img src ="http://www.blogjava.net/morphis/aggbug/123170.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-06-10 12:26 <a href="http://www.blogjava.net/morphis/archive/2007/06/10/123170.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转贴】泛型算法：Tips </title><link>http://www.blogjava.net/morphis/archive/2007/06/06/122292.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Wed, 06 Jun 2007 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/06/06/122292.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/122292.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/06/06/122292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/122292.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/122292.html</trackback:ping><description><![CDATA[<p><br>从 STL 出现到现在已经这么多年了，泛型算法是它的重要组成，也是其中最&#8220;看起来很美&#8221;的东西之一。然而在真实的程序设计中，它往往成为程序员的心头一痛，因为一旦要用 for_each ，accumulate 之类的算法做一些稍微复杂一点的事情，你就会发现自己一个头变成两个大。</p>
<p>从 STL 出现到现在已经这么多年了，泛型算法是它的重要组成，也是其中最&#8220;看起来很美&#8221;的东西之一。然而在真实的程序设计中，它往往成为程序员的心头一痛，因为一旦要用 for_each ，accumulate 之类的算法做一些稍微复杂一点的事情，你就会发现自己一个头变成两个大。即便是有了 boost::bind 和 boost.lambda 的帮助，事情也仍然是扑朔迷离，求助于 comp.lang.c++ 虽然有用，但是又何尝不是一种无奈。好了，现在我开始收集一些来自 comp.lang.c++(.moderated) 的解答，希望日后对自己和他人有用。</p>
<p>=================================================================================</p>
<p>预备问题（算是第0个问题吧）：如何对一个 STL 容器内的所有元素做某件事情？</p>
<p>这取决于你要做什么，以及容器是什么。如果是 vector, list 这样的容器，而你要把它们全部 cout 出来，当前的标准 STL 解法是这样的：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;vector&gt;<br>#include &lt;iterator&gt;<br>#include &lt;string&gt;</p>
<p>int main()<br>{<br>&nbsp; std::vector&lt;std::string&gt; vect;<br>&nbsp; vect.push_back("Hello");<br>&nbsp; vect.push_back(", ");<br>&nbsp; vect.push_back("world!");<br>&nbsp; <br>&nbsp; std::copy( vect.begin(), vect.end(), <br>&nbsp;&nbsp;&nbsp; std::ostream_iterator&lt;std::string&gt;(std::cout) );<br>}</p>
<p>基本上，这算是一个&#8220;过得去&#8221;的方案，但是有点问题：<br>1. 对于不熟悉这个固定用法的人，cout 所有元素所首要考虑算法是 for_each，而不是 copy ，事实上，for_each 也是最符合我们惯常逻辑的算法，因为在不使用 STL 算法的时候，我们使用 for 循环来干这件事。<br>2. 可读性不太良好，ostream_iterator 的使用有点 tricky ，而且也不能用于做其他的事情。</p>
<p>我想熟悉 boost&nbsp; 的人已经知道我下面要说什么了，因为用 boost.lambda 做这件事情的确非常漂亮：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;vector&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/lambda/lambda.hpp&gt;<br>#include &lt;boost/lambda/bind.hpp&gt;</p>
<p>using namespace boost::lambda;</p>
<p>int main()<br>{<br>&nbsp; std::vector&lt;std::string&gt; vect;<br>&nbsp; vect.push_back("Hello");<br>&nbsp; vect.push_back(", ");<br>&nbsp; vect.push_back("world!");<br>&nbsp; <br>&nbsp; std::for_each( vect.begin(), vect.end(), std::cout &lt;&lt; _1 );<br>}</p>
<p>这和前面的程序一样，输出我们熟悉的 Hello, world! 。直观、优雅而且容易修改，例如，如果你不是想要输出它们的值，而是想要输出它们的长度，只需要做很少的修改：</p>
<p>std::for_each( vect.begin(), vect.end(), std::cout &lt;&lt; bind(&amp;std::string::length, _1) &lt;&lt; "\n" );</p>
<p>输出<br>5<br>2<br>6</p>
<p>bind 的作用是把 lambda 表达式绑定到一个函数或者一个数据成员，在这里的意思，就是对于每一个 string ，都调用其 length() 方法。_1 同样也可以成为赋值的对象，例如，先执行</p>
<p>std::for_each( vect[0].begin(), vect[0].end(), _1 = bind(&amp;toupper, _1) );</p>
<p>然后再把这些 string 输出，你会得到</p>
<p>HELLO, world!</p>
<p>因为那一句对 "Hello" 中的每一个字母调用 toupper ，并把结果写回。</p>
<p>=================================================================================</p>
<p>第一个问题：如何对一个 map 中所有的 key 或者 value 做某件事情？</p>
<p>当然，这还是取决于你要做的是什么。手写 for 循环当然是万能的，但是现在有了那么多的泛型算法，我们可以考虑其他的方案了（这也是众多 C++ Gurus 推荐的思维方式）如果是把所有的 value 全部 cout 出来，用 boost.lambda 配合 for_each 还是比较优雅的（虽然没有像 vector 和 list 那样的优雅）：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;map&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/lambda/lambda.hpp&gt;<br>#include &lt;boost/lambda/bind.hpp&gt;</p>
<p>using namespace boost::lambda;</p>
<p>int main()<br>{<br>&nbsp; std::map&lt;int, std::string&gt; strs;<br>&nbsp; strs[0] = "Hello";<br>&nbsp; strs[1] = ", ";<br>&nbsp; strs[2] = "world";<br>&nbsp; strs[3] = "!";<br>&nbsp; <br>&nbsp; std::for_each( strs.begin(), strs.end(), <br>&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; bind(&amp;std::map&lt;int, std::string&gt;::value_type::second, _1) );<br>}</p>
<p>这样的输出如我们所料，就是 Hello, world! 。</p>
<p>如果想要把 key 也输出，道理是一样的，只需要这样：</p>
<p>&nbsp; std::for_each( strs.begin(), strs.end(), <br>&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; bind(&amp;std::map&lt;int, std::string&gt;::value_type::second, _1) &lt;&lt; '\t'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; bind(&amp;std::map&lt;int, std::string&gt;::value_type::first, _1) &lt;&lt; '\n'<br>&nbsp; );</p>
<p>其结果是：</p>
<p>Hello&nbsp;&nbsp; 0<br>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<br>world&nbsp;&nbsp; 2<br>!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3</p>
<p>因此，对于一个 map 中的 value 的操作往往可以依法炮制，如果我们想要在其中寻找 value 为 &#8220;world" 的那一个元素，并且输出它的 key ，只需要一句话：</p>
<p>&nbsp; std::cout &lt;&lt; <br>&nbsp;&nbsp;&nbsp; std::find_if( strs.begin(), strs.end(), <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bind(&amp;std::map&lt;int, std::string&gt;::value_type::second, _1) == "world" )-&gt;first;</p>
<p>STL 算法 find_if 接受的第三个参数是一个 prediate ，而生成这种临时的 functor 正是 lambda 的拿手好戏。上面的这句话也可以用 boost::bind 来做，只需要更改 include 和 using namespace ，代码本身无需更改。而如果你不借助于它们，你只有手写循环或者自己写一个 predicate 。</p>
<p>当情况变得复杂一些的时候，lambda 的用法也变得更加有趣了：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;map&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/lambda/lambda.hpp&gt;<br>#include &lt;boost/lambda/bind.hpp&gt;</p>
<p>using namespace boost::lambda;</p>
<p>class Person<br>{<br>public:<br>&nbsp; Person(){}<br>&nbsp; Person(const std::string&amp; name) : name_(name){}<br>&nbsp; <br>&nbsp; std::string Name()<br>&nbsp; { return name_; }<br>&nbsp; <br>private:<br>&nbsp; std::string name_;<br>};</p>
<p>int main()<br>{<br>&nbsp; std::map&lt;int, Person&gt; persons;<br>&nbsp; persons[123] = Person("Amy");<br>&nbsp; persons[234] = Person("Ralph");<br>&nbsp; persons[345] = Person("Simon");<br>&nbsp; persons[456] = Person("Maggie");</p>
<p>&nbsp; std::for_each( persons.begin(), persons.end(), <br>&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; bind(&amp;std::map&lt;int, Person&gt;::value_type::first, _1) &lt;&lt; '\t'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; bind(&amp;Person::Name, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bind(&amp;std::map&lt;int, Person&gt;::value_type::second, _1)) &lt;&lt; '\n'<br>&nbsp; );</p>
<p>&nbsp; std::cout &lt;&lt; "Ralph's Id is: " &lt;&lt;<br>&nbsp;&nbsp;&nbsp; std::find_if( persons.begin(), persons.end(), <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bind(&amp;Person::Name, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bind(&amp;std::map&lt;int, Person&gt;::value_type::second, _1)) == "Ralph" )-&gt;first;<br>}</p>
<p>这里 map 的 value 元素不再是一个单纯的 string，我们要输出的是这个 value 的 Name() ，幸好 lambda 的绑定可以级联，所以我们仍然可以用 STL 算法在一个表达式之内搞定这些任务：for_each 输出 key 和 value 的 Name()，而 find_if 找到 value 的 Name() 为 "Ralph" 的那一个元素，输出是这样的：</p>
<p>123&nbsp;&nbsp;&nbsp;&nbsp; Amy<br>234&nbsp;&nbsp;&nbsp;&nbsp; Ralph<br>345&nbsp;&nbsp;&nbsp;&nbsp; Simon<br>456&nbsp;&nbsp;&nbsp;&nbsp; Maggie<br>Ralph's Id is: 234</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>如果你想要把一个容器内的所有元素累加起来，应该怎么办？ </p>
<p>如果你想要把一个容器内的所有元素累加起来，应该怎么办？</p>
<p>STL 的 accumulate 可以让我们不必自己写循环：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;functional&gt;<br>#include &lt;numeric&gt;<br>#include &lt;vector&gt;<br>#include &lt;string&gt;</p>
<p>int main()<br>{<br>&nbsp; std::vector&lt;int&gt; vect;<br>&nbsp; vect.push_back(1);<br>&nbsp; vect.push_back(2);<br>&nbsp; vect.push_back(3);<br>&nbsp; vect.push_back(4);<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; "Accumulate: " &lt;&lt;<br>&nbsp;&nbsp;&nbsp; std::accumulate( vect.begin(), vect.end(), 0, std::plus&lt;int&gt;());<br>}</p>
<p>输出：</p>
<p>Accumulate: 10</p>
<p>其中的 std::plus&lt;int&gt;() 可以省略，因为这将是3个参数的 accumulate 的默认行为。 注意 accumulate 算法是定义在 numeric 里面而不是 algorithm 里面的。</p>
<p>由于 accumulate 和 plus 都是泛型的，所以如果你要累加的不是 int 而是字符串，对程序的修改也并不大：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;functional&gt;<br>#include &lt;numeric&gt;<br>#include &lt;vector&gt;<br>#include &lt;string&gt;</p>
<p>int main()<br>{<br>&nbsp; std::vector&lt;std::string&gt; vect;<br>&nbsp; vect.push_back("1");<br>&nbsp; vect.push_back("2");<br>&nbsp; vect.push_back("3");<br>&nbsp; vect.push_back("4");<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; "Accumulate: " &lt;&lt;<br>&nbsp;&nbsp;&nbsp; std::accumulate( vect.begin(), vect.end(), std::string(""));<br>}</p>
<p>输出：<br>Accumulate: 1234</p>
<p>不过，如果使用 boost.lambda ，这个问题会有一些很好看又容易理解的解法：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;numeric&gt;<br>#include &lt;vector&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/lambda/lambda.hpp&gt;<br>#include &lt;boost/lambda/bind.hpp&gt;<br>//#include &lt;boost/bind.hpp&gt;</p>
<p>using namespace boost::lambda;<br>//using namespace boost;</p>
<p>int main()<br>{<br>&nbsp; std::vector&lt;std::string&gt; vect;<br>&nbsp; vect.push_back("1");<br>&nbsp; vect.push_back("2");<br>&nbsp; vect.push_back("3");<br>&nbsp; vect.push_back("4");<br>&nbsp; <br>&nbsp; std::string result;<br>&nbsp; <br>&nbsp; std::for_each( vect.begin(), vect.end(), result += _1);<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; result;<br>}</p>
<p>输出：<br>1234</p>
<p>这里要借用变量 result ，在这个程序中显得多了几行，但是我们调用 accumulate 的目的也往往是把结果放到一个变量中，这样的话，使用 boost.lambda 反而会漂亮一些。</p>
<p>在上面的程序中，另一个丑陋的地方就是 vector 的初始化，为了把 1, 2, 3, 4 放进 vect 里面，我们居然要调用 push_back 4次！不过，使用 boost.lambda 就好得多了。</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; int i = 0;<br>&nbsp; std::for_each( vect.begin(), vect.end(), _1 = ++var(i) );</p>
<p>这里有两个地方值得注意：<br>1. 现在必须在 vect 的声明中指出其大小，否则 for_each 对一个空容器可是什么也不会做<br>2. 必须使用 ++var(i) ，而不是 ++i 。var 在这里的作用是强迫 lazy evaluation ，也就是让变量在被用到的时候在求值，如果用 ++i ，你会得到一个装有10个1的 vect ，而不是装有1-10。</p>
<p>=================================================================================</p>
<p>许多问题遇到 map 都会变得复杂起来，如果想要把一个 map 中所有的 key 或者 value 累加起来，该怎么办呢？这个时候已经不能直接使用 accumulate 了，用 boost.bind 可以办到，做法是这样的：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;numeric&gt;<br>#include &lt;map&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/bind.hpp&gt;</p>
<p>using namespace boost;</p>
<p>int main()<br>{<br>&nbsp; std::map&lt;int, std::string&gt; persons;<br>&nbsp; persons[123] = "Amy";<br>&nbsp; persons[234] = "Ralph";<br>&nbsp; persons[345] = "Simon";<br>&nbsp; persons[456] = "Maggie";<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; std::accumulate( persons.begin(), persons.end(), 0,<br>&nbsp;&nbsp;&nbsp; bind(std::plus&lt;int&gt;(), _1, bind(&amp;std::map&lt;int, std::string&gt;::value_type::first, _2)) )<br>&nbsp;&nbsp;&nbsp; &lt;&lt; std::endl;</p>
<p>&nbsp; std::cout &lt;&lt; std::accumulate( persons.begin(), persons.end(), std::string(),<br>&nbsp;&nbsp;&nbsp; bind(std::plus&lt;std::string&gt;(), _1, bind(&amp;std::map&lt;int, std::string&gt;::value_type::second, _2)) )<br>&nbsp;&nbsp;&nbsp; &lt;&lt; std::endl;<br>}</p>
<p>输出：</p>
<p>1158<br>AmyRalphSimonMaggie</p>
<p>办是办到了，但是平心而论，的确算不上是漂亮。连续的 bind 并不比自己写的循环更让人头晕。boost.lambda 也要用到 bind ，然而可以清晰许多：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;numeric&gt;<br>#include &lt;map&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/lambda/lambda.hpp&gt;<br>#include &lt;boost/lambda/bind.hpp&gt;</p>
<p>using namespace boost::lambda;</p>
<p>int main()<br>{<br>&nbsp; std::map&lt;int, std::string&gt; persons;<br>&nbsp; persons[123] = "Amy";<br>&nbsp; persons[234] = "Ralph";<br>&nbsp; persons[345] = "Simon";<br>&nbsp; persons[456] = "Maggie";</p>
<p>&nbsp; int iresult = 0;<br>&nbsp; std::string sresult;<br>&nbsp; <br>&nbsp; std::for_each( persons.begin(), persons.end(), <br>&nbsp;&nbsp;&nbsp; iresult += bind(&amp;std::map&lt;int, std::string&gt;::value_type::first, _1)<br>&nbsp; );<br>&nbsp; <br>&nbsp; std::for_each( persons.begin(), persons.end(),<br>&nbsp;&nbsp;&nbsp; sresult += bind(&amp;std::map&lt;int, std::string&gt;::value_type::second, _1)<br>&nbsp; );<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; iresult &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; sresult &lt;&lt; std::endl;<br>}</p>
<p>输出和上面的一样：</p>
<p>1158<br>AmyRalphSimonMaggie</p>
<p>有了它的帮助，即便间接层次再增加一层，也不会有太多困难：假如你的 map 并不直接存储 string ，而是存储 Person 对象，而它们的名字要通过 Name() 方法来取得，代码只需要稍微的修改：</p>
<p><br>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;numeric&gt;<br>#include &lt;map&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/lambda/lambda.hpp&gt;<br>#include &lt;boost/lambda/bind.hpp&gt;</p>
<p>using namespace boost::lambda;</p>
<p>class Person<br>{<br>public:<br>&nbsp; Person(){}<br>&nbsp; Person(const std::string&amp; name) : name_(name){}<br>&nbsp; <br>&nbsp; std::string&amp; Name()<br>&nbsp; { return name_; }<br>&nbsp; <br>private:<br>&nbsp; std::string name_;<br>};</p>
<p>int main()<br>{<br>&nbsp; std::map&lt;int, Person&gt; persons;<br>&nbsp; persons[123] = Person("Amy");<br>&nbsp; persons[234] = Person("Ralph");<br>&nbsp; persons[345] = Person("Simon");<br>&nbsp; persons[456] = Person("Maggie");</p>
<p>&nbsp; std::string result;<br>&nbsp; <br>&nbsp; std::for_each( persons.begin(), persons.end(), <br>&nbsp;&nbsp;&nbsp; result += bind(&amp;Person::Name, bind(&amp;std::map&lt;int, Person&gt;::value_type::second, _1))<br>&nbsp; );<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; result;<br>}</p>
<p>输出：</p>
<p>AmyRalphSimonMaggie</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br>上次提到过为容器生成数据的问题，我给出的用 boost.lambda 的方法是</p>
<p>上次提到过为容器生成数据的问题，我给出的用 boost.lambda 的方法是：</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; int i = 0;<br>&nbsp; std::for_each( vect.begin(), vect.end(), _1 = ++var(i) );</p>
<p>不错，这样可以生成连续的数字，也还算比较简洁，因为代码量不会随着容器的大小而变化，不过，如果要在容器内填入随机数呢？其实比上面更简单，因为 STL 的 generate 算法就是设计来做这个的：</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; std::generate(vect.begin(), vect.end(), rand);</p>
<p>rand 是我们熟悉的标准 C 库函数，这样我们可以生成任意数量的随机数了，不过还是有点不好的地方：每次生成的序列都是一样的，因为 rand 生成的是伪随机数。这个容易解决，我们必须先 seed 一下：</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; srand(time(NULL));<br>&nbsp; std::generate(vect.begin(), vect.end(), rand);</p>
<p>好了，我们终于还是用了三行（其实是两行，声明 vector 总是必需的吧！），但是好歹是有了一个可用的方案。回头看看，前面的连续整数问题也可以用 generate 来做，方法不言而喻：</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; int i = 0;<br>&nbsp; std::generate(vect.begin(), vect.end(), ++var(i));</p>
<p>好处是 generate 本身更能说明这句话的用途，当然这个可能因人而异。</p>
<p>我知道有人一定在问：一定要两行么？一定要有一个初始变量么？答案是可以没有，但是要用到另外的算法，再加上 boost.lambda 的协助。看看下面：</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = _1 + 1);</p>
<p>如果你现在把 vect 输出，你会得到：</p>
<p>0 1 2 3 4 5 6 7 8 9</p>
<p>乍看起来不太好理解，我来慢慢解释。<br>partial_sum 的第4个参数是一个双参数的 functor ，在这里，lambda 表达式 _2 = _1 + 1 充当了这个角色，它相当于</p>
<p>&nbsp;</p>
<p>f(x, y)&nbsp; {&nbsp; y&nbsp; =&nbsp; x&nbsp; +&nbsp; 1;&nbsp; } </p>
<p><br>而 partial_sum 呢？它把一个序列的 partial sum 送到结果序列中去，例如如果输入一个数组 v[10] ，而输出是 r[10] ，那么它的计算就是</p>
<p><br>r[0] = v[0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>r[1] = f( r[0], r[1] ) <br>r[2] = f( r[1], r[2] ) <br>...... <br>r[9] = f( r[8], r[9] ) </p>
<p><br>而当我们把 partial_sum 作用于 vect 本身，结果就成了</p>
<p><br>vect[0] = vect[0]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // vect[0] = 0 <br>vect[1] = (vect[1] = vect[0] + 1)&nbsp;&nbsp; // vect[1] = 1 <br>vect[2] = (vect[2] = vect[1] + 1)&nbsp;&nbsp; // vect[2] = 2 <br>...... <br>vect[9] = (vect[9] = vect[8] + 1)&nbsp;&nbsp; // vect[9] = 9 </p>
<p><br>你一定发现其中的问题所在了：首先，我们必须依赖于编译器把 vect[0] 初始化为0，其次，vect[0] = vect[0] 是不可回避的。以我当前所想到的，也只能这样了。</p>
<p>推广一下，如果把 _2 = _1 + 1 中的常数 1 换成另外的数字，我们就可以用一句话得到从 0 开始的等差数列，例如</p>
<p>&nbsp; std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = _1 + 3);</p>
<p>得到的是</p>
<p>0 3 6 9 12 15 18 21 24 27</p>
<p>如果再发挥一点想象力，你就可以构造出更复杂的 lambda 表达式，从而得到更复杂的数组（也许这里叫数列更好吧），例如</p>
<p>&nbsp; std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2 * _1 + 1);</p>
<p>得到的是 2 的 n 次方 - 1 数列</p>
<p>0 1 3 7 15 31 63 127 255 511</p>
<p>在 STL 算法中，adjacent_difference 和 partial_sum 是逆运算，因此，上面的事情也可以用 adjacent_difference 来做，只不过要把 lambda 表达式中的参数位置换一下，例如要得到 0, 3, 6... 的等差数列，只需要</p>
<p>&nbsp; std::adjacent_difference(vect.begin(), vect.end(), vect.begin(), _1 = _2 + 3);</p>
<p>而 2 的 n 次方 - 1 数列也是同样道理</p>
<p>&nbsp; std::adjacent_difference(vect.begin(), vect.end(), vect.begin(), _1 = 2*_2 + 1);</p>
<p>如果你要生成倒序的数列呢？当然，STL 算法 reverse 可以派上用场，不过也不要忘了 STL 还有 reverse_iterator 这回事，用它就无需另外调用 reverse 了：</p>
<p>&nbsp; std::partial_sum(vect.rbegin(), vect.rend(), vect.rbegin(), _2 = 2*_1 + 1);</p>
<p>得到</p>
<p>511 255 127 63 31 15 7 3 1 0</p>
<p>最后还要提醒大家不要忘了一个很有用的 STL 算法： random_shuffle 。它可以把 Random access container 里面的值打乱，配合上面的数列生成，在很多场合是进行测试 （例如测试排序算法） 的好工具。在我的机器上，下面两行</p>
<p>&nbsp; std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2*_1 + 1);<br>&nbsp; std::random_shuffle(vect.begin(), vect.end());</p>
<p>得到打乱以后的数列：</p>
<p>255 1 511 3 0 31 127 7 15 63</p>
<p>=================================================================================</p>
<p>有了强大的生成机制作基础，下面的实验也更加容易了。STL 的 count_if 和 find_if 都接受一个 predicate 作为比较的依据，而这个 predicate 往往非常简单，以至于为它专门写一个 functor 简直不可接受。在第一篇里面已经展示了用 boost.lambda 生成临时的无名 functor 的能力，这里再多说一点。</p>
<p>下面先生成 2^n - 1 的数组，然后找出其中第一个大于100的数</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2*_1 + 1);<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; *std::find_if(vect.begin(), vect.end(), _1 &gt; 100);</p>
<p>输出为 127 ，如我们所料。同样道理，如果是 count_if ，则会得到大于100的数的个数</p>
<p>&nbsp; std::cout &lt;&lt; std::count_if(vect.begin(), vect.end(), _1 &gt; 100);</p>
<p>输出是 3 。注意细节：find_if 返回一个 iterator ，所以在它之前有 * 解引用，而 count_if 直接返回一个数字，无需解引用。</p>
<p>与之类似的还有 STL 的 partition 算法，它根据传入的 predicate 对一个序列进行划分，predicate 得到 true 的将放在前面，其余的放在后面，返回的是那些&#8220; 放在 后面&#8221;的元素中的第一个，换言之就是分界点。下面的代码</p>
<p>&nbsp; std::vector&lt;int&gt; vect(10);<br>&nbsp; std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2*_1 + 1);<br>&nbsp; <br>&nbsp; std::cout &lt;&lt; *std::partition(vect.begin(), vect.end(), _1 &gt; 100) &lt;&lt; std::endl;<br>&nbsp; <br>&nbsp; std::for_each(vect.begin(), vect.end(), std::cout &lt;&lt; _1 &lt;&lt; " ");</p>
<p>输出为</p>
<p>7<br>511 255 127 7 15 31 63 3 1 0</p>
<p>如果仔细观察，还可以发现上面的输出有点问题：数列中原有的顺序（0, 1, 3, 7...）不复存在，这是因为 partition 并不是一个稳定排序的算法，它不保证排序结果保有原来的顺序。如果需要稳定排序，可以使用 stable_partition 。只需要更改排序的那一句代码为</p>
<p>&nbsp; std::cout &lt;&lt; *std::stable_partition(vect.begin(), vect.end(), _1 &gt; 100) &lt;&lt; std::endl;</p>
<p>结果是</p>
<p>0<br>127 255 511 0 1 3 7 15 31 63</p>
<p>当然，如果你还记得大学里的算法理论，就知道它们在效率上是有点区别的，partition 的复杂度保证为 O(n) ，具体地说是保证不超过 n/2 次交换；而 stable_partition 在最好情况下为 O(n) ，最差情况则达到 O(n*log(n)) 。</p>
<p>顺便说一下，上面的几件简单的事情，用标准的 STL 算法都可以办到，只不过实在是&#8230;&#8230;面目可憎：</p>
<p>&nbsp; std::cout &lt;&lt; *std::partition(vect.begin(), vect.end(), <br>&nbsp;&nbsp;&nbsp; std::bind2nd(std::greater&lt;int&gt;(), 100)) &lt;&lt; std::endl;</p>
<p>这句代码做的事情和前面的 partition 一模一样，但是孰优孰劣，大家自有公断。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><br>总有一些时候，我们不能够借助于&#8220;生成式&#8221;的初始化方法来给容器赋值，例如我们已经有了一个数组，要把它作为初值赋给一个容器，常规的做法已经深入人心了</p>
<p>总有一些时候，我们不能够借助于&#8220;生成式&#8221;的初始化方法来给容器赋值，例如我们已经有了一个数组，要把它作为初值赋给一个容器，常规的做法已经深入人心了：</p>
<p>&nbsp; int init[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};<br>&nbsp; std::vector&lt;int&gt; vect(init, init + sizeof(init)/sizeof(int));</p>
<p>通过两个 sizeof 来得到数组的大小在 C 语言里面是很常见的，然而在 C++ 里面，这即便不能称为丑陋，也绝对称不上是好。首先其可读性不好，其次它要进行一次除法来得到一个本来在编译期间就知道的数字，最后，它并不是总能用的！例如下面的例子：</p>
<p>&nbsp; std::string strs[] = { "Amy", "Ralph", "Simon", "Maggie" };</p>
<p>现在，你打算用 "sizeof " 什么来除以 "sizeof" 什么？</p>
<p>其实，经过了这么多 C++ GP 的磨练，我们很容易就会想到一个在编译期间得到静态数组大小的办法，模板偏特化是我们常用的武器，在这里非常好用：</p>
<p>template &lt;class T&gt;<br>struct ArraySize<br>{<br>&nbsp;&nbsp;&nbsp; static const unsigned int value = 0;<br>};</p>
<p>template &lt;class T, int S&gt;<br>struct ArraySize&lt;T[S]&gt;<br>{<br>&nbsp;&nbsp;&nbsp; static const unsigned int value = S;<br>};</p>
<p>就这么简单！虽然它只对付一维数组，但是扩展它是很容易的。不过，模板参数只能为类型，而我们需要传入的是一个变量。好在在计算机科学里面，加一层抽象是可以解决任何问题的，我们只要加一个模板函数，C++ 会自动帮我们做类型推导：</p>
<p>template &lt;class T&gt;<br>unsigned int array_size(const T&amp;)<br>{<br>&nbsp;&nbsp;&nbsp; return ArraySize&lt;T&gt;::value;<br>}</p>
<p>现在我们可以轻而易举的搞定那些数组了：</p>
<p>&nbsp; int ints[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};<br>&nbsp; std::vector&lt;int&gt; vint(ints, ints + array_size(ints));<br>&nbsp; <br>&nbsp; std::string strs[] = { "Amy", "Ralph", "Simon", "Maggie" }; <br>&nbsp; std::vector&lt;std::string&gt; vstr(strs, strs + array_size(strs));<br>&nbsp; <br>&nbsp; std::for_each(vint.begin(), vint.end(), std::cout &lt;&lt; _1 &lt;&lt; " ");<br>&nbsp; std::cout &lt;&lt; std::endl;<br>&nbsp; std::for_each(vstr.begin(), vstr.end(), std::cout &lt;&lt; _1 &lt;&lt; " ");</p>
<p>输出：</p>
<p>2 3 5 7 11 13 17 19 23<br>Amy Ralph Simon Maggie</p>
<p>顺便说一下，在 boost.type_traits 里面有一个类似于 ArraySize 的工具，叫做 extent ，它更加强大，可以对付多维数组，不过是否值得为了这个而把 boost.type_traits 包含到工程里面去就看读者自己抉择了。</p>
<p>=================================================================================</p>
<p>容器的初始化是如此的常见，以至于 boost 提供了一个 assign 库来简化这些操作。boost.assign 大量利用了重载的逗号和括号来简化赋值操作，提供了甚至比用数组更加简洁的语法：</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;vector&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/assign/std/vector.hpp&gt;<br>#include &lt;boost/assign/std/list.hpp&gt;</p>
<p>using namespace boost::assign;</p>
<p>int main()<br>{<br>&nbsp; std::vector&lt;int&gt; vint;<br>&nbsp; vint += 2,3,5,7,11,13,17,19,23;<br>&nbsp; <br>&nbsp; std::vector&lt;std::string&gt; vstr;<br>&nbsp; vstr += "Amy","Ralph","Simon","Maggie";<br>&nbsp; <br>&nbsp; std::list&lt;std::string&gt; lstr;<br>&nbsp; lstr += "Amy","Ralph","Simon","Maggie";<br>&nbsp;&nbsp;&nbsp; <br>&nbsp; std::for_each(vint.begin(), vint.end(), std::cout &lt;&lt; _1 &lt;&lt; " ");<br>&nbsp; std::cout &lt;&lt; std::endl;<br>&nbsp; std::for_each(vstr.begin(), vstr.end(), std::cout &lt;&lt; _1 &lt;&lt; " ");<br>&nbsp; std::cout &lt;&lt; std::endl;<br>&nbsp; std::for_each(lstr.begin(), lstr.end(), std::cout &lt;&lt; _1 &lt;&lt; " ");<br>}</p>
<p>运行这个程序，输出与前面的大致相同，但是我们注意到初始化更加简洁了，而且也不需要额外的空间来存储数组，对于各种类型，都能够以统一的方式来初始化，真是妙不可言。有趣的是 assign 的作者在文档中还特意引用了 Bjarne Stroustrup 的话作为引子：</p>
<p>There appear to be few practical uses of operator,(). <br>Bjarne Stroustrup, The Design and Evolution of C++</p>
<p>这也许就是 C++ 最大的魅力之一：你无法预料它可以办到些什么。</p>
<p>下面关于 map 的例子也使用 boost.assign ，可以看到重载的括号给我们带来了多少方便。</p>
<p>#include &lt;iostream&gt;<br>#include &lt;algorithm&gt;<br>#include &lt;map&gt;<br>#include &lt;string&gt;</p>
<p>#include &lt;boost/lambda/lambda.hpp&gt;<br>#include &lt;boost/lambda/bind.hpp&gt;</p>
<p>#include &lt;boost/assign/list_inserter.hpp&gt;<br>#include &lt;boost/assign/list_of.hpp&gt;</p>
<p>using namespace std;<br>using namespace boost::assign;<br>using namespace boost::lambda;</p>
<p>int main()<br>{<br>&nbsp; map&lt;string,int&gt; months;&nbsp; <br>&nbsp; <br>&nbsp; insert( months )<br>&nbsp;&nbsp;&nbsp; ( "january",&nbsp;&nbsp; 31 )( "february", 28 )<br>&nbsp;&nbsp;&nbsp; ( "march",&nbsp;&nbsp;&nbsp;&nbsp; 31 )( "april",&nbsp;&nbsp;&nbsp; 30 )<br>&nbsp;&nbsp;&nbsp; ( "may",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 31 )( "june",&nbsp;&nbsp;&nbsp;&nbsp; 30 )<br>&nbsp;&nbsp;&nbsp; ( "july",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 31 )( "august",&nbsp;&nbsp; 31 )<br>&nbsp;&nbsp;&nbsp; ( "september", 30 )( "october",&nbsp; 31 )<br>&nbsp;&nbsp;&nbsp; ( "november",&nbsp; 30 )( "december", 31 );<br>&nbsp;&nbsp;&nbsp; <br>&nbsp; map&lt;int,string&gt; persons = map_list_of<br>&nbsp;&nbsp;&nbsp; (2,"Amy")(3,"Ralph")<br>&nbsp;&nbsp;&nbsp; (5,"Simon")(7,"Maggie");<br>&nbsp;&nbsp;&nbsp; <br>&nbsp; for_each( months.begin(), months.end(),<br>&nbsp;&nbsp;&nbsp; cout &lt;&lt; bind(&amp;map&lt;string,int&gt;::value_type::second, _1) &lt;&lt; "\t"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; bind(&amp;map&lt;string,int&gt;::value_type::first, _1) &lt;&lt; "\n"<br>&nbsp; );<br>&nbsp; cout &lt;&lt; endl;<br>&nbsp; for_each( persons.begin(), persons.end(),<br>&nbsp;&nbsp;&nbsp; cout &lt;&lt; bind(&amp;map&lt;int,string&gt;::value_type::first, _1) &lt;&lt; "\t"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; bind(&amp;map&lt;int,string&gt;::value_type::second, _1) &lt;&lt; "\n"<br>&nbsp; );&nbsp; <br>}</p>
<p>输出：</p>
<p>30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; april<br>31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; august<br>31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; december<br>28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; february<br>31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; january<br>31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; july<br>30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; june<br>31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; march<br>31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; may<br>30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; november<br>31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; october<br>30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; september</p>
<p>2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Amy<br>3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ralph<br>5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Simon<br>7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Maggie<br></p>
<img src ="http://www.blogjava.net/morphis/aggbug/122292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-06-06 09:37 <a href="http://www.blogjava.net/morphis/archive/2007/06/06/122292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编译boost库-用vc2005编译boost</title><link>http://www.blogjava.net/morphis/archive/2007/06/05/122116.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Tue, 05 Jun 2007 04:45:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/06/05/122116.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/122116.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/06/05/122116.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/122116.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/122116.html</trackback:ping><description><![CDATA[<p>编译boost库-用vc2005编译boost1.33.1<br>//打开控制台窗口，请使用vs2005在开始菜单中的&#8220;Visual Studio Tools-&gt;Visual Studio 2005 命令提示&#8221;打开控制台，这样vc的的编译环境就设置好了。<br>//假设boost安装包的解压的目录为{BOOST_SRC}中。<br>//先编译出bjam.exe，它被用于安装boost库<br>cd {BOOST_SRC}\tools\build\jam_src<br>build.bat<br>//利用编译出的bjam.exe程序编译并安装boost库<br>cd {BOOST_SRC}<br>copy {BOOST_SRC}\tools\build\jam_src\bin.ntx86\bjam.exe<br>//下面的命令的各选项的说明：<br>//prefix&nbsp;&nbsp;&nbsp; 将boost安装到的路径（生成的头文件和库文件都会放到该路径中）。<br>//重定义以下变量（利用-s设置）：<br>//VC80_ROOT　　vc2005的安装路径，如果未将vc2005安装到默认位置，你必须指定该项。<br>//TOOLS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用的编译工具，vc2005对应的是vc-8_0<br>//PYTHON_ROOT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; python的安装目录，如果未将BOOST安装到默认位置，你必须指定该项。<br>//BUILD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 编译结果选项，默认会生成尽可能多的版本，如调试版／发行版，静态库／动态库，单线程／多线程。<br>bjam "-sVC80_ROOT=D:\Program Files\Microsoft Visual Studio 8\VC" "-sTOOLS=vc-8_0"&nbsp; "-sPYTHON_ROOT=D:\Program Files\Python24" "--prefix=E:\librarys\boost" install</p>
<p>boost在vc2005中的编译出现codepage警告和DEPRECATED函数的解决近日下载了一个VC2005 Express Edition，用它来编译boost，发现有不少的warning C4819，说代码文件中有cp936无法表示的字符，还有就是vc2005特有的废弃的ANSI函数的错误，虽说不影响编译，但是看着时不时出现的warning总是让人心神不安，还容易掩盖其他的错误，如果是直接用cl编译，只要加上/wd4819 /D_CRT_SECURE_NO_DEPRECATE就可以不显示这两个错误，但是大家都知道boost是使用其特有的boost.build进行编译的，下面我就给出如何修改boost.build来抑制这两个错误的显示</p>
<p>boost.build分为v1和v2两个版本<br>v1：<br>修改$(BOOST_ROOT)/tools/build/v1/vc-8_0-tools.jam<br>将</p>
<p>&nbsp;flags vc - 8_0 C ++ FLAGS :&nbsp; / Zc:forScope ; <br>改为</p>
<p><br>&nbsp;flags vc - 8_0 C ++ FLAGS :&nbsp; / Zc:forScope&nbsp; / wd4819&nbsp; / D_CRT_SECURE_NO_DEPRECATE ; <br>v2：<br>cvs版本<br>修改$(BOOST_ROOT)/tools/build/v2/tools/msvc.jam<br>在</p>
<p>&nbsp;#&nbsp; 8.0&nbsp; adds some more options<br>&nbsp;<br>一行的下方加上</p>
<p>&nbsp;flags msvc.compile CFLAGS $(condition) :&nbsp; / wd4819&nbsp; / D_CRT_SECURE_NO_DEPRECATE ; <br>&nbsp;<br>boost 1.33.1版本<br>将</p>
<p><br>&nbsp;&nbsp;&nbsp; #&nbsp; 8.0&nbsp; deprecates some of the options<br>&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp;&nbsp; !&nbsp; [ MATCH&nbsp; ^ ([ 67 ]. * ) : $(version) ] <br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.compile CFLAGS $(condition) /&lt; optimization &gt; speed :&nbsp; / O2 ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.compile CFLAGS $(condition) /&lt; optimization &gt; space :&nbsp; / O1 ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.link.dll MANIFEST :&nbsp; " mt -manifest&nbsp; "&nbsp; ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.link.dll OUTPUTRESOURCE :&nbsp; " -outputresource: "&nbsp; ;<br>&nbsp;&nbsp;&nbsp; } <br>改为：</p>
<p><br>&nbsp;&nbsp;&nbsp; #&nbsp; 8.0&nbsp; deprecates some of the options<br>&nbsp;&nbsp;&nbsp;&nbsp; if&nbsp;&nbsp; !&nbsp; [ MATCH&nbsp; ^ ([ 67 ]. * ) : $(version) ] <br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.compile CFLAGS $(condition) :&nbsp; / wd4819&nbsp; / D_CRT_SECURE_NO_DEPRECATE ; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.compile CFLAGS $(condition) /&lt; optimization &gt; speed :&nbsp; / O2 ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.compile CFLAGS $(condition) /&lt; optimization &gt; space :&nbsp; / O1 ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.link.dll MANIFEST :&nbsp; " mt -manifest&nbsp; "&nbsp; ;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags msvc.link.dll OUTPUTRESOURCE :&nbsp; " -outputresource: "&nbsp; ;<br>&nbsp;&nbsp;&nbsp; } </p>
<img src ="http://www.blogjava.net/morphis/aggbug/122116.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-06-05 12:45 <a href="http://www.blogjava.net/morphis/archive/2007/06/05/122116.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在面试中的最佳提问</title><link>http://www.blogjava.net/morphis/archive/2007/06/01/121438.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Fri, 01 Jun 2007 14:56:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/06/01/121438.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/121438.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/06/01/121438.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/121438.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/121438.html</trackback:ping><description><![CDATA[在面试中的最佳提问<br><br>面试是一种双向沟通的过程。雇佣（招聘）经理通过面试来决定你是否适合这个职位。同时，你也应该相应的提出若干问题来判断这个公司或职位是否让自己满意。<br><br>但是当正式开始面试的时候，很容易忘记准备好的提问。毕竟你在一个陌生的办公室进行面试。在听了雇佣经理对公司背景或产品的一番介绍后，你有被问到了一堆有关于你的工作经验、学历背景、未来计划等的问题。同时也在祈祷着自己给出了正确的回答。<br><br>到雇主（或招聘经理）问你有什么问题要问时，你很容易紧张并结结巴巴的回答&#8220;没有&#8221;。<br><br>然而，不提问题可能会错失了一个获得竞争的机会。<br><br>&#8220;这是一个很大的机会可以以积极的方式为你从其他候选人手中赢得这个职位&#8221;一位在人才招聘机构的资深顾问说道。雇主认为他们对于能提出有品质问题并能通过这种明智的谈话获得讯息的候选人很感兴趣。<br><br>在面试前，准备一份有关于面试公司及应聘职位的一些问题列表。以下是一些话题供参考:<br><br>关于公司的提问<br>1.您对贵公司未来5年有什么展望？<br>2.您对这个行业有什么看法？<br>3.您认为贵公司最重要的资产是什么？<br>4.您能介绍下贵公司的新产品或是增值计划吗？<br>5.您如何看待竞争？<br><br>关于职位背景<br>询问该职位为什么空缺，可以提供洞察公司和晋升的可能.如：<br>1.公司的整体架构是怎样的？<br>2.在这个部门的职场行径如何？<br>3.在过去几年里该部门的业绩如何？<br>4.您如何看待您的团队（或部门）？<br><br>关于职责<br>为了避免稍后的混乱，进而取得可靠的职位理解，可以提出以下问题来帮助自己进一步了解职位信息：<br>1.您认为这个职位最重要的方面是什么？<br>2.您认为衡量受雇于该职位的人所具备的技能和价值是什么？<br>3.之前从事该职位的员工是否成功升迁了？<br>4.您能描述下这个职位每天或每周需要做的工作有哪些吗？哪些客户需要维护？<br><br>关于期望<br>决定你什么时候如何被评估，专家建议：<br>1.需要在最初的三个月中表现出来的这个职位的最大挑战是什么？<br>2.在未来一年中您对这个职位的期望是什么？<br>3.在贵公司我如何被评估或考核？评定的周期是怎么样的？<br><br>在面试的最后，不要忘了询问：接下来的面试步骤是什么？
<img src ="http://www.blogjava.net/morphis/aggbug/121438.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-06-01 22:56 <a href="http://www.blogjava.net/morphis/archive/2007/06/01/121438.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Copy Location Shell Extension</title><link>http://www.blogjava.net/morphis/archive/2007/05/30/120918.html</link><dc:creator>morphis</dc:creator><author>morphis</author><pubDate>Wed, 30 May 2007 07:06:00 GMT</pubDate><guid>http://www.blogjava.net/morphis/archive/2007/05/30/120918.html</guid><wfw:comment>http://www.blogjava.net/morphis/comments/120918.html</wfw:comment><comments>http://www.blogjava.net/morphis/archive/2007/05/30/120918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/morphis/comments/commentRss/120918.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/morphis/services/trackbacks/120918.html</trackback:ping><description><![CDATA[<a href="http://www.codeproject.com/shell/copylocation.asp">http://www.codeproject.com/shell/copylocation.asp</a>
<img src ="http://www.blogjava.net/morphis/aggbug/120918.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/morphis/" target="_blank">morphis</a> 2007-05-30 15:06 <a href="http://www.blogjava.net/morphis/archive/2007/05/30/120918.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>