| 笑天 的个人资料笑天的共享空间日志列表 | 帮助 |
|
11月27日 选择比努力更重要选择比努力更重要 一个人一生当中最大的幸福在于选择对两件事,一是找对单位、找对老板、找对上司 ;第二件事就是找对妻子或丈夫。为什么这么说呢?当太阳升起时我们与上司共事,当日 落西下,我们与自己的爱人相拥。你永远可以更主动地去影响你的上司,很多时候公司做这 样的安排也是因为你没有告诉公司你的选择。喜欢一个岗位要有超前思维。 你自己的职业生涯,只有你自己去规划,公司帮你规划的,只是你这个职位的规划, 两者很多时候是不一致的,你要作的就是尽量让两者靠近,如果实在不行,就走人。踏踏 实实的干好每一项工作,没有对基础工作的理解就不有凤凰涅磐。 董事会关注产业,总裁关注行业,总经理关注企业,员工关注职业,你要想成长为总 裁或董事长,就要去关注他们应该关注的事情。 主动选择要考虑的要点主要包括地域、行业、企业和职业。 第一回:痛惜工作者丢失职业生涯利剑 我属于一直潜水的那种,偶尔会上传或者下载一点资料。看到了家人不少的关于职业 生涯的讨论,也感觉很受启发。所以也想着给自己一个挑战,那就是把自己这方面的感悟 总结一下呵呵。唯一的担心就是时间,平时工作还是比较忙,无论如何,还是先发第一贴 ,如果大家感兴趣的话可以谈得更多一点。 在担任公司高管的几年间,我面试过数以百计的各个层面的员工,其中最让我感到遗 憾的一个现象就是很多人有着非常好的素质,甚至有的还是名校的毕业生,因为不懂得去 规划自己的职业,在工作多年后,依然拿着微薄的薪水,为了一份好一点的工作而奔波。 很多这样的人,他们只要稍微修正一下自己的职业方向,就能够在职业发展上走得更从容 。 有一次,一个大连理工大学的研究生,好像是学电子的,来应聘我们的公关企划部部 长。那小伙长得不错,将近一米八的身高,很阳光,个人素质也很好。他研究生毕业后去 了一家稍微有点规模的IT企业,因为他对于软件的了解很不够,就没有做技术,而是从事 管理,后来做到了总经理助理,主管行政和企划。工作5年后的薪水也就是5000多点,他在 公司的发展也受到了一定的局限。我在面试的过程中了解到,他之所以应聘我们的公关企 划部部长,只是因为我们这个职位给的薪水还可以,而不是因为他喜欢这样的工作。后来 我帮助他分析,依照他的素质和职业兴趣,如果选择得当,几年后应该有着很好的发展。 但是我们公关企划部部长的职位并不适合他,如果我们聘用了他,不但耽误企业的发展, 而且也会耽误他本人的发展。我帮助他分析以后他恍然大悟,对我十分的感谢。后来他经 过认证的思考及时修正了自己的职业道路,目前取得了不错的发展。所以有时候没有应聘 上反而是面试的成功。在今天的市场环境中,类似的例子还有很多,这样的人大多都有一 个共性,那就是最初的时候不知道自己应该在哪个领域开始自己的职业生涯,几年过去了 ,稀里糊涂的换了几家公司,回过头来才发现,只是积累了不同行业、不同职能方向不成 功地丰富经验。而且据我观察越是聪明的人越容易产生这样的问题。因为似乎什么工作都 难不倒聪明人,他们就有机会尝试不同的工作,结果却都是"蜻蜓点水"。一段时间以后突 然发现,多种多样的工作经验并没有给自己带来沉甸甸的收获,反而造成了自己缺乏专长 、缺乏核心竞争力的局面。最最关键的就是他们永远都难以结束低薪长跑,白白浪费了上 天赋予他们的才智。 当然,和此相对应的是另外的例子。有的人起点并不高,既非名校也不是什么好得不 得了的专业,甚至这里边还有大专和中专毕业的人,但是因为他们的正确的职业发展之路 ,几年之后他们在职场上的价值超过了很多当初起点比他们高的人。我们公司现在的财务 总监就是专科毕业的。但在十多年的财务生涯中,从出纳、会计、主管会计到财务经理, 他一步一个脚印走得很踏实。不少和他同龄的本科生、研究生也还没有取得这样的成绩。 我也认识不少拿着高薪的人士,他们中不乏低学历的人才,只是因为在一个领域里辛勤耕 耘而成为这个领域的专精之士,从而能够获得和他们价值相匹配的薪酬。 各种有趣的职场现象还有很多。有的人进了国有企业,进了政府机关,没有得到太大 发展,一直非常矛盾,想离开又不愿失去既得利益,转换成本越来越大,勉强得来一官半职 ,也很是没意思。始终处在矛盾当中,年轻人的激情在无聊的事务中慢慢消磨。也有的人 盲目的相信考证和考研,希望借助证书增加自己在职场的砝码;有人成功了,为数不少的 人却越读越穷,所获得的薪酬远远达不到自己的期望。如果把考证和考研比作投资的话, 至少是投资收益率不高。我就亲自面试过不少MBA,至少我是觉得他们没有获得和他们的投 资相匹配的回报。我们身边总有这种从一工作就抱怨不断却委曲求全的人存在,他们或者 从一开始就没有为自己的职业做过规划,要么只进行过短期的职业指导,等有了一份自己 可以接受的工作之后就"适可而止",任由无聊和无奈一天天侵蚀自己日渐衰老的心。 根据我个人的经验和观察。有太多的人不了解如何去规划自己的职业生涯,包括不少 读过职业生涯方面的书的人。接触到不少刚刚毕业的大学生对这样的问题更是全然没有概 念,甚至我看到有的人30岁了还在为自己的职业发展感到迷茫,而且看趋势还要继续迷茫 下去。究其原因关键是功力太浅,仅仅囿于职业来考虑职业,没有能够从更高的高度上来 考虑这样的问题;而目前所谓的职业生涯之南的书也大都为学者所作,理论性有余,实践 性不足,用以促进思考或许还有点帮助,用来指导实践则全无所获。正是基于这样的原因 ,近来我一直考虑怎么样将自己对于职业生涯的经验和观点能够系统的表达出来,以期能 够对这方面的问题感到困惑的朋友有所帮助。有些内容纯粹是我自己的感悟,有的是别人 的感悟但我比较认同,对在这方面给予我启发的朋友们表示感谢。 以上的姑且算作引言,书归正传。开始。 第二回:职业生涯扬帆于选择-选择比努力更重要 首先想表达的第一个观点就是选择比努力更重要。其实一生来讲失败的人和成功的人 努力差不多,我甚至发现很多在职业发展上并不顺利的人非常努力,反而一些人顺风顺水 ,仿佛很轻易的就得到了别人眼中的成功。成功的人努力几年就很轻松了,顶多智力上开 发的多一些;而失败的人也很努力,因为一旦他不努力就没有饭吃。 一个人一生当中最大的幸福在于选择对两件事,一是找对单位、找对老板、找对上司 ;第二件事就是找对妻子或丈夫。为什么这么说呢?当太阳升起时我们与上司共事,当日 落西下时我们与自己的爱人相拥。 正确的选择是如此重要,然而你会发现现实生活当中很多的人面临选择的时候竟然会 非常草率。一个人花在影响自己未来命运的工作选择上的精力,竟比花在购买衣服上的心 思要少的多,这是一件多么奇怪的事情,尤其是当他的未来幸福和富足全部依赖于这份工 作时。几乎没有人会认为自己是错误的--没有人会故意做出一个不利于自己的决定。他们 之所以选错,往往是由于不懂得如何选择。很多人认为自己无法了解自己到底适合做什么 工作,只好换来换去,希望能在过程中找到自己的兴趣所在,但许多年过去了,仍然很迷惑 。所以我们要认真选择,否则你根本不知道这个世界上那片土地适合你生长,什么样的环 境适合你发展。 和企业发展是一个道理,方向比速度更重要,在没有选择对明确地方向以前,单纯的谈 速度是没有太大意义的,甚至有时等待优于行动。没有明确选择的行动就是我们平时所说的 瞎折腾,瞎折腾的结果就是无序导致无效. 在这个世界上,通向成功的道路何止千万条,但你要记住:所有的道路,不是别人给 的,而是你自己选择的结果。你有什么样的选择,也就有了什么样的人生。你有什么样的 职业选择,你就拥有什么样的职业生涯。你今天的现状是你几年前选择的结果,你今天的选 择决定你几年后的职业状况.那么究竟如何来做选择?选择的依据是什么?选择要考虑的要点 又有哪些呢? 第三回:选择的内在依据是源于你的价值观 根据我个人的经验,选择的最深层次的依据是你的价值观,选择的表面依据是你的职 业目标,当然对于没有目标的人选择的依据就是他个人所理解的利益。主动选择要考虑的 要点主要包括地域、行业、企业和职业。或者说一个非常清晰的职业目标应该描述为多少 年后我希望在某地(北京/上海/纽约/老家的县城)某个行业(房地产/物流/教育培训等等 )某个企业(500强/民企/国企/政府等等)的一个从事某职业(人力资源/财务/金融/管理 等等高/中/低层)的人士。 这几个要点我会在后面做详细地论述,我个人觉得也是最有实际参考作用的部分。从 实际的例子来看,我们的人生价值观决定了我们的生活态度,从而决定了我们的职业取向 并导致了我们做出各种的职业选择,这种职业选择决定了我们的职业状况从而也决定了我 们的生活方式,这种生活方式又最后决定了我们的人生幸福感。 价值观的这个环节是我们大多数人很容易忽略的,虽然它在事实上左右着我们的决定 并进而决定我们的人生包括职业。一个人之要想成为职场的顶尖人物,他就必须清楚知道 自己的价值观,同时确实按照这个价值观过其人生。我所见到的在职业上有着良好发展的 人士都是因为他们秉持他们的价值观念,而一些不太顺利的人士大多思想混乱,要么是秉 持错误的价值观念,要么是根本没有,随着社会大众的舆论摇摆不定。 第四回:破解价值观于职业规划中的重要性 从企业选人的角度也能够很好地揭示价值观的重要性。为什么麦肯锡的咨询顾问很多 并不是出身于管理专业?为什么一些学业上并不突出的同学能够在竞争激烈的应聘中胜过 那些学习成绩突出的人?为什么外企在招聘trainee的面试中总是会有"你最大的成就是什 么"、"你最大的优缺点是什么"等等看似非常普通的问题?其实我觉得都和价值观有非常密 切的关系。因为一个人在职业上的价值观念和他能取得的成就是息息相关的,与此相比, 一时的学习成绩反倒成了末节。 从价值观的角度来说,职业发展成功还是失败的判别标准就是你是否得到了你想要的 生活,你的职业所带来的生活方式是否符合你的价值观。如果符合,你就会感觉很快乐, 哪怕收入会相对低一些;如果不符合,你会感觉很疼苦,哪怕你拿着看起来很高的年薪。 我刚刚工作的时候,遇到哪些拿高薪的人,总是很羡慕;到了今天心态就比较平和,遇到 比自己薪水高的人能够理解甚至有时候有些高薪的朋友还让人觉得同情,因为为了高薪他 们也失去了很多,比如天伦之乐和某种程度的身体健康,但他们得到了成就感。 所以,我一向主张在职业发展上我们没有必要去羡慕别人,因为当你得到的时候你就 失去了,反之亦然。你可能得到的是高薪,但失去的是时间;你可能不能成为一个好领导 ,但会成为一个好儿子。关键是你得到的正好是你想要的,而你失去的你并不介意,真正 的职业追求是圆满和平衡。 职业发展不能用挣钱的多余少来判断,那不应该成为我们职业上的目标。我看到的真 正成功的职业人士,即使在他们职业生涯的早期,也没有单纯的考虑金钱而是更多的追求 自己的梦想,按照自己的价值观去发展,应该说,这样的人反而会成功,金钱是职业发展 所带来的副产品。当你按照自己的梦想去追求而后成功,所有美好的东西都会朝你拥来, 包括金钱。 关于价值观的部分我想暂时先放一下,因为这部分要说明白要稍微费点事,而大家也 往往没有这个耐心。我能够讲明白,暂时也没有太多的精力写出来。但毫无疑问,这是最 重要的部分。或许,最后我可以再补上这一部分的其他内容比如如何能够更清楚自己的价 值观等等。 接下来想谈一下选择的要点。来点实际的。 第五回:职业规划的选择有四-地域首当其冲 第一个选择是要考虑地域。这也是不少人容易忽略的。我的高中同学的案例最能说明 地域对一个人职业发展的重要性。我们高中同学大都来自于农村,也有部分是县城的,我 们当地的教育不是很发达。同班的50个同学,包括后来复读的在内,后来考上大学包括本 科、专科和中专的在内,也就是在30人左右。从我大学毕业到现在8年的时间,应该说大家 的职业发展基本上定型。大学毕业后,大部分同学选择了比较发达的城市,但也有部分同 学回到了并不发达的老家。尤其是家在县城的同学,因为当时大都专科或中专,基本上都 回去了。但其中有两个本科毕业的农村同学也选择了回去。去年春节回家同学聚会,这两 个同学都很后悔,因为他们所谓的学历和能力在落后的县城并没有用武之地,失去了竞争 优势,稍微好点的企业加起来不超过5家,想跳槽都没有地方去,想再去一线城市吧,早已 失去了当初的锋芒,更何况已经娶妻生子;反倒是家在县城的同学,因为家庭有良好的人 际网络大都发展得不错。我说这话的意思并不是反对大家回去建设家乡,而是说一定要考 虑长远发展,因为你改变不了落后的思维,更何况工作之初你本身就不成熟。如果你却由 此意,我到建议你可以先在比较发达的地方学习,将来成为真正的职业人士在返回家乡或 者到家乡去投资,都是一个很好的方式。 地域甚至会成为限制一个人发展的瓶颈。如果你分到县城,如果从政的话,基本上你 就当到县委书记,至多当到地区专员,还要运气非常的好;如果你分到各大部委,运气不 算太差的话也能混个处长,稍微好点就能干个司长,不小心就当了部长。当然,我这里有 说笑的味道,但从概率上来讲,大致如此。 企业设立时选择和自己配套的区域。咨询公司基本上分布在北京、上海、广州和深圳 ,这四个地方恐怕占了全国咨询公司的80%,其他地方也有,但大都规模不大。济南和大连 、青岛等地也有咨询公司,但日子整体上就不如上述四个地方的滋润。工厂选择时也要考 虑配套,所以长三角和珠三角的工厂就星罗棋布。人才要发展也要考虑配套。你去比较适 合自己的区域,就能够得到好的配套,比如比较好的平台、比较好的培训、更宽广的视野 等等;否则缺了某个环节,比如得不到培训、事业狭窄等等你就很难得到发展。 单纯的说要去大地方发展或应该固守一隅都是不对的。因为更换地域而获得发展或发 展受阻的例子都很常见,我只是告诉你这是个值得考虑的因素。在职业流动越来越普遍的 今天,一生中在几个城市工作也很正常。我个人的建议是在职业发展的初期要尽可能在比 较发达的地方工作,等你已经在职业发展上达到相当的程度再考虑生活上更能接受的城市; 我也不建议职业发展过程中频繁的更换城市,因为你在某个城市积累的资源随着地域的变 动而大大贬值,会无形中使你的很多成本上升。 有的人认为大城市竞争过于激烈,生活成本太高而没有勇气去面对挑战;其实完全没 有必要。因为从另一方面来说,大城市的机会更多,而且激烈的竞争更能够激发个人潜能 ,更容易达到更高的职业高度。在二三线城市有个一二十万的年薪就很难再有上升的空间 ,但在北京、上海这样的薪水算不上什么。我原来公司的行政秘书素质很好,是学建筑的 ,身高178,很有气质,钢琴九级,因为工作的原因从大连调到上海,后来跳槽到斯坦威, 是一家销售奢侈钢琴的公司,有了更为光明的职业前景,但在大连她永远没有这样的机会 。 大多数人毕业时理所当然的留在自己读书的城市,或者回老家等等,其实有必要深思哪 些地方更适合自己发展。即使在职业中期的朋友也可以考虑通过地域的转换让自己的职业 生涯跃上一个新的平台。 第六回:职业规划选择之二-行业选择应保持内在连续性 第二个选择是要考虑行业。也有不少的朋友在这个问题上犯错误。有的人工作了7,8年 都难说自己停留在哪个行业,其实行业和个人发展息息相关。如果你选择了金融,那就意 味着几个人操纵上亿的资金;二三十个人操纵上千万上亿的资金,那是房地产行业;几百 人拼死拼活的再干,只有百万数量级的利润,那是生产行业。选择什么样的行业,就有了 什么样的发展空间。 在行业选择上最容易犯的错误就是没有行业。这是职业发展的大忌,也是最让人感到惋 惜的,但是这点确实比较容易避免的,关键是是要有行业的意识。有的人聊起来我干过多 少多少行业,以为这是一个非常值得自豪的事情,其实对自己的职业发展并没有多少好处 。我面试中遇到不少的人,在不同的行业作过,但是对那个行业都没有深入地了解。我们 前段时间招聘一个地产的副总裁收到了不少的简历,30-35岁这个年龄段,只有很少的人在 这个行业拥有超过6年以上的行业经验,仅从这一点就能够淘汰很多的人。我在后面会将到 职业的选择,职业的选择也一定要结合行业才能有更大的发展。即使就财务而言,房地产 的财务和物流行业、贸易行业的财务也会有相当大的差异。 刚刚工作的人有时也很难马上发现最适合自己的行业,但你可以去尝试,但我建议你的 目标是要成为这个行业的专家,无论你是从事技术还是管理。没有相当年的行业经验,你 很难说了解了一个行业,比如对于行业的惯例、发展趋势得了解、行业的价值链条、各个 层面的细节、人脉关系的积累等等都需要相当时间的积累。失去了行业背景,你的价值就 会大打折扣。 行业不是不可以改,我的一个建议就是行业发展要有内在的连续性。比如沿着行业的价 值链条在不同的企业工作,这往往会铸就你的职业优势。原来做教师的该做培训师,原来 做建筑的改到房地产,等等基本上都是比较可行的转换。内在连续性的道理其实很简单, 就是保持你的职业资源的不断升值增值,而不是把精力浪费在不同的行业,这个道理也适 用于我在后面谈的职业的选择。其实职业发展的很多 道理和作企业管理是相通的,比如管理中的SWOT分析、销售中的4P、战略制定的步骤等等 很多的管理工具都可以拿过来指导我们的职业发展。我一向反对企业作不相关多元化,企 业应该聚焦在自己最擅长的领域。同样我们个人也是如此。有的聪明人拥有的能量是10, 分散在多个领域,每个领域都不超过5,而我们大家认为得并不聪明的朋友,或许能量只有 8,但聚焦在一个领域反而会有好的发展。我有一位大学同学六年干过十个行业,基本一无 所成,只积累了每个行业不成功的丰富经验。在高科技高速发展的现代社会,往往一个专 业足够一个人奋斗一生,在这种分工很细的空间里我们自己的特长在哪里?我们立志在哪 个行业干一辈子?你对行业的透彻见解和有所作为令人敬佩和追崇,那你的收入和你的生 活才能跟一般人不一样。 第七回:职业规划选择之三-大企业为首(此条适合初入职场者) 美国人一辈子在不同的企业作相同的职业,日本人一辈子在相同的企业作不同的职业 ,唯有中国人不同,没有改革开放的时候,和日本人差不多,一辈子在相同的企业作不同 的职业,改革开放了,人才流动了,不少人却又有点矫枉过正,变成了在不同的企业作不 同的职业。当然随着大家职业意识的提高,这种状况会有所好转。 不同的选择导致不同的生活方式,选择企业更是如此。粗略来说,国内的企业大致可 以分为外企、国企和民企,政府部门可以归到国企中去,我个人没有到政府部门发展的想 法,但从和政府打交道的过程中,也发现了一些素质不错的人,只是要适应他们的工作习 惯太难了,但我个人认为,如果把去政府也作为一个职业的话,这也是一个不错的选择。 首选当然是各大部委,必去什么外企都要好,因为占有的资源多,其次是省、市,在下面 的就没有什么意思了。企业里面有很多的隐形冠军,就是企业知名度不高,但是获利能力 很好,又很好的行业地位,各大部委包括中央的一些企业有不少这样的隐形冠军,名气虽 然没有500强大,但那待遇让500强的所谓白领都要羡慕,但他们不属于你我穷孩子做职业 规划要考虑的范畴,基本可以排除,但是如果你万一遇到这样的机会,可别千万错过。 我在这三种的企业都呆过,总的体会是外企讲能力,国企讲本事,民营企业既要讲能 力,还要有本事。本事是中国人特有的词汇,也只有我们中国人才能明白其中的内涵。我 们说政府部门或者国企某某人升迁了,我们的评价往往是这个人很有本事,所以我们遇到 的国企领导大多都是比较有本事的人,但是能力怎样就不好说了。因此我的建议是有本事 的朋友要去国企,有能力的朋友要去外企,两方面能兼顾的朋友要去民企呵呵。 当然,这个事情不是绝对的,现在国企也讲能力,应该是国企本事的比例要大一些, 外企对能力的要求要大一些,至于具体的比例,不同的企业不同。你要选择适合你自己的 企业。 就具体的福利待遇而言,也要看最终的结果。外企总体的福利很好,但也很难让你有 意外的收入;民企总体福利不好,但一不小心公司蓬勃发展,你就成了小富翁。外企压力 大一些,培训比较系统,进步比较快;国营企业压力小,可以兼顾很多家庭的事情。我觉 得本身无所谓好坏,就像我前面谈到的价值观,关键看你想选择什么。 但是扒开企业一个个看,却是各有各的特点。很难就简单得说外企就比国企或者民企 好。要针对每个企业来做决定。同样是国企/民企/外企,也分三六九等。有的外企只是挂 羊头卖狗肉而已,其管理和福利等甚至还不如一般的民企,即使是500强的下属公司,有时 候待遇和发展空间也会有很大差异。我的一个同学就去了西门子的一家公司,待遇在外企 里面里面也属于一般。刚毕业的同学最容易被这个光环迷惑,也有不少的企业用这个幌子 来骗人。一旗在前面的帖子提到"好,继续期待,不过,在做选择的时候,有个问题是很难解决 的,就是信息不对称,特别是对于某个企业的了解。"这是很有道理的。但是我们可以通过一 定的手段来识别出来。 我个人的意见是刚开始不要进一些比较小的企业,尤其是刚刚毕业的同学。因为你那 时得社会经验非常少,很难处理得好很多的关系,非常容易对社会和职业等等方面形成一 些错误乃至极端的看法。你从小企业获得的东西太少了,看似学到了一些东西,实际上得 不偿失,再去找工作的时候才发现已经处于竞争的劣势。我就遇到过几个在小企业作副总 经理的人,个人能力还不错,但是稍微大一点的工作都不愿再给他们机会,因为他们已经 长成了一颗歪脖子树,公司宁愿招一些完全没有经验的人来。谈到这里,又要说题外话。 不少人误把经验当作能力,误把学历、知识当作能力,都是不对的。有的人所谓的十年行 业经验也只是对行业有点粗浅了解,有的人干了三年已经有了很深的见识。或者有的人让 你感觉,虽然他的经验很不够,但他的那种思维方式很好,按照这个趋势发展下去肯定会 有不错的发展。小时候老家有句骂人的话"你一把年纪都活到狗身上去了"指责某些人的见 识没有随着年龄的增加而增长,话糙理不糙。所以我们人在企业,但不能局限于企业,要 有更高的视角。董事会关注产业,总裁关注行业,总经理关注企业,员工关注职业,你要 想成长为总裁或董事长,就要去关注他们应该关注的事情。 职业发展中最悲哀的两个状况一是拼命的在贫瘠的土地上耕耘,二是总是在寻找机会 却不知道自己就站在肥沃的土地上。在企业里工作这么多年,我的体会是让你100%满意的 企业是不存在的。我遇到不少的人整天抱怨企业,福利不要,上司或老板太苛刻等等,这 都不是一种职业的素质。如果你觉得企业不满意,我的建议是要么离开他,要么去改进, 抱怨不解决任何问题。我刚刚工作的时候,我们一帮一块进公司的大学生聚会的必修课之 一就是一起抱怨公司,我后来发现这种状态太危险,很容易把自己给搞成老大姐。去年我 又到原来的公司去了一趟,发现抱怨的那些人还在抱怨,而没有抱怨的那些人要么已经在 公司有了不错的发展,要么已经重新开辟了自己的职业领域。我并不是说一点都不能抱怨 ,现在不公平的事情太多,还不让我们说几句发泄一下嘛,但我只主张有限度的抱怨。根 据我的观察,其实抱怨很容易形成习惯,结果最后抱怨成了主旋律。尤其是几个喜欢抱怨 的人走到了一起,你一言我一语,开完声讨大会,不解决任何问题,反而容易消磨人的意 志,所有的抱怨之词都成了你安慰自己的借口。这不是一个积极心态的人的做法。我和不 少的私营企业老板打交道,现在社会上太多不公平的现象,尤其是政府部门,太多需要我 们抱怨的东西,但我发现他们很少抱怨,他们只是想着如何来利用目前的这种体制。我不 是说他们一定是对的,我只是请你相信,机会往往来自于不合理。 第八回:职业规划选择之四-工作锁定主战场 我在这里先解释一下,所谓的职业就是你所从事的具体职能比如营销、财务、行政、 管理或者业务。我遇到的大部分职业规划不理想的人是在这部分,而在具体职业上的选择 出现误差带来的伤害也最为明显、最为严重。 我先结合结合职业和企业来讲。我遇到过学管理的同学到很小的企业去做管理,我觉 得这个选择欠妥当。不是说小企业不需要管理,而是目前中小企业的现状实际上不重视管 理。中小企业是业务和机会导向,还没有发展到战略、管理导向。如果你是做业务的,去 中小企业也不一定有什么不妥,因为所有的大企业都是从小企业走过来的,但是学管理的 或者说将来希望做管理的,你必须到能够让你理解管理、应用管理的地方去。千万不要以 为你是管理专业毕业的你就会管理,这里面的学问太深了。你去了以后,一切全凭自己摸 索,真正规范的东西没有学到,积累了一大堆错误的观念和操作办法,真的是把自己给害 了。 人事行政部就是不少中小企业的产物。不否认有大的公司会设行政总裁,主管人事和 行政,也不否认有的人事行政部经理发展得很好,但就我接触的而言,这个职位的发展空 间小。尤其是行政。前段时间一个重点大学毕业的小女孩很高兴的告诉我她刚工作半年就 被提升为办公室主任,后来我给她分析她才明白其中的道理。为什么呢?行政这个职位的 发展空间太小,刚开始好像工资不低,但我很少见到在这个职位上拿高薪的,能突破10万 算是不错了。因为就绝大多数公司而言,它的进入门槛很低,经常遇到不知道干什么好地 说,我来干行政吧,这个岗位提供的价值是基本上一定的,无论谁来做,也不可能做出花 来,薪水上升到一定空间就后继乏力。很多有才情的小姑娘稀里糊涂在这个岗位呆了好几 年,结果就成了软翅膀的蝴蝶,很难再飞起来了。这样的工作倒是很好找,但是哪怕你做 了很多年的行政,薪酬也是在某个位置打晃,很难有突破。所以这个职位可以作为跳板, 但不宜久留,那些能力强的,要迅速利用这个职位,成长为副总等等。其实,不光是行政 ,关于职业这里我的建议就是要在企业的主战场。 什么是主战场?举例来说,实际上就是那些最能够直接提供价值的部门,主要是业务 部门,当然,对于一些大的企业而言,我认为财务、人力资源、战略规划部门等等也可以 划入主战场的范畴。如果是在军队里面,那就是直接打仗的那一部分,当然也会包括信息 和情报等支持部门,但是你如果进了炊事班,那你的职业空间就不是很大,有个笑话说炮 兵连炊事班的战士"背黑锅、戴绿帽子"还要看别人打炮,简直是悲惨之极。也很少听说那 个将军有多少年的炊事员生涯。所以,你要想当将军,不要去当炊事兵;你要想在职业上 有上升空间,最好不要去企业的不是主战场的部门。但是大家可能会说,这些部门的存在 对企业是确实必要的,我们都不去,那谁去?我的意见是让没有看到这个帖子的人去看呵 呵。 不过请大家放心,因为总归有些人喜欢平平淡淡,乐意去那样的部门。 前两天遇到一个著名大学学计算机的研究生,他去了一家比较大的公司作业务软件的 开发和硬件维护,虽然目前待遇也还可以,但我认为他的发展空间很有限,原因就是他没 有在企业的主战场,他们公司将来的总经理只能是业务出身,不太可能是他的这种经历。 如果将来他们公司计算机方面的业务外包,这非常有可能,他的发展就要受损,因为他和 那些在软件公司工作的同学的差距已经在逐步拉大。我遇到好几个学计算机的,都在房地 产、生产等等方面的企业,他们的发展空间可想而知。类似这种情况,要去也只能去一些 非常大的公司,否则一点意思都没有。 第九回:案例探讨 这里想再说点题外话,我们去企业工作的时候,首先应该问一下我们能够替企业创造 多大的价值,因为我们的收益实际上来自于我们创造的价值,如果我们的专业技能不能为 企业创造价值的话,既是我们能够拿到一时得高薪,也很难有大的发展,关键是有职业素 养的人会觉得很难受。我来目前公司的时候,有另外一家企业的老板也希望我过去做管理 ,给我的薪水是目前企业的1.5倍,但是那家企业只有50、60人的规模,远远不如我目前企 业的规模,所以我思虑再三,还是到了目前的这家公司。原因就是我去了那家公司,从管 理的角度来说,一是我很难再有提高,二是那样一个规模的公司我很难创造和自己收入相 匹配的价值,时间一长,在公司的地位就要下降,再找工作的话这段经历就不能够为我的 职业发展增值,而目前的公司空间就比较大,光集团职能部门就有8个,还有下面的产业, 在这种体制下,我的管理思想能够创造价值。当然还有其他的原因,但毫无疑问,主战场 原则是最主要的因素。从目前的实际工作情况来看,我的这个选择是正确的。 有个家人问到为什么讲财务也可以划入主战场呢?这是因为在大的企业财务能够创造 非常大的价值。一个一定规模的企业财务总监能够拿到几十万甚至上百万的年薪,那时因 为在那样的公司通过财务管理比如税务筹划、资金运营、内部控制等等能够创造几百万甚 至上千万的价值,某种程度上比业务部门的价值并不小。比如房地产公司而言,财务能力 甚至会成为公司的核心竞争力之一。而且随着管理的发展,财务会逐步的介入业务,大家 对财务的重视程度会越来越高。将来的高层管理者,谁在说自己不懂财务那就不应该了。 公司里的三驾马车,无论如何是应该有财务的一席之地的。但是小的公司就不同,皮包公 司老板或者老板娘就相当于财务经理,顶多设个出纳,规模再大一点的公司,如果要设副 总,一般也是业务出身,财务就是中层,因为业务有限,财务能够创造的价值本身就有限 。 在这里我要恭喜学财务的家人,我个人认为财务是非常有前途的一个职业,也是一个很容 易规划自己发展路径的职业。我遇到一些学财务的朋友,提起财务来大吐口水,认为财务 没有什么意思,其实我觉得是没有从更高的高度来看待这个问题,越来越多的企业会走向 以财务控制为核心的企业管理,而且财务和投资、资本运作、金融等等都有千丝万缕的联 系,可谓是前途无限。 其它和财务是差不多的职业包括人力资源、内审、管理、战略规划等等,如果不小心 没做好职业和企业的结合,只能是埋怨领导不重视你这一部分,其实不是领导不重视,而 是你那里创造的价值很有限,如果你是领导,你也这样干。 当然我不否认这里面有管理理念的因素,但是这是目前国内企业的现状。 还有一个很好的职业就是销售。销售是最能考验一个人能力的职业,而且我个人觉得 这是一个对于起点比较低的朋友非常好的一个职业。我就又遇到几个学历并不高但薪水很 不错的朋友,但我还遇到一个东财毕业的哥们,他大学毕业后在国内做了2年,后来竟然跑 到新西兰读了个营销的研究生,结果他的同学在国内都做到10万年薪了,他回到国内找工 作都还成问题。为什么?研究生学历去大学教书有点低,人家的门槛现在都提到了博士, 用来做销售又有点高,处于一个很尴尬的境地。所以我一向不建议身边的朋友去读营销方 面的研究生,除非你想做研究或者工作深造。销售是一个实践性非常强的职业,大家全凭 业绩说话,而且业绩也比较容易衡量。 我前面讲到在行业和职业的选择方面要有内在的连续性,最好的连续性当然是两者都 要保持,因为现在的专业化分工越来越明显,尤其是有些职业和业务的结合比较紧密,比 如你会做洗发水的销售但不一定能做好化肥的销售,你能担任生产性企业的财务总监但是 做地产公司的财务总监你就很吃力。但是如果做不到两者都连续,我建议你最好能保持其 中的一个是连续的。比如你一直在地产作但是作不同的职业,这样你将来的发展方向应该 就是某个地产公司的总经理或者高管;或者你一直从事某个职业,比如你一直做销售、财 务或者人力资源,这样即使在不同的行业作,但你会成为某个职业领域的专家。 探讨一: flybird300:有一个问题,是关于职业选择的。我是个刚毕业的研究生,学的是管理,专 业方向偏重投资理财。当初我参加目前这家公司面试时,是申请做与我专业相关的业务工 作的,可是进来后老板临时给我换成了做文秘,每天是写简报、报告,虽然也了解了些业 务,可是都是很间接的。从楼主上面的分析看,行政似乎并不是企业的"主战场",而且职 业发展空间很有限。可是造成这种局面的原因并非我的选择出了问题,而是老总就是这么 给我安排的,我曾多次想找老板谈这个事情,但是老板一直没时间和我细谈。想换单位吧 ,又担心刚来就换,给人印象不好,而且职业上目前也没有什么跳槽的资本积累。 我想问楼主的是,职业选择往往受到公司老总的左右,自己不能按照自己的意愿选择 ,这样的情况该如果作出应对呢?尤其是刚毕业没多久的大学生,说话没分量(公司老总 不会因为你不喜欢他给你的安排而改变他的决定),跳槽无资本,这样的处境真是很尴尬 ,希望楼主能凭借你多年的经验给我些合理化建议。非常感谢!landy0985:很抱歉没有及 时回答flybird300的问题,最近事情太多了,但感动与你的诚意,提几点意见供参考。 第一,我在前面讲过,行政不是企业的主战场,但并不是说从事行政的就完全没有前 途,只是你不要在这样的职位上停留太久,因为这样的职位门槛低,技术含量不高,可替 代性强。但行政职位也有他的优势,那就是和高层接触比较多,能力强的话比较容易得到 赏识,达到老总的认可后就可以以之为跳板,去争取你想去的位置。我想说的是在职业发 展的过程中,我们永远都可以比原来做得更主动一些,这是我们最宝贵的选择权利。 第二,让一些刚毕业的学生从事一些技术含量低的工作是很多公司的用人之道。绝大 多数新人都要从这个阶段走过来,但这是一个很重要的学习阶段。坦诚来说,现在让你承 担一些更重要的工作你也不一定能做得恰到好处。我觉得你现在能够做的,是把上司让你 做的工作做到让他放心并尝试着比他吩咐的做得更多,为自己的职业生涯赢得第一笔授信 。我现在手下有一个今年刚毕业的研究生,我就故意考察他,一项工作做好了再安排另一 项,逐步提高工作的挑战性。如果他第一项工作没做好,后续的工作就很难再安排,顶多 有2,3次的尝试机会。所以新的机会是自己一步步赢来的。 第三,喜欢一个岗位要有朝前思维。如果一个人等到当上了高层才开始思考高层的问 题,那他成为高层的机会很渺茫;同理,如果你想去做投资管理,哪怕现在在行政或文秘 的职位,那你要问自己一个问题:我怎么才能去做投资管理的职位?如果让我去做,我会 怎样去做?比如你可以和现在做投资管理的同事去聊,了解目前公司投资管理方面需要改 进的地方,然后你可以认真思考,写报告或者和总经理沟通,谈你的看法;或者尽可能的 主动去做投资管理方面的工作,慢慢得你就会成为投资管理团队中的一员。 第四, flybird300的问题是很多到中小企业的朋友都会遇到的问题,那就是老总本身 很少有职业规划的意识,他是根据自己的感觉在用人,往往是非常的草率;而且这样的企 业本身在招人的时候就没有人力资源规划,甚至有的时候根本没有想好为什么要把这个人 给招进来,但是这个人并不知情,只是他的工作职责一般都不会很清晰;再者来说,这样 的企业业务体系往往并不成熟,组织架构调整比较频繁,也会不考虑员工的感受,根据自 己的感觉把员工放在某一个位置上,这个位置还会经常地变换。所以会把很多人的职业路 径给搞得乱七八糟。问题的原因是多种多样,关键是怎么来解决?什么样的方案更合适?我 个人的意见就是以上的三点,实际总结起来就是你自己要主动地去选择,否则就是把自己 的命运完全的交到了公司手里。我个人的经验就是你永远可以更主动地去影响你的上司, 很多时候公司做这样的安排也是因为你没有告诉公司你的选择。当然,如果公司实在很烂 ,那就毫不犹豫,骑驴找马尽早脱身。 11月21日 ATI笔试题11月16日20:00pm-21:00pm参加了ATI的笔试。2006年10月25日,ATI已经被AMD收购,所 以现在ATI只是AMD公司的一个部门。ATI笔试题共有8个题目: 1:windows API里面用于线程同步的有哪些? 答案:共有12个API 1) 临界区共有五个API (1)InitializeCriticalSection 此函数用于设置临界区对象,即对临界区对象初始化。该函数必须在执行EnterCritica lSection前调用。单个进程的线程可以为互斥同步使用临界区对象。进程负责分配临界 区对象使用的内存,可以通过对CRITICAL_SECTION类型变量的定义和使用来实现。 (2)EnterCriticalSection 此函数用于等待指定的临界区对象的所有权。授予调用线程所有权后,该函数返回,临 界区对象在单个进程的各线程内强制互斥同步。在线程拥有临界区对象以后,对同一个 临界区对象应调用EnterCriticalSection函数,防止发生死锁。在退出临界区后用Leav eCriticalSe- ction函数使其他线程可以进入临界区。 (3)TryEnterCriticalSection 此函数用没有阻塞的方式试图进入一个临界区。若函数调用成功,则进行调用的线程拥 有对临界区的所有权,否则立即返回。 (4)LeaveCriticalSection 此函数用于释放对临界区对象的所有权。每次线程对同一个对象执行EnterCriticalSec tion或TryEnterCriticalSection都必须调用LeaveCriticalSection函数。 (5)DeleteCriticalSection 此函数用于删除一个临界区对象,释放所有与不再为自己所控制的临界区对象有关的资 源。一个临界区对象被删除,就不能再对其调用函数EnterCriticalSection,函数TryE nterCriticalSection和函数LeaveCriticalSection了。 2) 互斥和信号量共有7个API (1) CreateMutex 此函数用于创建命名或未命名的互斥对象。这些互斥对象用于进程同步,当互斥对象不 为任何线程拥有时才处于信号态,否则将处于非信号态。若要线程释放其所有权,则线 程在每次互斥对象处于非信号态时都调用函数ReleaseMutex。当不再需要互斥对象时可 以使用函数CloseHandle来关闭互斥对象。当所有互斥对象的打开句柄都关闭时,就删除 互斥对象。 (2)OpenMutex 用于返回存在的已命名互斥对象的句柄。该函数允许多个进程打开同一个互斥对象的句 柄。该函数的调用一定要在函数CreateMutex创建互斥对象之后,当不需要句柄时可以调 用CloseHandle函数。 (3)ReleaseMutex 此函数用于释放互斥对象。若函数调用成功,互斥对象处于信号态。 (4)CreateSemaphore 此函数用于创建已命名或未命名的信号量对象,信号量用计数器实现同步。每次取信号 量时(可利用函数WaitForSingleObject来取),信号量计数器递减;每次ReleaseSema phore释放信号量值时,信号量计数器递增。计数永远不会小于0或大于在lSemMaxCount 参数中定义的值。 (5)OpenSemaphore 用于打开一个已经存在的命名的信号量对象。该信号量必须是函数CreateSemaphore创建 的。如果不再需要时,可以用函数CloseHandle关闭返回的句柄。 (6)WaitForSingleObject 此函数仅当在参数列表中指定的对象处于信号态或超过了超时间隔时,该函数才返回。 (7)ReleaseSemaphore 用来递增信号量的计数。对于CreateSemaphore函数创建的对象使用,计数可以达到设定 的最大计数值。 2: windows内核内存分为paged memory和 nonpaged memory,请问有什么区别? 答案: paged memory:是指可以分页的内存,可以交换到硬盘文件上。 Nonpaged memory:不可分页,也就是不能交换到硬盘文件上。有些内存,比如驱动程序 ,内核代码是不允许交换出去的,应该常驻内存,就使用nonpaged memory。 3:请问什么情况下,cache中只放指令(数据直接从存储器存取)比cache中放数据和指 令的效率高? 答案:计算密集型 cache中只放指令(数据直接从存储器存取)比cache中放数据和指令 的效率高,可以充分利用指令的局部原理。 4:RISC和CISC等其他指令集相比有哪些优点,请至少举出5个。 答案: (1)寻址方式少且简单,一般为2—3种,最多不超过4种,绝不出现存储器间接寻址方式 。 (2)指令集中的指令数目一般少于100种,指令格式一般少于4种。 (3)指令功能简单,控制器多采用硬布线方式,以期更快的执行速度。 (4)平均而言,所有指令的执行时间为一个处理时钟周期。 (5)指令格式中用于指派整数寄存器的个数不少于32个,用于指派浮点数寄存器的个数不 少于16个。 (6)强调通用寄存器资源的优化使用。 (7)支持指令流水并强调指令流水的优化使用。 5:选择题:如果两个节点x,y,preorder遍历,x在y之前,postorder遍历,x在y之后, 请问x,y的关系为: A x是y的左兄弟 B x是y的右兄弟 C x是y的祖先 D x是y的后裔 答案:C 6:请问下面程序如果运行会出现什么结果?如果有错误请指出并改正。 #include <stdlib.h> #include <string.h> class mystring{ public: mystring(){ m_str=NULL; } mystring(mystring& str){ if(m_str!=NULL){ delete []m_str; } m_str=new char[strlen(str.m_str)]; strcpy(m_str,str.m_str); } mystring & operator=(const char *str){ if(m_str!=NULL){ delete []m_str; } m_str=new char[strlen(str)+1]; strcpy(m_str,str); } ~mystring(){ if(m_str!=NULL){ delete m_str; } } private: char *m_str; }; int main(){ mystring str1; str1="hello world"; mystring str2; str2=str1; mystring str3=str2; return 0; } ~ 答案: 程序运行会出现内存释放错误 错误共有四处,分别在下面改正的代码中标出。 #include <stdlib.h> #include <string.h> class mystring{ public: mystring(){ m_str=NULL; } mystring(mystring& str){ /*if(m_str!=NULL){ delete []m_str; }*/ //错误1,因为m_str没有被初始化,所以此处可能为NULL,也可能不为NULL,如果不为 null,则会出错,因为m_str是一个随机的值。 m_str=new char[strlen(str.m_str)+1]; //错误2:长度应该+1 strcpy(m_str,str.m_str); } mystring & operator=(mystring& str){ //错误3:缺少赋值重载函数 if(m_str!=NULL){ delete []m_str; } m_str=new char[strlen(str.m_str)+1]; //错误2:长度应该+1 strcpy(m_str,str.m_str); } mystring & operator=(const char *str){ if(m_str!=NULL){ delete []m_str; } m_str=new char[strlen(str)+1]; strcpy(m_str,str); } ~mystring(){ if(m_str!=NULL){ delete []m_str; //错误4:析构函数中,应该析构数组 } } private: char *m_str; }; int main(){ mystring str1; str1="hello world"; mystring str2; str2=str1; mystring str3=str2; return 0; } ~ 7:100个乒乓球取胜之道,A,B两个人轮流拿,A先拿,一次只能拿[1,5]个,获胜者 为拿到最后一个球的人。请问A第一次该拿几个?以后又该怎么拿,才能够确保获胜? 答案:A先拿4个,然后B拿,设B拿x个,则每次A拿6-x个即可。 8:有编号1-50的人,依次排列,然后单号出列,然后剩下的人重新编号,单号出列, 依次类推,最后剩下一个人,请问这个人原来编号是多少号?如果是每一次双号出列, 请问这个人原来编号是多少? 答案:单号出列:32号 双号出列:1号 面试题: 今天下午面试ATI,问了很多问题。 (1)除了我们公司,你最想去哪家公司? (2)你平时都作什么体育运动? (3)什么叫做流水线,什么叫做拷贝构造函数? (4)MIPS流水线分为几级?每一级分别完成什么功能? (5)研究生阶段学了那些主要课程?你最喜欢哪两门课? (6)比较一下二叉树和B+树的不同? (7)冒泡排序算法的时间复杂度是多少?什么排序算法的时间复杂度是o(nlgn)?什 么排序算法在最坏情况下的时间复杂度是o(nlgn)? (8)sizeof()的值是在编译阶段计算的还是在执行阶段计算的? (9)PXA25X的CPU是几级流水线? (10)请详细介绍一下你现在做的项目? (11)你认为AMD为什么要和ATI进行合并? 11月12日 B-tree索引B-tree索引是数据库中存取和查找文件(称为记录或键值)的一种方法。B-tree算法减少定位记录时所经历的中间过程,从而加快存取速度。
一个B-tree的典型例子就是硬盘中的结点。与内存相比,硬盘必须花成倍的时间来存取一个数据元素,这是因为硬盘的机械部件读写数据的速度远远赶不上纯电子媒体的内存。与一个结点两个分支的二元树相比,B-tree利用多个分支(称为子树)的结点,减少获取记录时所经历的结点数,从而达到节省存取时间的目的。 11月11日 有犯错的小问题以前的题目又出错了 1 参数大小
解答:
数组名的本质如下:
输出结果为10,str指代数据结构char[10]。 (2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;
(3)数组名作为函数形参时,沦为普通指针。 2优先级 *和++运算符的优先级是一样的但是结合性是自右向左 不同于a+++b 3 (1).对于公有继承方式: ·基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员可见:基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态;基类的私有成员不可见:基类的私有成员仍然是私有的,派生类不可访问基类中的私有成员。 对派生类对象来说,基类的公有成员是可见的,其他成员是不可见。 所以,在公有继承时,派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。 ·基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员是可见的:基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问;基类的私有成员是不可见的:派生类不可访问基类中的私有成员。 ·对派生类对象来说,基类的所有成员都是不可见的。 (3).对于保护继承方式: 在一个类中,例如在写String的赋值构造函数时, 4、找错 void test2() void Test( void ) (1)如果面试者指出字符数组str1不能在数组内结束可以给3分,这种情况下不等于一个字符串;如果面试者指出strcpy(string, str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分; (2)malloc后最好要加一句if(str=NULL)判断内存是否申请成功;free后面要有str=NULL 5 String的构造函数 String::String(const char *str) 6、在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值; 排序算法空间、时间复杂度简单排序法——
冒泡法是第二维循环中自己循环,找最小或最大值
选择排序和交换排序是第二维循环与第一维循环中的值比较;交换法最清晰,选择法作了改进,
只交换位置标号,算法复杂度没变。
插入法,它的基本工作原理是抽出牌,在前面的牌中寻找相应的位置插入,然后继续下一张(较为复杂)
高级排序法——
快速排序,从冒泡法改进得到,基本思想是任选一个记录,一般选取序列第一个,通过一趟排序将待排记录分割成相邻的两个区域,其中一个区域中记录的关键字比另一个区域关键字都小,即一个区域的值都大于所取的关键字,另一个区域的指都小于所取的关键字,则可以分别对这两个区域的记录进行排序,以达到整个序列有序。
将它区别于SHELL排序,后者是先有一个递减的步长数组,对相隔step-1的内容排列,然后改变步长,依次
下去。
归并排序,先在原记录中找一个中间位置(low+high)/2,对两段分别进行归并排序,最后再整体排序(即分三次)。
注意,快速排序没有最后整体排序,但一开始先排了一次。
堆排序,对选择排序的改进,利用堆的特性对记录序列进行排序。
时间复杂度
冒泡排序、选择排序和插入排序的比较次数为O(n2),最坏情况 O(n2),最好O(n)
(但选择排序最好是 O(n2))
快速排序在平均情况下复杂性为O(nlogn),最坏情况 O(n2),最好O(nlogn)
堆排序和合并排序在最坏情况下复杂性为O(nlogn)。可见,合并排序和堆排序是比较排序算法中时间复杂度最优算法。
空间复杂度
空间性能是排序所需辅助空间大小
所有简单排序和堆排序都是0(1)
快速排序为0(logn),要为递归程序执行过程栈所需的辅助空间
归并排序和基数排序所需辅助空间最多,为O(n)
看个小代码
#include <stdlib.h>
main()
{ int m,n,p; // scanf("m=%dn=%dp=%d",&m,&n,&p); // printf("%d%d%d\n",m,n,p); m=3; n=m&(-1); p=m&&(-2);
printf("%d%d\n",n,p); } 一、
n=m&(-1);中n恒等m
p=m&&(-2);中p恒等1;(改称0则p为0)了
-1的二进制为11;
二、
屏蔽的两句使用时,应该
输入 m=1n=2p=3
不能 1 2 3
RAID先讲一下奇偶校验 串行数据在传输过程中,由于干扰可能引起信息的出错,例如,传输字符‘E’,其各位为: 奇偶校验码是一种通过增加冗余位使得码字中“1”的个数为奇数或偶数的编码方法,它是一种检错码。 各阶层磁盘阵列(RAID)介绍: RAID 1:Mirroring (磁盘镜射) RAID 0+1:Mirror + Striping (磁盘镜射+切分/延展) RAID 3:Parallel with Parity (平行同位检查) RAID 5:Striping with Rotating Parity (切分/延展+轮转同位) 前言: 现在己经有很多主机板都内建了IDE RAID芯片,除了提供ATA/133功能外,也提供了磁盘阵列功能,给使用者一个完整的IDE周边解决方案。不过,应该还有很多人弄不清楚磁盘阵列是什么,对磁盘阵列的使用及工作原理也有很多疑问。在这里我们就来介绍一下磁盘阵列(RAID)的概念与工作原理,相信对各位会有所帮助。 什么是磁盘阵列? 磁盘阵列简称RAID(Redundant Arrays of Inexpensive Disks),有”价格便宜且多余的磁盘阵列”之意。其原理是利用数组方式来作磁盘组,配合数据分散排列的设计,提升数据的安全性。磁盘阵列主要针对硬盘,在容量及速度上,无法跟上CPU及内存的发展,提出改善方法。磁盘阵列是由很多便宜、容量较小、稳定性较高、速度较慢磁盘,组合成一个大型的磁盘组,利用个别磁盘提供数据所产生的加成效果来提升整个磁盘系统的效能。同时,在储存数据时,利用这项技术,将数据切割成许多区段,分别存放在各个硬盘上。 磁盘阵列还能利用同位检查(Parity Check)的观念,在数组中任一颗硬盘故障时,仍可读出数据,在数据重构时,将故障硬盘内的数据,经计算后重新置入新硬盘中。 磁盘阵列的由来: 由美国柏克莱大学(University of California-Berkeley)在1987年,发表的文章:”A Case for Redundant Arrays of Inexpensive Disks”。文章中,谈到了RAID这个字汇,而且定义了RAID的5层级。柏克莱大学研究其研究目的为,反应当时CPU快速的性能。CPU效能每年大约成长30~50%,而硬磁机只能成长约7%。研究小组希望能找出一种新的技术,在短期内,立即提升效能来平衡计算机的运算能力。在当时,柏克莱研究小组的主要研究目的是效能与成本。 另外,研究小组也设计出容错(fault-tolerance),逻辑数据备份(logical data redundancy),而产生了RAID 理论。研究初期,便宜(Inexpensive)的磁盘也是主要的重点,但后来发现,大量便宜磁盘组合并不能适用于现实的生产环境,后来Inexpensive被改为independence,许多独立的磁盘组。 磁盘阵列,时事所趋: 自有PC以来,硬盘是最常使用的储存装置。但在整个计算机系统架构中,跟CPU与RAM来比,硬盘的速度是PC中最弱的设备之一。所以,为了加速计算机整体的数据流量,增加储存的吞吐量,进阶改进硬盘数据的安全,磁盘阵列的设计因应而生。 硬盘随着科技的日新月异,现在其容量已达40GB以上,转速到了1万转,甚至15000转,而且价格实在是很便宜,再加现在企业流行,人力资源规画(Enterprise Resource Planning:ERP)是每个公司建构网络的主要目标。所以,利用局域网络来传递数据,服务器所使用的硬盘显得非常重要,除了容量大、速度快之外,稳定更是基本要求。基于此因,磁盘阵列开始广泛的应用在个人计算机上。 磁盘阵列其样式有三种,一是外接式磁盘阵列柜、二是内接式磁盘阵列卡,三是利用软件来仿真。外接式磁盘阵列柜最常被使用大型服务器上,具可热抽换(Hot Swap)的特性,不过这类产品的价格都很贵。内接式磁盘阵列卡,因为价格便宜,但需要较高的安装技术,适合技术人员使用操作。另外利用软件仿真的方式,由于会拖累机器的速度,不适合大数据流量的服务器。 由上述可知,现在IDE磁盘阵列大行其道的道理;IDE接口硬盘的稳定度与效能表现已有很大的提升,加上成本考量,所以采用IDE接口硬盘来作为磁盘阵列的决解方案,可说是最佳的方式。
各阶层磁盘阵列(RAID)介绍: 磁盘阵列是由2个以上的硬盘,仿真一个逻辑硬盘出现在系统中;使用磁盘阵列控制器以达成其存在,利用不同数组形式,仿真各种层级。现在我们先来了解磁盘阵列(RAID)到底有几种模式,一般最常提到及应用的RAID层级分为0、1、0+1、3及5。另外还有一些极少用到的RAID 4及RAID 6在此我们就不提它了。 以下就是各个阶层的介绍及图解: RAID 0:Striping/Span (切分/延展) RAID 0,它是将数据储存在2个以上的硬盘机,其将全部磁盘驱动器的储存容量合并,藉由将数据切分到全部的磁盘驱动器上,进行平行读写,而达到提高效能增加容量。但是缺点是完全没有容错能力,只要有一个磁盘故障,就会导致数组磁盘的所有数据,毁于一旦无法挽回。 以下是原理示意图及实体概念图: RAID 1:Mirroring (磁盘镜射) RAID 1,必须由2个以上的硬盘所组成,由磁盘阵列(RAID)来控制,将数据同时写入第1个与第2个硬盘,其2组硬盘上的数据完全相同,也就是其中一个硬盘是用来作备份用途;当其中有一个硬盘故障时,系统照常运作正常。RAID 1是所有RAID阶层上,经济效益最好,效能很高,极佳的数据安全性。是所有阶层中使用最多最广最符合当初RAID设计概念的一种。唯一小缺点是,其数组磁盘容量是全部硬盘容量的一半。 RAID 0+1:Mirror + Striping (磁盘镜射+切分/延展) RAID 0+1,是结合了RAID 0与1两种模式,这个阶层须具备4个或以上的双数硬盘所组成。这个模式是由2个硬盘遵守RAID 0规范,设定成一组,再由每组间遵循RAID 1的规范,使RAID 0+1拥有容错力及整体读写速度与数据安全性。不过,缺点是成本很高。 RAID 3:Parallel with Parity (平行同位检查) RAID 3,最少须3个硬盘或以上,这个阶层的磁盘阵列具备了同位高阶智能型算法,利用一个硬盘来储存其运算出来的同位值的数据。当数组磁盘中有一个硬盘发生故障时(当然不能是同位碟),只要换上新硬盘后,磁盘阵列控制器就能利用同位碟的数据,重新演算得到其旧有数据并回写建立。因为其同位检查数据是将数据切割成数个区段,利用XOR算法计算出同位数据;而其区段以Bytes计算时,称为RAID 3,如果是以Block计算时,就称为RAID 4。所以RAID 3在整体读写效能会较慢较差,但在成本上会比RAID 0+1还省一点,其数组磁盘整体容量计算公式为N-1。 RAID 5:Striping with Rotating Parity (切分/延展+轮转同位) RAID 5,最少须3个硬盘,其工作原理与RAID 3相似,主要差别是其同位数据没有固定在同个硬盘,是以轮流方式储存在每个硬盘上,故称轮转同位。当磁盘阵列控制器利用XOR演算出同位检查数据后,会随着数据分别写入各台硬盘上,因此整体读写效能比RAID 3要好一些,当然比RAID 0要差。不过在大型数据处理时,需同时读写多个硬盘,而同位检查是由磁盘阵列控制器的XOR逻辑所控制的,所以数据处理越大越多时,一定会有所遗失,但这个阶层的RAID还是可以提供很高的容错能力... 11月9日 外企面试官最爱提的10个问题(附答案) 1.请介绍一下你自己。 这是外企常问的问题。一般人回答这个问题过于平常,只说姓名、年龄、爱好、工作经验,这些在简历上都有,其实,外企最希望知道的是求职者能否胜任工 作,包括:最强的技能、最深入研究的知识领域、个性中最积极的部分、做过的最成功的事,主要的成就等,这些都可以和学习无关,也可以和学习有关,但要突出 积极的个性和做事的能力,说得合情合理外企才会相信。外企很重视一个人的礼貌,求职者要尊重考官,在回答每个问题之后都说一句“谢谢”。外企喜欢有礼貌的 求职者。 2.在学校你最不喜欢的课程是什么?为什么? 这个问题外企不希望求职者直接回答“数学”、“体育”之类的具体课程,如果直接回答还说明了理由,不仅代表求职者对这个学科不感兴趣,可能还代表将来 也会对要完成的某些工作没有兴趣。这个问题外企招聘者最想从求职者口里听到:我可能对个别科目不是特别感兴趣,但是正因为这样,我会花更多的时间去学习这 门课程,通过学习对原本不感兴趣的科目也开始有了兴趣,对于本来就有兴趣的科目我自然学习得更认真,所以各门课的成绩较为平衡。通过这样的问题,外企可以 找到对任何事情都很感兴趣的求职者。 3.说说你最大的优缺点? 这个问题外企问的概率很大,通常不希望听到直接回答的缺点是什么等,如果求职者说自己小心眼、爱忌妒人、非常懒、脾气大、工作效率低,外企肯定不会录 用你。外企喜欢求职者从自己的优点说起,中间加一些小缺点,最后再把问题转回到优点上,突出优点的部分。外企喜欢聪明的求职者。 4.你认为你在学校属于好学生吗? 外企的招聘者很精明,问这个问题可以试探出很多问题:如果求职者学习成绩好,就会说:“是的,我的成绩很好,所有的成绩都很优异。当然,判断一个学生 是不是好学生有很多标准,在学校期间我认为成绩是重要的,其他方面包括思想道德、实践经验、团队精神、沟通能力也都是很重要的,我在这些方面也做得很好, 应该说我是一个全面发展的学生。”如果求职者成绩不尽理想,便会说:“我认为是不是一个好学生的标准是多元化的,我的学习成绩还可以,在其他方面我的表现 也很突出,比如我去很多地方实习过,我很喜欢在快节奏和压力下工作,我在学生会组织过××活动,锻炼了我的团队合作精神和组织能力。” 有经验的招聘者一 听就会明白,外企喜欢诚实的求职者。 5.说说你的家庭。 外企面试时询问家庭问题不是非要知道求职者家庭的情况,探究隐私,外企不喜欢探究个人隐私,而是要了解家庭背景对求职者的塑造和影响。外企希望听到的 重点也在于家庭对求职者的积极影响。外企最喜欢听到的是:我很爱我的家庭!我的家庭一向很和睦,虽然我的父亲和母亲都是普通人,但是从小,我就看到我父亲 起早贪黑,每天工作特别勤劳,他的行动无形中培养了我认真负责的态度和勤劳的精神。我母亲为人善良,对人热情,特别乐于助人,所以在单位人缘很好,她的一 言一行也一直在教导我做人的道理。外企相信,和睦的家庭关系对一个人的成长有潜移默化的影响。 6.说说你对行业、技术发展趋势的看法? 外企对这个问题很感兴趣,只有有备而来的求职者能够过关。求职者可以直接在网上查找对你所申请的行业部门的信息,只有深入了解才能产生独特的见解。外 企认为最聪明的求职者是对所面试的公司预先了解很多,包括公司各个部门,发展情况,在面试回答问题的时候可以提到所了解的情况,外企欢迎进入企业的人是 “知己”,而不是“盲人”。 7.就你申请的这个职位,你认为你还欠缺什么? 外企喜欢问求职者弱点,但精明的求职者一般不直接回答。他们希望看到这样的求职者:继续重复自己的优势,然后说:“对于这个职位和我的能力来说,我相 信自己是可以胜任的,只是缺乏经验,这个问题我想我可以进入公司以后以最短的时间来解决,我的学习能力很强,我相信可以很快融入公司的企业文化,进入工作 状态。”外企喜欢能够巧妙地躲过难题的求职者。 8.你期望的工资是多少? 外企的工资水平是很灵活的,何种能力拿何种工资。外企喜欢直率的人,但这个问题却不能正面回答,外企希望听到:“以我的能力和我的优势,我完全可以胜 任这个职位,我相信我可以做得很好。但是贵公司对这个职位的描述不是很具体,我想还可以延后再讨论”。外企欢迎求职者给其定薪的自由度,而不是咬准一个价 码。 9.你能给公司带来什么? 外企很想知道未来的员工能为企业做什么,求职者应再次重复自己的优势,然后说:“就我的能力,我可以做一个优秀的员工在组织中发挥能力,给组织带来高 效率和更多的收益”。外企喜欢求职者就申请的职位表明自己的能力,比如申请营销之类的职位,可以说:“我可以开发大量的新客户,同时,对老客户做更全面周 到的服务,开发老客户的新需求和消费。”等等。 10.你还有什么问题吗? 外企的这个问题看上去可有可无,其实很关键,外企不喜欢说“没有问题”的人,因为其很注重员工的个性和创新能力。外企不喜欢求职者问个人福利之类的问 题,如果有人这样问:贵公司对新入公司的员工有没有什么培训项目,我可以参加吗?或者说贵公司的晋升机制是什么样的?外企将很欢迎,因为体现出你对学习的 热情和对公司的忠诚度以及你的上进心。 MFC 消息映射机制---- 我们可以看到,在MFC的框架结构下,可以进行消息处理的类的头文件里面都会含有DECLARE_MESSAGE_MAP()宏,这里主要进行消息映射和消息处理函数的声明。可以进行消息处理的类的实现文件里一般都含有如下的结构。
---- 而AFX_MSGMAP主要作用是两个,一:用来得到基类的消息映射入口地址。二:得到本身的消息映射入口地址。 ---- 实际上,MFC把所有的消息一条条填入到AFX_MSGMAP_ENTRY结构中去,形成一个数组,该数组存放了所有的消息和与它们相关的参数。同时通过AFX_MSGMAP能得到该数组的首地址,同时得到基类的消息映射入口地址,这是为了当本身对该消息不响应的时候,就调用其基类的消息响应。 ---- 现在我们来分析MFC是如何让窗口过程来处理消息的,实际上所有MFC的窗口类都通过钩子函数_AfxCbtFilterHook截获消息,并且在钩子函数_AfxCbtFilterHook中把窗口过程设定为AfxWndProc。原来的窗口过程保存在成员变量m_pfnSuper中。 在MFC框架下,一般一个消息的处理过程是这样的 1.函数AfxWndProc接收Windows操作系统发送的消息。 2.函数AfxWndProc调用函数AfxCallWndProc进行消息处理,这里一个进步是把对句柄的操作转换成对CWnd对象的操作。 函数AfxCallWndProc调用CWnd类的方法WindowProc进行消息处理。注意AfxWndProc和AfxCallWndProc都是AFX的API函数。而WindowProc已经是CWnd的一个方法。所以可以注意到在WindowProc中已经没有关于句柄或者是CWnd的参数了。 方法WindowProc调用方法OnWndMsg进行正式的消息处理,即把消息派送到相关的方法中去处理。消息是如何派送的呢?实际上在CWnd类中都保存了一个AFX_MSGMAP的结构,而在AFX_MSGMAP结构中保存有所有我们用ClassWizard生成的消息的数组的入口,我们把传给OnWndMsg的message和数组中的所有的message进行比较,找到匹配的那一个消息。实际上系统是通过函数AfxFindMessageEntry来实现的。找到了那个message,实际上我们就得到一个AFX_MSGMAP_ENTRY结构,而我们在上面已经提到AFX_MSGMAP_ENTRY保存了和该消息相关的所有信息,其中主要的是消息的动作标识和跟消息相关的执行函数。然后我们就可以根据消息的动作标识调用相关的执行函数,而这个执行函数实际上就是通过ClassWizard在类实现中定义的一个方法。这样就把消息的处理转化到类中的一个方法的实现上。举一个简单的例子,比如在View中对WM_LButtonDown消息的处理就转化成对如下一个方法的操作。 注意这里CView::OnLButtonDown(nFlags, point)实际上就是调用CWnd的Default()方法。 而Default()方法所做的工作就是调用DefWindowProc对消息进行处理。这实际上是调用原来的窗口过程进行缺省的消息处理。 如果OnWndMsg方法没有对消息进行处理的话,就调用DefWindowProc对消息进行处理。这是实际上是调用原来的窗口过程进行缺省的消息处理。 ---- 继续上面的例子,根据我们对MFC消息机制的分析,我们很容易得到除了上面的方法,我们至少还可以在另外两个地方进行操作。 ---- 一:在消息的处理方法里面即OnChar中,当然最后我们不再调用CEdit::OnChar(nChar, nRepCnt, nFlags),而是直接调用DefWindowProc(WM_CHAR,nChar,MAKELPARAM (nRepCnt,nFlags))。因为从我们上面的分析可以知道CEdit::OnChar(nChar, nRepCnt, nFlags)实际上也就是对DefWindowProc方法的调用。 ---- 二:我们可以直接重载DefWindowProc方法,对message类型等于WM_CHAR的,直接修改nChar的值即可。
发送消息到一个窗口可以采用传送(send)或寄送(post)方式,这两种方式之间的主要区别是消息被接收对象收到后是否立即被处理。
Windows将所有的消息值分为4段: Windows系统消息:0x0000~0x03FF 用户自定义窗口消息:0x0400~0x7FFF Windows保留值:0x8000~0xBFFF 应用程序的字符串消息:0xC000~0xFFFF
利用#define语句直接定义自己的消息,如: #define WM_USER1 WM_USER+0 #define WM_USER2 WM_USER+1 #define WM_MYMESSAGE WM_USER+2
自定义消息处理函数时,必须在函数返回类型前面加上afx_msg标识。 VC对话框知识 一、模式对话框
使用有模式对话框时在对话框弹出后调用函数不会立即返回,而是等到对话框销毁后才会返回(请注意在对话框弹出后其他窗口的消息依然会被传递)。所以在使用对话框时其他窗口都不能接收用户输入。创建有模式对话框的方法是调用CDialog::DoModal()。下面的代码演示了这种用法: CYourView::OnOpenDlg()
{
CYourDlg dlg;
int iRet=dlg.DoModal();
}
CDialog::DoModal()的返回值为IDOK,IDCANCEL。表明操作者在对话框上选择“确认”或是“取消”。由于在对话框销毁前DoModal不会返回,所以可以使用局部变量来引用对象。在退出函数体后对象同时也会被销毁。而对于无模式对话框则不能这样使用,下节5.3 创建无模式对话框中会详细讲解。 你需要根据DoModal()的返回值来决定你下一步的动作,而得到返回值也是使用有模式对话框的一个很大原因。 使用有模式对话框需要注意一些问题,比如说不要在一些反复出现的事件处理过程中生成有模式对话框,比如说在定时器中产生有模式对话框,因为在上一个对话框还未退出时,定时器消息又会引起下一个对话框的弹出。 同样的在你的对话框类中为了向调用者返回不同的值可以调用CDialog::OnOK()或是CDialog::OnCancel()以返回IDOK或IDCANCEL,如果你希望返回其他的值,你需要调用 下面的代码演示了如何使用自己的函数来退出对话框: void CMy52_s1View::OnLButtonDown(UINT nFlags, CPoint point)
{//创建对话框并得到返回值
CView::OnLButtonDown(nFlags, point);
CTestDlg dlg;
int iRet=dlg.DoModal();
CString szOut;
szOut.Format("return value %d",iRet);
AfxMessageBox(szOut);
}
//重载OnOK,OnCancel
void CTestDlg::OnOK()
{//什么也不做
}
void CTestDlg::OnCancel()
{//什么也不做
}
//在对话框中对三个按钮消息进行映射
void CTestDlg::OnExit1()
{
CDialog::OnOK();
}
void CTestDlg::OnExit2()
{
CDialog::OnCancel();
}
void CTestDlg::OnExit3()
{
CDialog::EndDialog(0XFF);
}
由于重载了OnOK和OnCancel所以在对话框中按下Enter键或Escape键时都不会退出,只有按下三个按钮中的其中一个才会返回。 此外在对话框被生成是会自动调用BOOL CDialog::OnInitDialog(),你如果需要在对话框显示前对其中的控件进行初始化,你需要重载这个函数,并在其中填入相关的初始化代码。利用ClassWizard可以方便的产生一些默认代码,首先打开ClassWizard,选择相应的对话框类,在右边的消息列表中选择WM_INITDIALOG并双击,如图,ClassWizard会自动产生相关代码,代码如下: BOOL CTestDlg::OnInitDialog()
{
/*先调用父类的同名函数*/
CDialog::OnInitDialog();
/*填写你的初始化代码*/
return TRUE;
}
有关对对话框中控件进行初始化会在5.4 在对话框中进行消息映射中进行更详细的讲解。 二、非模式对话框 无模式对话框与有模式对话框不同的是在创建后其他窗口都可以继续接收用户输入,因此无模式对话框有些类似一个弹出窗口。创建无模式对话框需要调用 void CYourView::OnOpenDlg(void)
{
/*假设IDD_TEST_DLG为已经定义的对话框资源的ID号*/
CTestDlg *dlg=new CTestDlg;
dlg->Create(IDD_TEST_DLG,NULL);
dlg->ShowWindows(SW_SHOW);
/*不要调用 delete dlg;*/
}
在上面的代码中我们新生成了一个对话框对象,而且在退出函数时并没有销毁该对象。因为如果此时销毁该对象(对象被销毁时窗口同时被销毁),而此时对话框还在显示就会出现错误。那么这就提出了一个问题:什么时候销毁该对象。我时常使用的方法有两个:
同样无模式对话框的另一个作用还可以用来在用户在对话框中的输入改变时可以及时的反映到其他窗口。下面的代码演示了在对话框中输入一段文字,然后将其更新到视图的显示区域中,这同样也是利用了消息进行通知和数据传递。 /*在对话框中取出数据,并向其他窗口发送消息和数据,将数据指针作为一个参数发送*/
void CTestDlg2::OnCommBtn()
{
char szOut[30];
GetDlgItemText(IDC_OUT,szOut,30);
m_pParent->SendMessage(WM_DLG_NOTIFY,(WPARAM)szOut);
}
/*在消息接收窗口中*/
/*映射消息处理函数*/
ON_MESSAGE(WM_DLG_NOTIFY,OnDlgNotifyMsg)
/*在视图中绘制出字符串 m_szOut*/
void CMy53_s1View::OnDraw(CDC* pDC)
{
CMy53_s1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->TextOut(0,0,"Display String");
pDC->TextOut(0,20,m_szOut);
}
/*处理通知消息,保存信息并更新显示*/
LONG CMy53_s1View::OnDlgNotifyMsg(WPARAM wP,LPARAM lP)
{
m_szOut=(char*)wP;
Invalidate();
return 0;
}
此外这种用法利用消息传递数据的方法对有模式对话框和其他的窗口间通信也一样有效。 /*SendMessage同步阻塞,它不但发送消息到消息队列,还需要等待消息被执行完才返回; PostMessage异步非阻塞函数,就是个异步函数,它只管发送一个消息,而不管这个消息是否被处理,就马上返回*/
三、通用对话框
在Windows系统中提供了一些通用对话框如:文件选择对话框如图,颜色选择对话框如图,字体选择对话框如图。在MFC中使用CFileDialog,CColorDialog,CFontDialog来表示。一般来讲你不需要派生新的类,因为基类已经提供了常用的功能。而且在创建并等待对话框结束后你可以通过成员函数得到用户在对话框中的选择。 CFileDialog文件选择对话框的使用:首先构造一个对象并提供相应的参数,构造函数原型如下:
创建文件对话框可以使用DoModal(),在返回后可以利用下面的函数得到用户选择:
CColorDialog颜色选择对话框的使用:首先通过CColorDialog::CColorDialog( COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd* pParentWnd = NULL )构造一个对象,其中clrInit为初始颜色。通过调用DoModal()创建对话框,在返回后调用COLORREF CColorDialog::GetColor( )得到用户选择的颜色值。 CFontDialog字体选择对话框的使用:首先构造一个对象并提供相应的参数,构造函数原型如下:
类的几个小问题(2)C++程式设计过程中,const的使用可以频度是非常高的.它在保证程式安全方面起到了不可估量的作用. 用一句话来表达最确切不过了:”小兵立大功”. 有了const,那么mutable当然缺不了. 然作为const的同胞兄弟,volatile却在很多人的视野中消失.其实volatile担负的责任有何尝小呢? 自然,它们的用法多样而灵巧,以至新手迷惑久久,下面就来系统的探讨总结一下吧: 一.一般应用 a.修饰参数 b.修饰函数返回值 这个地方还有很多的细节问题(譬如在连续赋值、返回的临时对象的处理、 二、难点 a.const对象只能访问const成员函数,而非const对象可以访问任意 4.谈谈volatile和”完全const对象” 11月8日 类的几个小问题1空类大小不为零?
对象存在的话,就必须在内存中占据一个地方,
这是现在基本上所有编译器实现的对象模型的一个基本假设 (1) 允许已定义类名出现在类的说明中
(2) 类可以无名,用于直接声明对象 (3) 类是一个程序包。可以只有数据成员或只有成员函数,或者为空。空类的对象大小不为零,空类对象具有地址 2vtable
虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。
——摘自MSDN vtable是指一张函数指针表,如同C++中类的实现一样,vtable中的指针指向一个对象支持的接口成员函数。 ——摘自MSDN 每个虚函数都在vtable中占了一个表项,保存着一条跳转到它的入口地址的指令(实际上就是保存了它的入口地址)。当一个包含虚函数的对象(注意,不是对象的指针)被创建的时候,它在头部附加一个指针,指向vtable中相应位置。调用虚函数的时候,不管你是用什么指针调用的,它先根据vtable找到入口地址再执行,从而实现了“动态联编”。而不像普通函数那样简单地跳转到一个固定地址。 一、基础略(限于篇幅,请参阅相应的c++书籍):
1、多态性:使用基础类的指针动态调用其派生类中函数的特性。 2、动态联编:在运行阶段,才将函数的调用与对应的函数体进行连接的方式,又叫运行时联编或晚捆绑。 二、过程描述: 1、编译器发现一个类中有虚函数,编译器会立即为此类生成虚拟函数表 vtable(后面有对vtable的分析)。虚拟函数表的各表项为指向对应虚拟函数的指针。 2、编译器在此类中隐含插入一个指针vptr(对vc编译器来说,它插在类的第一个位置上)。 有一个办法可以让你感知这个隐含指针的存在,虽然你不能在类中直接看到它,但你可以比较一下含有虚拟函数时的类的尺寸和没有虚拟函数时的类的尺寸,你能够发现,这个指针确实存在。 class cnovirtualfun cnovirtualfun obj; 3、在调用此类的构造函数时,在类的构造函数中,编译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable。这就将类与此类的vtable联系了起来。 菱形继承的类中会有两个vptr,指向不同父类。区别于v型继承,没有virtual继承,会有两份祖父类。不用virtual继承就要把基类定义为纯虚类。 4、在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable,从而实现了多态性。在此时才能真正与函数体进行连接,这就是动态联编。 三、vtable 分析: 分析1:虚拟函数表包含此类及其父类的所有虚拟函数的地址。如果它没有重载父类的虚拟函数,vtable中对应表项指向其父类的此函数。反之,指向重载后的此函数。 分析2:虚拟函数被继承后仍旧是虚拟函数,虚拟函数非常严格地按出现的顺序在 vtable 中排序,所以确定的虚拟函数对应 vtable 中一个固定的位置n,n是一个在编译时就确定的常量。所以,使用vptr加上对应的n,就可得到对应函数的入口地址。 四、编译器调用虚拟函数的汇编码(参考think in c++): push funparam ;先将函数参数压栈 push si ;将this指针压栈,以确保在当前类上操作 mov bx,word ptr[si] ;因为vc++编译器将vptr放在类的第一个位置上,所以bx内为vptr call word ptr[bx+n] ;调用虚拟函数。n = 所调用的虚拟函数在对应 vtable 中的位置 纯虚函数: 一、引入原因: 1、为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。 2、在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。 为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual returntype function()= 0;),则编译器要求在派生类中必须予以重载以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。 二、纯虚函数实质: 1、类中含有纯虚函数则它的vtable表不完全,有一个空位,所以,不能生成对象(编译器绝对不允许有调用一个不存在函数的可能)。在它的派生类中,除非重载这个函数,否则,此派生类的vtable表亦不完整,亦不能生成对象,即它也成为一个纯虚基类。 虚函数与构造、析构函数: 1、构造函数本身不能是虚拟函数;并且虚机制在构造函数中不起作用(在构造函数中的虚拟函数只会调用它的本地版本)。 想一想,在基类构造函数中使用虚机制,则可能会调用到子类,此时子类尚未生成,有何后果!?。 2、析构函数本身常常要求是虚拟函数;但虚机制在析构函数中不起作用。 若类中使用了虚拟函数,析构函数一定要是虚拟函数,比如使用虚拟机制调用delete,没有虚拟的析构函数,怎能保证delete的是你希望delete的对象。 虚机制也不能在析构函数中生效,因为可能会引起调用已经被delete掉的类的虚拟函数的问题。 补充一下——虚拟析构函数: 条款14 基类的析构函数一定要定义为虚拟函数(From Effective C++) 什么时候才应该将析构函数定义为虚拟呢?当类至少拥有一个虚拟函数时。拥有虚拟函数意味着一个类是派生类的接口,在这种情况下,一个派生类的对象可能通过一个基类指针来销毁。 如果基类的析构函数不是虚拟的,那么派生类的析构函数将不会被调用。 #include <iostream> class A class B: public A{ void main(){ 程序运行结果: A construction 如果去掉 virtual 结果为: A construction C++语言标准的叙述异乎寻常的清楚:当你试图使用基类的指针删除派生类的对象时,如果基类没有将析构函数定义为虚拟函数,那么结果是未定义的。
对象切片: 向上映射(子类被映射到父类)的时候,会发生子类的vtable 完全变成父类的vtable的情况。这就是对象切片。 原因:向上映射的时候,接口会变窄,而编译器绝对不允许有调用一个不存在函数的可能,所以,子类中新派生的虚拟函数的入口在vtable中会被强行“切”掉,从而出现上述情况。 虚拟函数使用的缺点 优点讲了一大堆,现在谈一下缺点,虚函数最主要的缺点是执行效率较低,看一看虚拟函数引发的多态性的实现过程,你就能体会到其中的原因。 11月6日 MPEG4 & H.264学习笔记之二——视频编码基本概念及时域模型3.1压缩(compress) 动词: 挤压到更小的空间中;即condense 压缩(conpress) 名词: 压缩的行为或是压缩的状态 压缩是把数据用更小的空间来存放的技术.视频压缩(视频编码)是把数字视频流序列用更少的数据位进行存放的方法."Raw"或叫没压缩过的视频需要大量的码(大约每秒信息216M),而且压缩对于数字视频的存储和传输来说都是需要的. 压缩包括一对互补的系统,一个编码器(encoder)和一个解压器(decoder).编码器把原数据在传输或存放之前转变为压缩格式(占用更少的数据位),而解压器把压缩的格式转会到原来的视频数据格式上.编码器/解码器对经常被叫做CODEC(enCOder/DECoder) 数据压缩是通过移除数据冗余来实现的,比如说,对于数据重构过程中无用的数据。很多种数据都有统计上的冗余性,它们就可以通过无损压缩进行有效的压缩,这样的标准比如说JPEG-LS,它可以达到3-4倍的压缩。有损压缩可以达到更高的压缩比。在有损压缩系统中,解压数据与源码流数据是不同的,高压缩率是通过视频质量的下降来达到的。有损视频压缩系统是建立在删除主观冗余的原理之上的,从图象或视频中删掉的部分不会很大程度上影响观察者对于视频质量的认识的。 大多数视频编码方法寻找空间和时间上的冗余来达到压缩的效果。在时间域中,连续几帧的视频通常有很强的相关性,特别是当时域采样率是非常高的时候尤其如止。在空间域中,通常像素采样点之间是相互关联的,比如说,相邻象素之间很相近。 H.264和MPEG4视频标准共用了一部分特征。这两种标准都假设了一种以块(block)为基础的运动补偿,变换,量化和熵编码。我们主要关注到这些主要的方法中,并从时间模型开始,接下来是图象变换,量化,预测式编码和熵编码。并以对于一个图象采样块进行编码和解码的过程进行描述。 3.2 视频编解码器 CODEC用一种模型来表示原始视频流(一个被有效编码的表示方式,并可以用它来重建视频数据的近似结果或尽量取得高的码率。这两个目标(压缩效率和高质量)通常是相矛盾的,因为一个低的压缩码率通常在解压部分会降低图象的质量。码率和质量的平衡我们会在之后进行介绍 视频编码器是由三个主要的功能部件实现的:时域模型,空域模型和熵编码。时域模型的输入为一个未压缩的视频流序列。时域模型试图用邻近帧的相似性来消除了时域冗余,通常是构造通当前帧的预测。在MPEG4视频部分和H.264中,预测通常从一个或多个之前或之后的帧来进行的,并通过对于帧之间的差别进行补偿。时域模型的输出是一个剩余帧(通过从实际当前帧中减去预测值得到),而一系列的模型参数,通常是一系列用来描述运动是如何补偿的运动向量。 剩余帧构成了时域模型的输入,它会利用邻近采样点的相似性来降低空域的冗余。在MPEG4视频部分和H.264中,这通常通过一些变换来对样点进行处理来实现。变换把采样点转到其他的域中,在这些域中用变换系数来表示。这些系数被量化来删除不明显的值,只留下很少的大系数来对剩余帧进行表示。空域模型的输出是一系列的量化变换的系数。 时域模型的参数(通常是运动向量)和空域模型的参数(系数)通常用熵编码来进行压缩。这就删除掉了统计上的冗余度(比如,用短二进制码表示当前的向量和系数)并制造出一个压缩流或文件来进行传输或存储。一个压缩的序列由编码的运动向量参数,编码的剩余系数和头信息表示。 时域预测编码,得到剩余帧(即运动向量),空域根据邻近点相关性得到系数,最后熵编码删除统计上的冗余。 视频解码器从一个压缩流中构造一个视频帧。系数和运动向量由熵解码器进行解码,然后空域模型构建出一个版本的剩余帧。解码器利用运动向量参数与一个或多个解压帧来构成一个对当前帧的预测,然后帧就可以通过加入这个剩余帧来得到。 3.3 时域模型 3.3.1 从前一视频帧进行预测 3.3.2 由于运动造成的改变 如果光流域是准确描述的,那么它应该可以构成一个对大多数像素点准确的预测,方法即为沿着光流向量移动参考帧中的每个像素点。然而,种种原因之下,这并不是一个实用的运动补偿的方法.对于光流的准确的计算对于计算来说是非常敏感的而且把每个像素点的光流传给解码器也是必要的,以使它能重构造预测帧(这样就得到了大量的传输数据,与我们小剩余值的目标是相矛盾的)。 3.3.3 基于块的运动估计和补偿 1. 在参考帧中查找一帧(过去的或以后的,已被编码的或传输的),来找到一个相匹配的M * N的区域。这是由在查找区域中比较M * N的块,并找到一个最接近这一块的区域。一个流行的匹配方式是用把两个块的能量作差,这样能量相差最小的两个区域被认为是最佳的匹配结果。这个查找匹配的过程被叫做运动估计。 2. 选定的区域成为对于当前M * N块的预测块,它被减掉当前的块来构成一个M*N的剩余块(运动补偿). 3. 剩余块被编码并传输,当前块和选定块的差值(运动向量)也被传输. 解码器使用接收到的运动向量来重建预测区域并解压剩余块,加上之前的预测块来重建一个原始块。 基于块的运动补偿这么流行是有很多原因的。它很直接,计算性上也很易处理,它与矩形视频帧很相适应,并且使用基于块的图形变换(比如DCT等),而且它对于视频序列提供了一个有很效的时域模型。然而它也有一些缺点,比如说,实际物体中几乎没有平滑的边缘来进行矩形边界的匹配,物体通常在帧之间用很小的像素点位置移动(比如说可变形的物体,旋转和扭曲),而且很多种运动是难以用基于块的方法进行补偿的。尽管它有这些缺点,基于块的运动补偿是当前所有的视频标准使用的时域模型的基础. 3.3.4 对于一个宏块的运动补偿 运动估计 运动补偿 在运动估计和补偿的过程中有很多不同方法。参考帧可以是之前的或之后的一帧,也可以是结合或是更多帧的搭配。。如果一个之后的帧用来进行参考的话,那么就要先对这一帧进行编码。在参考帧和当前帧之间有一个很大的改变的地方(比如说,一个场景的变化),也许不使用运动补偿进行编码宏块会更有效。这样编码器就选择帧内编码(在没有运动补偿的情况下进行编码.在移动场景中移动的物体很少符合16*16像素边缘而且这样也许使用可变的块大小进行运动估计和补偿会更高效。物体可能有很少的像素部分运动,这样使用在参考帧中插值法会是一种更加好的预测方法。 3.3.5 运动补偿块大小 3.3.6 子像素运动补偿 用4*4的块大小得到的剩余帧可以使用半采样插值并有更低的剩余能量。这种方法可以由从四分之一采样格来得到更小的剩余帧能量得到扩展。总体上说,“更好的”插值可以达到更好的运动补偿性能(更小的剩余帧能量),代价则是复杂度会更高一些。这样得到的性能提升会因为插值的步骤的增多而抵销。半采样插值相比整采样有更好的性能,四分之一采样插值会给出更好的效果,八分之一更胜之,以此类推。 一个运动补偿过的参考帧被从当前帧中减去,剩余帧的能量如下(用总绝对误差来近似SAE): 一个低的SAE表示更好的运动补偿性能。在每种情况下,子像素运动补偿相对整像素补偿都有更好的性能表现,而四分之一补偿会更好。"Grasses"序列有更复杂的运动,这样就更难以实施运动补偿,悲痛"Violen"和"Carphone"就更容易进行补偿了。 在四分之一采样插值中寻找一个匹配的4*4的块是比在没有插值的16*16的块中更加复杂的。除了更大的复杂度之外,因为每个块的运动向量都要被编码并传输到接收端以更好的重建图象,这样就有了编码上的性能损失了。因为块大小减小了,传输的向量数增加了。需要更多的位来表示半采样或四分之一采样向量,因为向量的更细节部分也必须被像整采样那样进行编码。这样有另复杂运动的补偿模式下就有编码效率上的平衡度了,因为运动补偿越准确,就有更多的数据来表示运动域,但是在不那么准确的情况下,就不需要那么多位了。 在图像的任意区域应用运动补偿是可以达到更好的性能的。比如说,如果我们试图在椭圆形的物体中进行运动补偿的话,我们可以在参考帧中找到一个理想的匹配。然而使用基于区域的运动补偿会遇到很多的实际困难,包括识别区域边界,指出边界的轮廓,在运动补偿之后编码剩余帧,MPEG-4视频包括了一系列的工具来支持基于区域的补偿和编码。 H.264标准三个框架 H.264的编解码框架与以前提出的标准如H.261、H.263及MPEG-1/2/4并无显著变化,也是基于
混合编码的方案:以运动矢量代表图象序列各帧的运动内容,使用前面已解码帧对其进行运动估
计和补偿或使用帧内预测技术,所得的图象参差值要经过变换、量化、熵编码等部分的处理。所
以,新标准的性能提升在于各个部分的技术方案的改进及新算法的应用。
新标准在提高图象传输的容错性方面做了大量工作,重新定义了适于图像的结构划分。在编码 时,图象帧各部分被划分到多个slice结构中去,每个slice都可以被独立解码不受其它部分的影
响。Slice由图象最基本的结构——宏块组成,每个宏块包含一个16×16的亮度块和两个8×8的色
度块。为进一步提高鲁棒性,整个系统被划分为视频编码层和网络抽取层。视频编码层主要描述
要传输的视频数据所承载的视频内容。而网络抽取层则是考虑不同的应用,如视频会议通信、
H.32X连续包的视频传输或RTP/UDP/IP的通信。
H.264标准分成三个框架(profile):Baseline、Main及X,代表了针对不同应用的算法集及技 术限定。其中,Baseline主要包含了低复杂度、低延时的技术特征;主要是针对交互式的应用;
考虑到了恶劣环境下的容错性,Baseline的内容基本都被其它更高级别的profile所包含。而Main
profile是针对更高编码效率的应用,如视频广播。X profile 的设计主要针对流媒体的应用,在
这一框架中所有容错技术和对比特流的灵活访问及切换技术都将包括其中。
Baseline profile的主要技术特征——
⑴ Baseline的解码器只对I slice及P slice进行操作。对于帧间预测,相比以前的标准,为了更精确的对图象的运动内容进行预测补偿,新标准允许宏块更进一步划分为16×16、16×8、8×16、8×8、8×4、4×8、4×4的子块;运动估计精确到经由6-tap滤波器得到的1/4;运动矢量由相邻块预测得到,其预测的差值被编码传输。
H.264支持多参考帧的预测,规定运动估计使用的参考帧数最多可达15帧,多参考帧的使用大 大提高了对图像传输的容错性,抑制了错误在空间和时间上的蔓延。对于所有的slice编码类型,
H.264支持两类帧内编码:4x4与16x16编码模式。对于4x4模式,每一个亮度4x4块有8种不同方向
上的预测模式及DC预测模式。对于16x16模式,每个16x16亮度块有4种帧内预测模式。而对于宏块
的8x8色度采样,采用与亮度16x16几乎相同的预测模式。为了保证slice的编码独立性,帧内预测
是不允许跨越slice边界的。对于变换、量化部分。不同于以前标准对预测参差值的变换编码使用
DCT变换,H.264使用了简单的整数变换。这种变换与DCT相比压缩性能几乎相同且有许多优势,其
核心变换的计算只使用加减、移位运算,避免了精度的损失。对变换参差系数的量化使用了52级
步长的量化器,而H.263标准只有31级。量化步长以12.5%递增,量化步长范围的扩大似的编码器
能够更灵活和精确的进行控制,在比特率和图象质量之间达到折中。对熵编码部分。对于要传输
的量化变换系数,若使用基于上下文的变长编码(CAVLC),它是根据前面已编码传输的量化变换
系数值的大小来选择接下来系数编码要使用的变长编码表。由于变长编码表的设计是基于相应的
统计条件,所以其性能要优于使用单一变长编码表。而对其它数据如头信息等,使用一种单一的
变长编码表(Exp-Golomb code)。新标准仍然使用基于块的预测及重构方式,为了去除由此产生的
影响图象主观质量的方块效应,H.264使用了去块效应滤波器。其主要思想是当块边界上两边差较
小则使用滤波器使差别“平滑”掉,若边界上图象特征明显就不使用滤波。这样既为减弱“块效应
”的影响又避免滤掉图象的客观特征。同时在相同主观质量下使得比特率减少5-10%。另外,对
图象数据的组织及传输。
在H.264标准中的图象宏块可以灵活的宏块组织顺序(FMO)划分为多个slice group;slice之间 是相互独立的可以任意的顺序传输到解码端(ASO)。而且在比特流中slice可以使用重复的方式
(RS)传输,这在slice数据出错的情况下可用来进行恢复,增强了图象传输的鲁棒性。同时slice
间的相互独立性抑制了错误的空间传播,因此提高了比特流的容错性。
⑵ Main profile的技术特征 Main profile包含Baseline profile的所有算法并具有额外的技术 特征,但它并不支持FMO、ASO及RS等技术。只支持对I、P、B slice的处理操作。在此框架内提出
了适配块划分尺寸的变换(ABT)的概念。此概念是针对帧间编码的,其主要思想是将对预测参差进
行变换编码的块尺寸与用来进行运动补偿的块尺寸联系起来。这样就尽可能的利用最大的信号长
度进行变换编码。但是由于复杂度的原因,进行变换的最大块尺寸被限制在8×8以下。对熵编码
部分,为更高效的进行编码,这里使用了基于上下文的算术编码(CABAC)使熵编码的性能进一步
提高。相比较CAVLC,在相同图象质量下编码电视信号使用CABAC将会使比特率减少10-15%。另,
Main profile不支持多个slice group的划分。
⑶ 相关的编码问题如何对已提出的预测模式进行选择(mode decision)和使用运动估计策略(ME) 历来都视频编码实现的重点研究课题。在H.263标准的实现软件中对模式的选择是简单的基于对阀
值的比较。在新标准的测试软件中使用了拉格朗日率失真优化策略,它是基于使用每种图象块尺
寸和每种预测模式而产生的参差及其传输的码率。这样,模式选择可以取得优化的率失真性能但
这是以提高运算复杂度为代价的。此优化操作是对下面拉各朗日函数的最小化: J = SATD + λ
•R 其中,R为对应传输的各部分的比特率;λ为优化参数,其与量化参数有很强的相关性。SATD
为经过哈德曼变换的4×4块的预测参差绝对值总和。对于所有帧内、帧间宏块编码模式及多参考
帧的选择都通过对拉各朗日函数的最小化来实现。通常,视频标准只是包括解码规范,而模式选
择的技术研究是属于编码端的范畴,所以不列在标准之内。 信号基本概念11、如果信号的取值为复数,则称此类信号为复值信号,简称复信号。 2、根据信号的取值在时间上是否是连续的(不考虑个别不连续点),可以将信号分为时间连续信号和时间离散信号。
希望同学们注意这里的"连续"概念。
除个别不连续点外,如果信号在所讨论的时间段内的任意时间点都有确定的函数值,则称此类信号为时间连续信号,简称连续信号。连续信号的函数值可以是连续的,也可以是离散的。 有两种连续信号:一种是取值也是连续的,即模拟信号,例如 信号f(t)=sin(t),一种是取值是离散的,即量化信号;同理,离散信号也有两种:一种是取值连续----这也叫抽样信号,一种是取值离散----这也叫数字信号
3、周期信号与非周期信号
若信号按照一定的时间间隔周而复始,并且无始无终,则称此类信号为周期信号。他们的表达式可以写作 f(t)=f(t+nT) n=0,1,2……(任意整数) 其中nT称为f(t)的周期,而满足关系式的最小T值则称为是信号的基本周期。为叙述方便,在不致引起混淆的情况下,如不作特别强调,今后我们将把"基本周期"简称为"周期"。 若信号在时间上不具有周而复始的特性,即周期信号的周期趋于无限大,则称此类信号为非周期信号。 这种把非周期信号的周期视作为无穷大,是一种很有用的思想方法。后面我们在学习傅里叶变换时,从周期信号的傅氏级数推广到非周期的一般信号傅氏变换,就是用到了这种思路。 而从非周期信号的傅氏变换推广到周期信号的傅氏变换,则利用了" '周期信号'可以由'非周期信号'周而复始地进行重复而得到 "的思路,把"非周期信号"作为一个片段,不断重复,就得到了一种周期信号。 怎么样"周期重复"呢?我们有相应的数学方法或思路来完成解决这个问题。这在我们学习完本章的"信号运算"(其中的加法、卷积运算)以及"奇异信号"中的"冲激信号"后就可以来做了。因为冲激信号具有"搬移特性",能够将其它信号"搬移(平移、移动)"到指定的位置,这个特性我们以后会学到。 4、 信号与功率信号
在研究过程中,我们有时需要知道信号的能量特性和功率特性。对连续信号f(t)和离散信号f(n),我们分别定义它们在区间 上的能量E为: 注意:这里的能量是定义在区间上的。相加的(积分也是一种相加)是信号的幅值的平方,一般把它称为是信号的能量。
信号的功率P是区间 上的平均功率,即: 大家知道功率是能量在一定时间内的平均值,所以在公式里要除时间长度。这个时间长度,对于离散信号来讲,就是其点数了。 如果信号的能量 ,则称之为能量有限信号,简称能量信号。 如果信号的功率 ,则称之为功率有限信号,简称功率信号。 为什么还要研究信号的功率呢?这是因为有的信号的能量太大了(等于无穷:))。研究没太大意义。但是不是都可以用功率来进行研究呢?不过,很遗憾,有些信号的能量变化实在太快了,没法表示,这时研究它的功率就没有意义。所以,能量和功率各有所长所短,根据需要来使用。 11月5日 GSM && CDMAGSM全名为:Global System for Mobile Communications,中文为全球移动通讯系统,俗称"全球通",是一种起源于欧洲的移动通信技术标准,是第二代移动通信技术,其开发目的是让全球各地可以共同使用一个移动电话网络标准,让用户使用一部手机就能行遍全球。我国于20世纪90年代初引进采用此项技术标准,此前一直是采用蜂窝模拟移动技术,即第一代GSM技术(2001年12月31日我国关闭了模拟移动网络)。目前,中国移动、中国联通各拥有一个GSM网,为世界最大的移动通信网络。GSM系统包括 GSM 900:900MHz、GSM1800:1800MHz 及 GSM-1900:1900MHz等几个频段 。
GSM系统有几项重要特点:防盗拷能力佳、网络容量大、手机号码资源丰富、通话清晰、稳定性强不易受干扰、信息灵敏、通话死角少、手机耗电量低。 目前我国主要的两大GSM系统为GSM 900及GSM1800,由于采用了不同频率,因此适用的手机也不尽相同。不过目前大多数手机基本是双频手机,可以自由在这两个频段间切换。欧洲国家普遍采用的系统除GSM900和GSM1800另外加入了GSM1900,手机为三频手机。在我国随着手机市场的进一步发展,现也已出现了三频手机,即可在GSM900\GSM1800\GSM1900三种频段内自由切换的手机,真正做到了一部手机可以畅游全世界。 早期来看,GSM900发展的时间较早,使用的较多,反之GSM1800发展的时间较晚。物理特性方面,前者频谱较低,波长较长,穿透力较差,但传送的距离较远,而手机发射功率较强,耗电量较大,因此待机时间较短;而后者的频谱较高,波长较短,穿透力佳,但传送的距离短,其手机的发射功率较小,待机时间则相应地较长。 CDMA
CDMA是码分多址的英文缩写(Code Division Multiple Access)先进的无线通信技术,原为军方通信所开发,现今已广泛应用到全球民用通信中。CDMA 将话音转换为数字信号,给每个数字话音分组增加一个地址,进行扰码处理,并且将它发射到空中.CDMA最大的优点就是相同的带宽下可以容纳更多的呼叫.而且它还可以随话音传送数字信息.
CDMA是目前2G网络中的主要制式之一,中国联通运营的就是CDMA2000 1x的网络。技术上的定义如下。 CDMA是 Code Division Multiple Access码分多路接续的缩写,其基础是使用一组 正交(或准正交)的伪随机噪声(PN)序列(简称伪码)通过相关处理以实现多用户共享频率资源 和同时入网接续的功能。码分多址采用扩频技术。扩频技术的概念就是把原始信息的带宽变换成带宽宽得 多的类噪声信号。比特率为Rb的数据Vi(t)被一个速率很高的扩频码Ci(t)(通常用PN序列)调制后便展宽了频谱,这个过程称为扩频。然后再对频谱展宽后的序列进行射频调制,成为扩 展频谱的射频信号Si(t),经天线发射出去。发射机 输出的信号是所有这些扩频信号的 和 S(t)=Vi(t)Ci(t)cos2fot 。 在接收端,射频信号经混频后变为中频信号。为识别它所需要接收的信号 ,使用 一种与发 射端相同的扩频码,对中频信号进行反扩展,将宽 带信号恢 复成窄带信号 ,这个过程称为解扩。解扩后的窄带信号经解调器 进行解调,恢复成原始的数据。 11月4日 套接字编程基本概念一. 网间进程通信进程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如UNIX BSD中的管道(pipe)、命名管道(named pipe)和软中断信号(signal),UNIX system V的消息(message)、共享存储区(shared memory)和信号量(semaphore)等,但都仅限于用在本机进程之间通信。网间进程通信要解决的是不同主机进程间的相互通信问题(可把同机进程通信看作是其中的特例)。为此,首先要解决的是网间进程标识问题。同一主机上,不同进程可用进程号(process ID)唯一标识。但在网络环境下,各主机独立分配的进程号不能唯一标识该进程。例如,主机A赋于某进程号5,在B机中也可以存在5号进程,因此,“5号进程”这句话就没有意义了。
其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。因此,网间进程通信还要解决多重协议的识别问题。
为了解决上述问题,TCP/IP协议引入了下列几个概念。
端口
网络中可以被命名和寻址的通信端口,是操作系统可分配的一种资源。
按照OSI七层协议的描述,传输层与网络层在功能上的最大区别是传输层提供进程通信能力。从这个意义上讲,网络通信的最终地址就不仅仅是主机地址了,还包括可以描述进程的某种标识符。为此,TCP/IP协议提出了协议端口(protocol port,简称端口)的概念,用于标识通信的进程。
端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序(即进程)通过系统调用与某端口建立连接(binding)后,传输层传给该端口的数据都被相应进程所接收,相应进程发给传输层的数据都通过该端口输出。在TCP/IP协议的实现中,端口操作类似于一般的I/O操作,进程获取一个端口,相当于获取本地唯一的I/O文件,可以用一般的读写原语访问之。
类似于文件描述符,每个端口都拥有一个叫端口号(port number)的整数型标识符,用于区别不同端口。由于TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立,如TCP有一个255号端口,UDP也可以有一个255号端口,二者并不冲突。
端口号的分配是一个重要问题。有两种基本分配方式:第一种叫全局分配,这是一种集中控制方式,由一个公认的中央机构根据用户需要进行统一分配,并将结果公布于众。第二种是本地分配,又称动态连接,即进程需要访问传输层服务时,向本地操作系统提出申请,操作系统返回一个本地唯一的端口号,进程再通过合适的系统调用将自己与该端口号联系起来(绑扎)。TCP/IP端口号的分配中综合了上述两种方式。TCP/IP将端口号分为两部分,少量的作为保留端口,以全局方式分配给服务进程。因此,每一个标准服务器都拥有一个全局公认的端口(即周知口,well-known port),即使在不同机器上,其端口号也相同。剩余的为自由端口,以本地方式进行分配。TCP和UDP均规定,小于256的端口号才能作保留端口。
地址
网络通信中通信的两个进程分别在不同的机器上。在互连网络中,两台机器可能位于不同的网络,这些网络通过网络互连设备(网关,网桥,路由器等)连接。因此需要三级寻址:
1. 某一主机可与多个网络相连,必须指定一特定网络地址;
2. 网络上每一台主机应有其唯一的地址;
3. 每一主机上的每一进程应有在该主机上的唯一标识符。
通常主机地址由网络ID和主机ID组成,在TCP/IP协议中用32位整数值表示;TCP和UDP均使用16位端口号标识用户进程。
网络字节顺序
不同的计算机存放多字节值的顺序不同,有的机器在起始地址存放低位字节(低价先存),有的存高位字节(高价先存)。为保证数据的正确性,在网络协议中须指定网络字节顺序。TCP/IP协议使用16位整数和32位整数的高价先存格式,它们均含在协议头文件中。
连接
两个进程间的通信链路称为连接。连接在内部表现为一些缓冲区和一组协议机制,在外部表现出比无连接高的可靠性。
半相关
综上所述,网络中用一个三元组可以在全局唯一标志一个进程:
(协议,本地地址,本地端口号)
这样一个三元组,叫做一个半相关(half-association),它指定连接的每半部分。
全相关
一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识:
(协议,本地地址,本地端口号,远地地址,远地端口号)
这样一个五元组,叫做一个相关(association),即两个协议相同的半相关才能组合成一个合适的相关,或完全指定组成一连接。 二. 服务方式 在网络分层结构中,各层之间是严格单向依赖的,各层次的分工和协作集中体现在相邻层之间的界面上。“服务”是描述相邻层之间关系的抽象概念,即网络中各层向紧邻上层提供的一组操作。下层是服务提供者,上层是请求服务的用户。服务的表现形式是原语(primitive),如系统调用或库函数。系统调用是操作系统内核向网络应用程序或高层协议提供的服务原语。网络中的n层总要向n+1层提供比n-1层更完备的服务,否则n层就没有存在的价值。 在OSI的术语中,网络层及其以下各层又称为通信子网,只提供点到点通信,没有程序或进程的概念。而传输层实现的是“端到端”通信,引进网间进程通信概念,同时也要解决差错控制,流量控制,数据排序(报文排序),连接管理等问题,为此提供不同的服务方式: 面向连接(虚电路)或无连接 面向连接服务是电话系统服务模式的抽象,即每一次完整的数据传输都要经过建立连接,使用连接,终止连接的过程。在数据传输过程中,各数据分组不携带目的地址,而使用连接号(connect ID)。本质上,连接是一个管道,收发数据不但顺序一致,而且内容相同。TCP协议提供面向连接的虚电路。 无连接服务是邮政系统服务的抽象,每个分组都携带完整的目的地址,各分组在系统中独立传送。无连接服务不能保证分组的先后顺序,不进行分组出错的恢复与重传,不保证传输的可靠性。UDP协议提供无连接的数据报服务。 下面给出这两种服务的类型及应用中的例子: 服务类型 可靠的字节流 不可靠的连接 远程登录(Telnet) 数字话音 有确认的数据报 请求-应答 电子邮件中的挂号信 网络数据库查询
顺序 在网络传输中,两个连续报文在端-端通信中可能经过不同路径,这样到达目的地时的顺序可能会与发送时不同。“顺序”是指接收数据顺序与发送数据顺序相同。TCP协议提供这项服务。
差错控制 保证应用程序接收的数据无差错的一种机制。检查差错的方法一般是采用检验“检查和(Checksum)”的方法。而保证传送无差错的方法是双方采用确认应答技术。TCP协议提供这项服务。
流控制 在数据传输过程中控制数据传输速率的一种机制,以保证数据不被丢失。TCP协议提供这项服务。
字节流 字节流方式指的是仅把传输中的报文看作是一个字节序列,不提供数据流的任何边界。TCP协议提供字节流服务。
报文 接收方要保存发送方的报文边界。UDP协议提供报文服务。
全双工/半双工 端-端间数据同时以两个方向/一个方向传送。 缓存/带外数据 在字节流服务中,由于没有报文边界,用户进程在某一时刻可以读或写任意数量的字节。为保证传输正确或采用有流控制的协议时,都要进行缓存。但对某些特殊的需求,如交互式应用程序,又会要求取消这种缓存。 在数据传送过程中,希望不通过常规传输方式传送给用户以便及时处理的某一类信息,如UNIX系统的中断键(Delete或Control-c)、终端流控制符(Control-s和Control-q),称为带外数据。逻辑上看,好象用户进程使用了一个独立的通道传输这些数据。该通道与每对连接的流相联系。由于Berkeley Software Distribution中对带外数据的实现与RFC 1122中规定的Host Agreement不一致,为了将互操作中的问题减到最小,应用程序编写者除非与现有服务互操作时要求带外数据外,最好不使用它。 三. 客户/服务器模式 在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户/服务器模式(Client/Server model),即客户向服务器发出服务请求,服务器接收到请求后,提供相应的服务。客户/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户/服务器模式的TCP/IP。 客户/服务器模式在操作过程中采取的是主动请求方式: 首先服务器方要先启动,并根据请求提供相应服务: 1. 打开一通信通道并告知本地主机,它愿意在某一公认地址上(周知口,如FTP为21)接收客户请求; 2. 等待客户请求到达该端口; 3. 接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务请求,要激活一新进程来处理这个客户请求(如UNIX系统中用fork、exec)。新进程处理此客户请求,并不需要对其它请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。 4. 返回第二步,等待另一客户请求。 5. 关闭服务器 客户方: 1. 打开一通信通道,并连接到服务器所在主机的特定端口; 2. 向服务器发服务请求报文,等待并接收应答;继续提出请求...... 3. 请求结束后关闭通信通道并终止。 从上面所描述过程可知: 1. 客户与服务器进程的作用是非对称的,因此编码不同。 2. 服务进程一般是先于客户请求而启动的。只要系统运行,该服务进程一直存在,直到正常或强迫终止。 四. 套接字类型 TCP/IP的socket提供下列三种类型套接字。
流式套接字(SOCK_STREAM) 提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。文件传送协议(FTP)即使用流式套接字。 数据报式套接字(SOCK_DGRAM) 提供了一个无连接服务。数据包以独立包形式被发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。网络文件系统(NFS)使用数据报式套接字。 原始式套接字(SOCK_RAW) 该接口允许对较低层协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。 H.264 (1)在技术上,H.264标准中有多个闪光之处,如统一的VLC符号编码,高精度、多模式的位移估计,基于4块的整数变换、分层的编码语法等。这些措施使得H.264得算法具有很高的编码效率,在相同的重建图像质量下,能够比H.263节约50%左右的码率。H.264的码流结构网络适应性强,增加了差错恢复能力,能够很好地适应IP和无线网络的应用。 H.264能以较低的数据速率传送基于联网协议(IP)的视频流,在视频质量、压缩效率和数据包恢复丢失等方面,超越了现有的MPEG-2、MPEG-4和H.26x视频通讯标准,更适合窄带传输。 H.264的技术特点 —— .1 分层设计 视频编码层具有高效的视频内容表示功能; 网络提取层将网络中所需要的数据进行打包和传送; .2 高精度、多模式运动设计 支持1/4或1/8像素精度的运动矢量; 多模式的灵活和细致的划分,大提高了运动估计的精确程度; 多帧参考技术; .3 帧内预测功能 在空间域进行预测编码算法,以便取得更有效的压缩: .4 4×4块的整数变换 由于用二变换块的尺寸缩小,运动物体的划分更精确,这样,不但变换计算量比较小,而且在运动物体边缘处的衔接误疾差也大为减小: 为了提高码率控制的能力,量化步长的变化的幅度控制在125%左右,而不是以不变的增幅变化。为了强调彩色的逼真性,对色度系数采用了较小量化步长; .5 统一的VLC 为快速再同步而经过优化的,可以有效防止误码。 H.264和MPEG4视频标准共用了一部分特征。这两种标准都假设了一种以块(block)为基础的运动补偿,
变换,量化和熵编码。我们主要关注到这些主要的方法中,并从时间模型开始,接下来是图象变换,量化,预测式编码和熵编码。并以对于一个图象采样块进行编码和解码的过程进行描述。
H.264标准三个框架
H.264的编解码框架与以前提出的标准如H.261、H.263及MPEG-1/2/4并无显著变化,也是基于混合
编码的方案:以运动矢量代表图象序列各帧的运动内容,使用前面已解码帧对其进行运动估计和补偿或
使用帧内预测技术,所得的图象参差值要经过变换、量化、熵编码等部分的处理。所以,新标准的性能
提升在于各个部分的技术方案的改进及新算法的应用。新标准在提高图象传输的容错性方面做了大量
工作,重新定义了适于图像的结构划分。在编码时,图象帧各部分被划分到多个slice结构中去,每个
slice都可以被独立解码不受其它部分的影响。Slice由图象最基本的结构——宏块组成,每个宏块包
含一个16×16的亮度块和两个8×8的色度块。为进一步提高鲁棒性,整个系统被划分为视频编码层和
网络抽象层。视频编码层主要描述要传输的视频数据所承载的视频内容。而网络抽象层则是考虑不同
的应用,如视频会议通信、H.32X连续包的视频传输或RTP/UDP/IP的通信。
H.264标准分成三个框架(profile):Baseline、Main及X,代表了针对不同应用的算法集及技
术限定。其中,Baseline主要包含了低复杂度、低延时的技术特征;主要是针对交互式的应用;考虑
到了恶劣环境下的容错性,Baseline的内容基本都被其它更高级别的profile所包含。而Main profile
是针对更高编码效率的应用,如视频广播。X profile 的设计主要针对流媒体的应用,在这一框架中所
有容错技术和对比特流的灵活访问及切换技术都将包括其中。 Baseline profile的主要技术特征 ⑴ Baseline的解码器只对I slice及P slice进行操作。对于帧间预测,相比以前的标准,为了更精确的对
图象的运动内容进行预测补偿,新标准允许宏块更进一步划分为16×16、16×8、8×16、8×8、
8×4、4×8、4×4的子块;运动估计精确到经由6-tap滤波器得到的1/4象素位置;运动矢量由相邻
块预测得到,其预测的差值被编码传输。H.264支持多参考帧的预测,规定运动估计使用的参考帧数
最多可达15帧,多参考帧的使用大大提高了对图像传输的容错性,抑制了错误在空间和时间上的蔓延
。对于所有的slice编码类型,H.264支持两类帧内编码:4x4与16x16编码模式。对于4x4模式,每
一个亮度4x4块有8种不同方向上的预测模式及DC预测模式。对于16x16模式,每个16x16亮度块有
4种帧内预测模式。而对于宏块的8x8色度采样,采用与亮度16x16几乎相同的预测模式。为了保证
slice的编码独立性,帧内预测是不允许跨越slice边界的。对于变换、量化部分。不同于以前标准对
预测参差值的变换编码使用DCT变换,H.264使用了简单的整数变换。这种变换与DCT相比压缩性能
几乎相同且有许多优势,其核心变换的计算只使用加减、移位运算,避免了精度的损失。对变换参差
系数的量化使用了52级步长的量化器,而H.263标准只有31级。量化步长以12.5%递增,量化步长
范围的扩大似的编码器能够更灵活和精确的进行控制,在比特率和图象质量之间达到折中。对熵编码
部分。对于要传输的量化变换系数,若使用基于上下文的变长编码(CAVLC),它是根据前面已编码
传输的量化变换系数值的大小来选择接下来系数编码要使用的变长编码表。由于变长编码表的设计是基
于相应的统计条件,所以其性能要优于使用单一变长编码表。而对其它数据如头信息等,使用一种单一
的变长编码表(Exp-Golomb code)。新标准仍然使用基于块的预测及重构方式,为了去除由此产生的
影响图象主观质量的方块效应,H.264使用了去块效应滤波器。其主要思想是当块边界上两边差较小则
使用滤波器使差别“平滑”掉,若边界上图象特征明显就不使用滤波。这样既为减弱“块效应”的影响又
避免滤掉图象的客观特征。同时在相同主观质量下使得比特率减少5-10%。另外,对图象数据的组织
及传输。在H.264标准中的图象宏块可以灵活的宏块组织顺序(FMO)划分为多个slice group;slice之
间是相互独立的可以任意的顺序传输到解码端(ASO)。而且在比特流中slice可以使用重复的方式(RS)传输,这在slice数据出错的情况下可用来进行恢复,增强了图象传输的鲁棒性。同时slice间的相互独立性
抑制了错误的空间传播,因此提高了比特流的容错性。 ⑵ Main profile的技术特征 Main profile包含Baseline profile的所有算法并具有额外的技术特征,但它并不支持FMO、ASO及RS等技术。只支持对
I、P、B slice的处理操作。在此框架内提出了适配块划分尺寸的变换(ABT)的概念。此概念是针对帧间
编码的,其主要思想是将对预测参差进行变换编码的块尺寸与用来进行运动补偿的块尺寸联系起来。这
样就尽可能的利用最大的信号长度进行变换编码。但是由于复杂度的原因,进行变换的最大块尺寸被限
制在8×8以下。对熵编码部分,为更高效的进行编码,这里使用了基于上下文的算术编码(CABAC)
使熵编码的性能进一步提高。相比较CAVLC,在相同图象质量下编码电视信号使用CABAC将会使比特
率减少10-15%。另,Main profile不支持多个slice group的划分。 ⑶ 相关的编码问题如何对已提出
的预测模式进行选择(mode decision)和使用运动估计策略(ME)历来都视频编码实现的重点研究课题。
在H.263标准的实现软件中对模式的选择是简单的基于对阀值的比较。在新标准的测试软件中使用了拉
格朗日率失真优化策略,它是基于使用每种图象块尺寸和每种预测模式而产生的参差及其传输的码率。
这样,模式选择可以取得优化的率失真性能但这是以提高运算复杂度为代价的。此优化操作是对下面拉
各朗日函数的最小化: J = SATD + λ•R 其中,R为对应传输的各部分的比特率;λ为优化参数,其
与量化参数有很强的相关性。SATD为经过哈德曼变换的4×4块的预测参差绝对值总和。对于所有帧内、
帧间宏块编码模式及多参考帧的选择都通过对拉各朗日函数的最小化来实现。通常,视频标准只是包括
解码规范,而模式选择的技术研究是属于编码端的范畴,所以不列在标准之内。
11月3日 数据库知识(4)——一篇关于trigger挺好的文章INSTEAD OF 触发器 AFTER 触发器(也叫“FOR”触发器)会在触发 insert、update 或是delect 动作之后执行。例如,一个 Employees 表上的 AFTER 触发器会在在 Employee 表上执行一条 update 语句后激活。因此,AFTER 触发器只有在已插入一行或是多行和所有约束已被处理且通过后才触发。INSTEAD OF 触发器和 AFTER 触发器有本质上的不同,因为 INSTEAD OF 触发器代替触发动作进行激发。就拿同样的例子来说,如果在 Emplyees 表上有一个 INSTEAD OF UPDATE 触发器和在这个表上执行一条 UPDATE 语句,结果是这条 UPDATE 语句并不会改变 Employee 表中的任何一行。相反,这条 UPDATE 语句只有是为了踢离 INSTEAD OF UPDATE 触发器,这个触发器可能会,也可能不会改变 Employees 表中的数据。 因此,怎么决定在合适的时间和位置放置 INSTEAD OF 触发器呢?有几个关键的因素在做决定是值得考虑的。AFTER 触发器多用在动作必须在表中数据发生改变之后才执行后情情况。比如,AFTER 触发器可以用于将对数据作任何变动的日志记录在一个相对独立的审计表中。INTEAD OF 触发器也能做同样的工作。但是 INSTEAD OF 触发器在这个情况下的效率比较低,因为更新动作只能在将它发生的动作准确地记录在审计表之后才允许执行。 一般来说,只要不影响数据的修改,AFTER 触发器比 INSTEAD OF 触发器更有效率。在对数据进行计算或是对数据的修改作为一个整体提交或是作为一个整体回退的情况下,AFTER 触发器也是一个很好的选择。例如,存在这样一条规则:对在 Products 表的产品价格的变动超过30%的必须回退。AFTER 触发器能很漂亮地完成这个工作,它利用已插入同已删除的表中的产品价格作比较,然后在有必要的时回滚事务。这些都是 AFTER 触发器的理想条件,但有时 INSTEAD OF会更好些。 INSTEAD OF 触发器有一个很大的特点——就是它允许你在某个表或视图上用多个复杂的查询操作来代替单一的查询。跟 AFTER 触发器只能对表起作用不同,INSTEAD OF 触发器可以同时对表和视图起作用。我常常被问到怎么样去解决这种情况:有一个多表组成的视图,如何对该视图进行一次更新。如果视图包含有关键字段和包含有基本表的某些字段,这只是简单的更新基本表。但是,当有视图中包含有多个基本表示,逻辑上的更新比单单一个 UPDATE 语句会更复杂。因此,你是怎么利用什么可以替代的工具来解决这个问题的呢?其中一个方法就是将一个INSTEAD OF 触发器放在视图上。INSTEAD OF 触发器可以定义在一个或多个表上.INSTEAD OF 触发器就能转开在多个基本表中修改的范围. 例如,如果一个视图将 Customers、Products、orders 和 OrderDteils 等表合并成一个视图,并利用视图通过程序在屏幕上来显示所有的数据。更新操作便允许用来代替这个视图,假如存在一个这个样的视图:它包含 Northwind 数据库中的四个表,并且被命名为vwCustomersOrdersOrderDetailsProducts,它看起来像这样(Figure 1): Figure 1 连接 Customers 及其 Order Details 的视图
CREATE VIEW vwCustomersOrdersOrderDetailsProducts
AS
SELECT c.CustomerID,
c.CompanyName,
o.OrderID,
o.OrderDate,
od.UnitPrice,
od.Quantity,
od.Discount,
p.ProductID,
p.ProductName
FROM Customers c
INNER JOIN Orders o ON c.CustomerID = o.CustomerID
INNER JOIN [Order Details] od ON o.OrderID = od.OrderID
INNER JOIN Products p ON od.ProductID = p.ProductID
GO vwCustomersOrdersOrderDetailsProducts 视图连接着四个表,并且每个表都暴露一个取样字段。必须记住的一点是,当你设计一个含有 INSTEAD OF UPDATE 的触发器时,将每个表的主关键字段包含在SELECT语句中是很有益的做法。即使这些字段在应用程序不会用到,它们也以在 INSTEAD OF 触发器中用来定位将要被修改的行,然后对基表作相应的修改。假设你打算允许更新该视图以便按非关键字过滤基表。更新代码应该写在 INSTEAD OF UPDATE 触发器中,让触发器去更新 Customers 表中的 CompnayName 列,Orders 表中的 OrderDate 列,Order Details 表的 UnitPrice 和 Quantity 列以及在 Products 表中的 ProductName 列。在这种情况下,使用 AFTER 触发器就不适合了,而 INSTEAD OF 触发器则是一个很好的选择,参见 Figure 2: Figure 2 用 INSTEAD OF 触发器更新视图
CREATE TRIGGER tr_vwCustomersOrdersOrderDetailsProducts_IO_U
ON vwCustomersOrdersOrderDetailsProducts
INSTEAD OF UPDATE
AS
— 更新 Customers
UPDATE Customers
SET CompanyName = i.CompanyName
FROM inserted i
INNER JOIN Customers c ON i.CustomerID = c.CustomerID
— 更新 Orders
UPDATE Orders
SET OrderDate = i.OrderDate
FROM inserted i
INNER JOIN Orders o ON i.OrderID = o.OrderID
— 更新 Order Details
UPDATE [Order Details]
SET UnitPrice = i.UnitPrice,
Quantity = i.Quantity
FROM inserted i
INNER JOIN [Order Details] od ON i.OrderID = od.OrderID AND
i.ProductID = od.ProductID
— 更新 Products
UPDATE Products
SET ProductName = i.ProductName
FROM inserted i
INNER JOIN Products p ON i.ProductID = p.ProductID
GO 注意在 Figure 2 中的 INSTEAD OF UPDATE 触发器包含了四个 UPDATE 语句。每个 UPDATE语句目的都是为了对其中一个基表中的非关键字段进行修改。在 UPDATE 语句中包含了每个表中的关键字段对应于视图中的字段。这样就允许 UPDATE 语句在相应的表中定位对应的列并只对这些列作修改。下面的 UPDATE 语句将对 INSTEAD OF 触发器进行测试: UPDATE vwCustomersOrdersOrderDetailsProducts
SET Quantity = 100,
UnitPrice = 20,
CompanyName = ''''Fake Name'''',
OrderDate = ''''11/23/2001'''',
ProductName = ''''Widget''''
WHERE OrderID = 10265
AND ProductID = 17 如果你(通过视图或是表自身)检查相应表中的值,很明显,这些值已被更新了。当然,对INSTEAD OF 触发器作一些改变会使其有不同的结果。例如,不存在写一个触发器去改变四个基表的需求,因此,可以将触发器中的一个或是多个 UPDATE 语句删去。假设 INSTEAD OF 触发器仅仅是为了更新 Order Details 表的值,这就会仅仅更新在 Order Details 表中的字段,而忽视任何在其他基表上的修改。在这种情况下,在 Customers,Products 或是 Orders 表中不会产生任何错误同时也不会发生任何改变。当然,如果这三个表中的某些字段发生改变的话,会发生报错。如我呆会在这篇文章会讨论的一样,UPDATE 和 COLUMNS_UPDATED 函数是个检测哪些字段发生改变的理想的方法。Figure 2 也演示了怎么写一个触发器修改多行记录。注意到 UPDATE 语句如何按关键字连接被插入的表和各个基表。这就保证更新是对所有的行,这些行在视图中被原有的 UPDATE 语句修改。通过循环被插入表的记录行也能完成该操作。不管怎么样,通常避免使用游标是个好主意,尤其是在使用触发器时更应如此。SQL SERVER 被设计成以数据集的方式来处理数据,而游标是为一次处理一个数据行而设计的。在触发器中使用游标会降低程序的性能,因此,最好能使用象 Figure 2 中那样更有效代替方法或使用一个子查询。 另一个改变 INSERT OF UPDATE 触发器的方法就是使其在视图的 INSERT 和 DELETE 语句中激发。这也就意味着在适当的地方,触发器会实现 INSERT 或是 DELETE 的功能。但是必须记隹的是 DELETE 可能会删除多个记录,这关键在于触发器是怎样写的。因此,检查触发器的需求,在实现之前进行测试,这些做法十分重要。INSERT OF UPDATE 触发器可写在视图中,因此它可插入一个新的顾客、订单、详细的订单和产品。这个触发器也可以用来在插入一个新顾客之前检查这个顾客是否是新的(对其它记录的操作也是一样)。当采用的是 INSTEAD OF 触发器时存在有许多机会,但是,当然,触发器是为解决相应的需求这才是它的本质。 通常,当引用一张表的 UPDATE 语句试图去赋值一个计算型的,恒等型的或是时间戳型的列时,会产生一个错误,因为这些列的值必须是由SQL SERVER来决定的。这些列必须被包含在UPDATE 语句中以便能满足列不能为空的要求。但是,如果 UPDATE 语句用 INSTEAD OF 触发器引用一个视图,定义在触发器中的逻辑可以旁路掉这些列来避免错误的发生。为了达到这个目的,触发器决不能尝试去更新基表中相应列的值(让它们远离 UPDATE 语句的 SET 从句)。当某一条被处理的记录来自被插入的表时,计算型的,恒等型的或是时间戳型的列可以用一个虚假值以满足不为空值的要求,这时,INSTEAD OF 触发器将忽略这些值,正确的值由 SQL SERVER 设置。 更新分开的列 INSTEAD OF 触发器也很普遍地用于更新基表中计算型的列。例如,假设存在有如下这样一个叫 vwOrdersOrderDetailsProducts 的视图: CREATE VIEW vwOrdersOrderDetailsProducts
AS
SELECT o.OrderID,
o.OrderDate,
od.UnitPrice * od.Quantity AS ExtendedPrice,
p.ProductID,
p.ProductName
FROM Orders o
INNER JOIN [Order Details] od ON o.OrderID = od.OrderID
INNER JOIN Products p ON od.ProductID = p.ProductID
GO
这个视图揭示了一个计算型的列叫ExtendedPrice,这个列不能被直接被更新,因为它不能将其自己变为表中独立的一列。虽然你可实现这样一个生意规则,在这个规则中ExtendedPrice通过这个视图来修改,Quantity列不应修改,但是UnitPrice可被修改(我知道这条规则有点奇怪,但我可以忍受这点)。可以写一个INSTEAD OF UPDATE触发器来增强这条生意规则,其代码如下所示: CREATE TRIGGER tr_vwOrdersOrderDetailsProducts_IO_U
ON vwOrdersOrderDetailsProducts
INSTEAD OF UPDATE
AS
UPDATE [Order Details]
SET UnitPrice = i.ExtendedPrice / Quantity
FROM inserted i
INNER JOIN [Order Details] od ON i.OrderID = od.OrderID AND
i.ProductID = od.ProductID
GO
这些代码揭示了怎样用一个在INSTEAD OF 触发器中的逻辑来代替对一个计算型列的更新。假设一个产品在一张特定的定单表中Quantity为100而ExtendedPrice要更新为200,这时新的UnitPrice值就变为2。在这种情况下,在执行一个对ExtendedPrice列进行修改的UPDATE语句时,最终的结果是UnitPrice被赋为ExtendedPrice除以Quantity的商。下面的代码可以用来测试这种情况: UPDATE vwOrdersOrderDetailsProducts SET ExtendedPrice = 200 WHERE OrderID = 10265 AND ProductID = 17 检查改变在INSTEAD OF和AFTER触发器中都有UPDATE和COLUMNS_UPDATE功能,这二种功能允许由触发器决定哪些字段由触发器的语句来改变。例如,下面的触发器阻止任何对Employees表中的lastname字段进行修改。在这里,UPDATE功能用来决定对哪些对字段的修改可以执行。如果超出发生了改变(而又是不允许修改的)就会产生一个错误。PAISERR OR功能和事务就会回退,回退会撤消所做的任何修改。UPDATE功能都可以在AGTER触发器和INSTEAD OF触发器中工作,而不是在外部工作。 CREATE TRIGGER tr_Employees_U on Employees AFTER UPDATE AS
IF UPDATE(lastname)
BEGIN
RAISERROR (''''cannot change lastname'''', 16, 1)
ROLLBACK TRAN
RETURN
END
GO
UPDATE功能是为了判断单一列是否被INSERT或是UPDATE语句修改过。UPDATE(列)是一个用来检测更新的标准的方法。但是当需要用来他检测多列是否受到INSERT或UPDATE语句的影响时就变得更低效率。而这恰恰是COLUM_UPDATE功能的一个亮点。COLUMN_UPDATE功能返回一个位掩码来判断特定的列是否被修改过。位掩码是包含在被表中被修改的列中的一个比特,目的是为了在表模式中定义这些列。如果一行修改,这比特位的值就为1,否则为0。不像从右到左地读字节的常规方法,位掩码是从左往右读。例如,下面的代码提示了一个在Order Details表中的触发器,这个触发器是为了检测Quantity和UnitPrice二个字段是否被修改过。 CREATE TRIGGER tr_OrderDetails ON [Order Details] AFTER UPDATE
AS
IF (COLUMNS_UPDATED() = 12)
BEGIN
RAISERROR (''''Cannot change both UnitPrice and Quantity at the
same time'''', 16, 1)
ROLLBACK TRAN
END
GO
如果这个字段都被修改了,就会产生一个错误,同时事务也将回滚。就拿Order Details表来说,COLUMN_UPDATED功能返回代表Order Details表中字段的五个字节。只要第三和第四个字段被修改,上面这种情况就会发生,它检测这些位是不是已赋值为1.当第三和第四位都打开的庆,它就如:00110。L因这个位掩码代表2次幂,第一位表示1,第二位表示2,第三位表示4,第四位表示8,第五位表示16(是的,这是和正常二进制数相反的顺序);因此只表示UnitPrice和Quantity字段被修改位掩码的值为00110,这个值为12(4+8)。请注意,这个触发器只有在UnitPrice和Quantity字段被修改才会将事务回滚。如果其他字段修改的话,位掩码就会不一样,因此就不等于整数12了。如果触发器被修改为禁止对这二个字段修改即使对其他字段也禁止,它就可重新编写为如下: ALTER TRIGGER tr_OrderDetails ON [Order Details] AFTER UPDATE
AS
IF (COLUMNS_UPDATED() >= 12)
BEGIN
RAISERROR (''''Cannot change both UnitPrice and Quantity
at the same time'''', 16, 1)
ROLLBACK TRAN
END
GO
请注意 COLUMN_UPDATED 功能现在是怎么去检测位掩码的但是否小于等于12.如果你修改联系UnitPrice,Quantity和Discount列的话,位掩码就变为00111,代表整数28(4+8+16)。当在一个表中不止有8个列时,这个函数就会先返回包含了前八列的五个字节,而第从第九到第十六就会在第二个字节中,以此类推。这个功能在决定允许哪些列可以被更新比只对第列进行更新的UPDATE功能更有用。如前期所描述的一样,在潢足特定条件规则条件下,触发器可以回滚事务,当一个含有回滚的触发器在SQL脚本中执行时,整个处理将被取消。因此,被触发动作修改的的所有数据将由ROLLBACK TRANSACION语句回滚。虽然一个回滚并不阻止触发执行SQL语句所有在ROLLBACK TRANSACION语句后面的语句都会被执行 。特别是当一个触发器继续执行回滚语句后面的语句时,在回滚以后所作的任何修改都不会回滚。发生这种情况是因为当在触发器中执行了一个ROLLBACK TRANSACTION时,所以有的事务都被取消。因此当一个新的查询语句被执行时,一个新的不同与以前事务的事务就重新开始。因此,一般情况下,建议不要在ROLLBACK TRANSACTION语句后放置任何语句。 像回滚不会自动退出触发器一样,它也不会自动产生错误。如果必须回滚且必会产生错误,PAISERR OR语句应该放在退出触发器代码前,紧跟在回滚后. 结束语 在对同一个表的数据所作的修改会激发同样的INSTEAD OF触发器,这种触发器不会递归调用。因此,如果在Emplyee表中有一个INSTEAD OF触发器,P这个触发器是用来更新Employee表的,这并不会发生调用同一个INSTEAD OF触发器。如果允许这种递旭的话,更新应该被禁止。INSTEAD OF触发器和AFTER触发器的另一个不同在于Text,Ntext和Image列可以出现在被更新和删除的表的触发器中。这些二进制列会以如VARCAHAR数值出现在更新和删除表的触发器中,这种是可行的,但这并不是他们原始的数据类型。 这有一个有用的存储过程-sp_helptrigger 系统存储过程-来检测触发器。他返回定义在表上的触发器类型,这个表是传递给存储过程的。用这种方法,你可以看到哪些触发器和某个表有关联,什么操作动触发这些触发器和判断触发器是AFTER触发器还是INSTEAD OF触发器。 在最后二栏中,我已经讨论了AFTER触发器和INSTEAD OF触发器的多个方面。当然,还有许多情形下他们很有用,还有许多使用时机也没有提出来。当一个触发器必须查询其他表的情况下,触发器就会没有什么效率了。在这些情况下,触发器的性能和触发动作会受到很大损害。当使用得好时,触发器是一个很棒的工具,但是必须保证在使用他们之前必须对你的程序作一个全面的测试。 |
|
|