密码算法可以用数字函数f x x m x 3c=f(m,key)表示,这题怎么解

扫一扫下载手机客户端
扫描我,关注团购信息,享更多优惠
||网络安全
| | | | | | | | | | | | | | | |
||电子电工
汽车交通| | | | | | | | | |
||投资理财
| | | | | | | | | | | | | | | | |
| | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
||外语考试
| | | | | | | | |
| 视频教程|
应用密码学:协议、算法与C源程序(原书第2版)
内容广博权威,具有极大的实用价值,是致力于密码学研究的专业及非专业人员一本难得的好书。
定价:¥79.00
校园优惠价:¥55.30 (70折)
促销活动:
商品已成功飞到您的手机啦!快登录手机站看看吧!
下载客户端
> 微信关注“互动出版网”,便捷查询订单,更多惊喜天天有
原书名:Applied Cryptography:Protocols,Algorithms,and Source Code in C
原出版社:
ISBN:3上架时间:出版日期:2014 年1月开本:16开页码:545版次:1-1
所属分类:
  密码学的应用领域远远不只是编码和解码信息,要了解有关密码学技术的数字签名的知识,施奈尔编*的《应用密码学:协议、算法与C源程序(原书第2版)》是**之作。本书介绍了密码学协议的通用类型、特定技术,详细介绍了现实世界密码学算法的内部机制。包括DES和RSA公开密钥加密系统。书中提供了源代码列表和大量密码学应用方面的实践活动,如产生真正的随机数和保持密钥安全的重要性。
《应用密码学:协议、算法与C源程序(原书第2版)》内容简介:全书共分四个部分,定义了密码学的多个术语,介绍了密码学的发展及背景,描述了密码学从简单到复杂的各种协议,详细讨论了密码技术。并在此基础上列举了如DES、IDEA、RSA、DSA等十多个算法以及多个应用实例,并提供了算法的源代码清单。
全书内容广博权威,具有极大的实用价值,是致力于密码学研究的专业及非专业人员一本难得的好书。
Bruce Schneier是国际知名的安全技术专家,被《经济学家》(The Economist)杂志称为“安全大师”(security guru)。他是12本安全方面技术图书的作者,还是数百篇文章、杂文和学术论文的作者。他的有影响力的通讯“Crypto-Gram”和博客“Schneier on Security”有超过25万的读者和浏览者。他曾在国会作证,还经常做客电视台和广播电台,并在几个政府委员会供职。他是哈佛大学法学院伯克曼互联网和社会中心的fellow,新美国基金会开放科技中心的program fellow,电子前哨基金会的董事会成员,电子隐私信息中心的咨询委员会成员,以及BT(原英国电信)的安全未来学家。
《应用密码学:协议、算法与C源程序(原书第2版)》
出版者的话
Whitfield Diffie序
第1章 基础知识1
1.1 专业术语1
1.1.1 发送者和接收者1
1.1.2 消息和加密1
1.1.3 鉴别、完整性和抗抵赖1
1.1.4 算法和密钥2
1.1.5 对称算法3
1.1.6 公开密钥算法3
1.1.7 密码分析4
1.1.8 算法的安全性5
1.1.9 过去的术语6
1.2 隐写术7
1.3 代替密码和换位密码7
1.3.1 代替密码7
1.3.2 换位密码8
  自密码学从外交情报和军事领域走向公开后,密码学文献难觅的窘境已大为改观,但密码学资料的晦涩难懂却依然如故。广大研究人员和读者一直盼望能有一本全面介绍当代密码学现状且可读性强的著作。Bruce Schneier所著《Applied Cryptography:Protocols,Algorithms,and Source Code in C》一书正是这样一部集大成之作。本书以生动的描述和朴实的文风将当代密码学的方方面面熔于一炉,1994年第1版一经推出即在国际上引起广泛关注,成为近几年来引用最多、销量最大的密码学专著,极大地推动了国际密码学研究与应用的发展。作者顺应近年来世界各国对信息安全普遍关注的趋势,结合第1版问世以来密码学的新成果,于1996年推出了第2版,仍是好评如潮。本书即根据第2版译出。
  本书作者没有将密码学的应用仅仅局限在通信保密性上,而是紧扣密码学的发展轨迹,从计算机编程和网络化应用方面,阐述了密码学从协议、技术、算法到实现的方方面面。该书详细解释了大量的新概念,如盲签名、失败终止签名、零知识证明、位承诺、数字化现金和保密的多方计算等,向读者全面展示了现代密码学的新进展。
  本书的核心部分自然是论述密码协议、技术和算法的一系列章节。作者收集了大量的公开密钥和私人密钥密码体制的实例,内容几乎涵盖了所有已公开发表的具有实用性的密码算法。作者将它们分门别类,一一评论。其中,对密码技术中密钥管理技术和算法的分析与总结详尽全面;对数十种密码算法的软件实现提出了务实可行的建议;对苏联和南非的一些算法的介绍更是引人入胜。对编程人员和通信专业人士来说,本书尤若百科全书。难怪美国《Wired》杂志说这是一本美国国家安全局永远也不愿看到它问世的密码学著作。此外,作者还简述了各种散列函数和签名方案,并结合实例说明了如何有效地利用现有的工具箱,特别指出了实现保密协议的方法,比如盲签名和零知识证明。同时,还涉猎了密码学领域中不少时髦的话题,比如阈下信道、秘密共享、隐写技术和量子密码学等。
  该书的第四部分也颇具特色,它以“真实世界”为题,向人们展示了密码学应用于社会的真实情况。首先,作者用十多个实际的例子,讨论密码学应用于计算机网络的现实情况,内容包括了国外大多数的商用保密协议,如IBM公司的密钥管理方案、应用较多的KryptoKnight、ISO的鉴别框架、因特网中的保密增强型电子邮件产品PEM以及PGP安全软件,甚至还讨论了密码学界的热门话题――美国军用保密电话STU-Ⅲ、商用密码芯片Clipper和Capstone。接着,作者从政治角度探讨了美国的密码政策,其中对围绕专利的争论、出口许可证的管理和密钥第三方托管的评说,都让国内读者耳目一新。
  当然,纵览全书,也不难看出本书的不足,如序列密码、密码的形式证明、密码学在金融系统(或银行)和军事系统中的应用等方面的内容略显不足。加之本书内容广博,作者在对引用资料的使用上也有一些失误。但是,正如作者在前言中所说,本书的目的是将现代密码学的精髓带给计算机编程人员、通信与信息安全专业人员和对此有兴趣的爱好者,从这个角度看,上述的缺陷当在情理之中。
  参加本书翻译和校对的同志有:吴世忠、祝世雄、张文政、朱甫臣、龚奇敏、钟卓新、蒋继洪、方关宝、黄月江、李川、谭兴烈、王佩春、曾兵、韦文玉、黄澄、罗超、王英、伍环玉、蒋洪志、陈维斌等。本书最后由吴世忠、祝世雄统稿。何德全院士在百忙之中审校了全部译稿。
  必须指出的是,该书内容浩繁,由多人翻译,限于水平和经验,加之密码学的很多概念在译法上本身就有难度,故而谬误在所难免,敬请读者见谅。
  世界上有两种密码:一种是防止小孩偷看你的文件;另一种是防止当局阅读你的文件。本书写的是后一种情况。
  如果把一封信锁在保险柜中,把保险柜藏在纽约的某个地方,然后告诉你去看这封信,这并不是安全,而是隐藏。相反,如果把一封信锁在保险柜中,然后把保险柜及其设计规范和许多同样的保险柜给你,以便你和世界上最好的开保险柜的专家能够研究锁的装置,而你还是无法打开保险柜去读这封信,这才是安全的概念。
  许多年来,密码学是军队专有的领域。NSA和苏联、英国、法国、以色列以及其他国家的安全机构已将大量的财力投入到加密自己的通信,同时又千方百计地破译别人的通信的残酷游戏中。面对这些政府,个人既无专业知识又无足够财力保护自己的秘密。
  在过去的20年里,公开的密码学研究爆炸性地增长。从第二次世界大战以来,当普通公民还在长期使用经典密码时,计算机密码学已成为世界军事专有的领域。今天,最新的计算机密码学已应用到军事机构外,现在就连非专业人员都可以利用密码技术去阻止最强大的敌人,包括军方的安全机构。
  普通百姓真的需要这种保密性吗?是的,他们可能正在策划一次政治运动,讨论税收或正干一件非法的事情;也可能正设计一件新产品,讨论一种市场策略,或计划接管竞争对手的生意;或者可能生活在一个不尊重个人隐私权的国家,也可能做一些他们自己认为并非违法实际却是非法的事情。不管理由是什么,他的数据和通信都是私人的、秘密的,与他人无关。
  本书正好在混乱的年代出版。1994年,克林顿当局核准了托管加密标准(包括Clipper芯片和Fortezza卡),并将数字电话法案签署成为法律。这两个行政令企图确保政府实施电子监控的能力。
  一些危险的Orwellian假设在作祟:政府有权侦听私人通信,个人对政府保守秘密是错误的。如果可能,法律总有能力强制实施法院授权的监控,但是,这是公民第一次被迫采取“积极措施”,以使他们自己能被监控。这两个行政令并不是政府在某个模糊范围内的简单倡议,而是一种先发制人的单方面尝试,旨在侵占以前属于公民的权力。
  Clipper和数字电话不保护隐私,它强迫个人无条件地相信政府将尊重他们的隐私。非法窃听小马丁?路德?金电话的执法机构,同样也能容易地窃听用Clipper保护的电话。最近,地方警察机关在不少管区都有因非法窃听而被控有罪或被提出民事诉讼的事件,这些地方包括马里兰、康涅狄格、佛蒙特、佐治亚、密苏里和内华达。为了随时方便警察局的工作而配置这种技术是很糟糕的想法。
  这给我们的教训是采用法律手段并不能充分保护我们自己,还需要用数学来保护自己。加密太重要了,不能让给政府独享。
  本书为你提供了一些可用来保护自己隐私的工具。提供密码产品可能被宣布为非法,但提供有关的信息绝不会犯法。
  怎样阅读本书
  我写本书的目的是为了在真实地介绍密码学的同时给出全面的参考文献。我尽量在不损失正确性的情况下保持本书的可读性,我不想使本书成为一本数学书。虽然我无意给出任何错误信息,但匆忙中理论难免有失严谨。对形式方法感兴趣的人,可以参考大量的学术文献。
  第1章介绍密码学,定义许多术语,简要讨论计算机出现前密码学的情况。
  第一部分(第2~6章)描述密码学的各种协议:人们能用密码学做什么。协议范围从简单(一人向另一人发送加密消息)到复杂(在电话上抛掷硬币)再到深奥(秘密的和匿名的数字货币交易)。这些协议中有些一目了然,有些却十分奇异。密码学能够解决大多数人绝没有认识到的许多问题。
  第二部分(第7~10章)讨论密码技术。对密码学的大多数基本应用来说,这一部分的4章都很重要。第7章和第8章讨论密钥:密钥应选多长才能保密,怎样产生、存储密钥,怎样处理密钥等。密钥管理是密码学最困难的部分,经常是保密系统的一个致命弱点。第9章讨论使用密码算法的不同方法。第10章给出与算法有关的细节:怎样选择、实现和使用算法。
  第三部分(第11~23章)列出多个算法。第11章提供数学背景,如果你对公开密钥算法感兴趣,那么这一章你一定要了解。如果你只想实现DES(或类似的东西),则可以跳过这一章。第12章讨论DES:DES算法、它的历史、安全性和一些变型。第13~15章讨论其他的分组算法:如果你需要比DES更保密的算法,请阅读IDEA和三重DES算法这节;如果你想知道一系列比DES算法更安全的算法,就请读完整章。第16章和第17章讨论序列密码算法。第18章集中讨论单向散列函数,虽然讨论了多种单向散列函数,但MD5和SHA是最通用的。第19章讨论公开密钥加密算法。第20章讨论公开密钥数字签名算法。第21章讨论公开密钥鉴别算法。第22章讨论公开密钥交换算法。几种重要的公开密钥算法分别是 RSA、DSA、Fiat-Shamir和Diffie-Hellman。第23章讨论更深奥的公开密钥算法和协议,这一章的数学知识非常复杂,请你做好思想准备。
  第四部分(第24~25章)转向密码学的真实世界。第24章讨论这些算法和协议的一些实际实现;第25章涉及围绕密码学的一些政治问题。这些章节并不全面。
  此外,本书还包括在第三部分讨论的10个算法的源代码清单,由于篇幅的限制,不可能给出所有的源代码,况且密码的源代码不能出口(非常奇怪的是,国务院允许本书的第1版和源代码出口,但不允许含有同样源代码的计算机磁盘出口)。配套的源代码盘中包括的源代码比本书中列出的要多得多,这也许是除军事机构以外最大的密码源代码集。我只能给住在美国和加拿大的公民发送源代码盘,但我希望有一天这种情况会改变。
  对本书的一种批评是,它的广博性代替了可读性。这是对的,但我想给可能偶然在学术文献或产品中需要算法的人提供参考。密码学领域正日趋热门,这是第一次把这么多资料收集在一本书中。即使这样,还是有许多东西限于篇幅舍弃了,但尽量保留了那些我认为是重要的、有实用价值的或者有趣的专题。如果我对某一专题讨论不深,我会给出深入讨论这些专题的参考文献。
  我在写作过程中已尽力查出和根除书中的错误,但我相信不可能消除所有的错误。第2版肯定比第1版的错误少得多。勘误表可以从我这里得到,并且它定期发往Usenet的新闻组 sci.crypt。如果读者发现错误,请通知我,我将不胜感谢。
  Whitfield Diffie序
  Applied Cryptography:Protocols,Algorithms,and Source Code in C,Second Edition
  密码学文献有一个奇妙的发展历程。当然,保密总是扮演着主要角色,但是直到第一次世界大战之前,密码学重要的进展很少出现在公开文献中,但该领域却和其他专业学科一样一直在向前发展。直到1918年,20世纪最有影响的密码分析文章之一――William F.Friedman的专题论文“ The Index of Coincidence and Its Applications in Cryptography”(重合指数及其在密码学中的应用)[577]作为私立Riverbank实验室的一份研究报告问世了。其实,这篇论文所涉及的工作是在战时完成的。同年,加州奥克兰的Edward H.Hebern申请了第一个转轮机专利[710],这种装置在差不多50年里被指定为美军的主要密码设备。
  然而,第一次世界大战之后,情况开始变化,完全处于秘密工作状态的美国陆军和海军的机要部门开始在密码学方面取得根本性的进展。在20世纪三四十年代,有多篇基础性的文章出现在公开的文献中,还出现了几篇专题论文,只不过这些论文的内容离当时真正的技术水平相去甚远。战争结束时,情况急转直下,公开的文献几乎殆尽。只有一个突出的例外,那就是Claude Shannon的文章“The Communication Theory of Secrecy Systems”(保密系统的通信理论)[1432]出现在1949年的《Bell System Technical Journal》(贝尔系统技术杂志)上,它类似于Friedman 1918年的文章,也是战时工作的产物。这篇文章在第二次世界大战结束后即被解密,可能是由于失误。
  从1949年到1967年,密码学文献近乎空白。1967年,一部与众不同的著作(David Kahn的《The Codebreakers》(破译者)[794])出现了,它并没有任何新的技术思想,但却对密码学的历史做了相当完整的记述,包括提及政府仍然认为是秘密的某些事情。这部著作的意义不仅在于它涉及了相当广泛的领域,而且在于它使成千上万原本不知道密码学的人了解了密码学。新的密码学文章开始源源不断地发表出来。
  大约在同一时期,早期为空军研制敌我识别装置的Horst Feistel在位于纽约约克镇高地的 IBM Watson实验室里花费了毕生精力致力于密码学的研究。那里他开始着手进行美国数据加密标准(Data Encryption Standard,DES)的研究,20世纪70年代初期,IBM发表了Feistel和他的同事在这个课题方面的多篇技术报告[、552]。
  这就是我于1972年年底涉足密码学领域时的情形,当时密码学的文献还不丰富,但也包括一些非常有价值的东西。
  密码学提出了一个一般学科领域都难以遇到的难题:它需要密码学和密码分析学紧密结合、互为促进。这是由于缺乏实际通信需求所致。提出一个表面上看似不可破译的系统并不难,但许多学术性的设计非常复杂,以至于密码分析家不知从何入手,分析这些设计中的漏洞远比最初设计它们更难。结果是,那些可以强劲推动学术研究的竞争过程在密码学中并没起多大作用。
  当我和Martin Hellman在1975年提出公开密钥密码学[496]时,我们贡献的一个方面是引入了―个看来不易解决的难题。现在有抱负的密码体制设计者能够提出被认为是很聪明的一些东西――这些东西比只是把有意义的正文变成无意义的乱语更有用。结果是研究密码学的人数、召开的会议、发表的论文和专著数都惊人地增加了。
  我在接受Donald E.Fink奖(该奖是奖给在IEEE杂志上发表过最佳文章的人,我和Hellman在1980年共同获得该奖)发表演讲时,告诉听众,我在写“Privacy and Authentication”(保密性与鉴别)一文时有一种体验――这种体验,我相信即使在那些参加IEEE授奖会的著名学者当中也是罕见的:我写的那篇文章,并非我的研究结果而是我想要研究的课题。因为在我首次沉迷于密码学的时候,这类文章根本就找不到。如果那时我可以走进斯坦福书店,挑选现代密码学的书籍,我也许能在多年前就了解这个领域了。但是在1972年秋季,我能找到的资料仅仅是几篇经典论文和一些难以理解的技术报告而已。
  现在的研究人员再也不会遇到这样的问题了,他们的问题是要在大量的文章和书籍中选择从何处入手。研究人员如此,那些仅仅想利用密码学的程序员和工程师又会怎样呢?这些人会转向哪里呢?直到今天,在能够设计出一般文章中所描述的那类密码实用程序之前,花费大量时间寻找并研究那些文献仍然是很有必要的。
  本书正好填补了这个空白。作者Bruce Schneier从通信保密性的目的和达到目的所用的基本程序实例入手,对20年来公开研究的全部成果做了全景式的概括。书名开门见山,从首次叫某人进行保密会话的世俗目的,到数字货币和以密码方式进行保密选举的可能性,到处都可以发现应用密码学的地方。
  Schneier不满足于这本书仅仅涉及真实世界(因为此书叙述了直至代码的全部过程),他还叙述了发展密码学和应用密码学的那些领域,讨论了从国际密码研究协会到国家安全局这样的一些机构。
  在20世纪70年代后期和80年代初期,当公众显示出对密码学的兴趣时,国家安全局 (NSA),即美国官方密码机构,曾多次试图平息它。第一次是一封来自一名长期在NSA工作的雇员的信,据说这封信是这个雇员自己写的,此雇员自认为如此,表面上看来亦是如此。这封信是发给IEEE的,它警告密码资料的出版违反了国际武器交易条例(ITAR)。然而这种观点并没有被条例本身所支持(条例明显不包括已发表的资料)。但这封信却为密码学的公开实践和1977年的信息论专题研讨会做了许多意想不到的宣传。
  一个更为严重的事态发生在1980年,当时NSA为美国教育委员会提供资金,说服国会对密码学领域的出版物进行合法的控制。结果与NSA的愿望大相径庭,形成了密码学论文自愿送审的程序。研究人员在论文发表之前需就发表是否有损国家利益征询NSA的意见。
  随着20世纪80年代的到来,NSA将重点更多地集中在密码学的实际应用,而不是研究上。现有的法律授权NSA通过国务院控制密码设备的出口。随着商务活动的日益国际化和世界市场上美国份额的减少,国内外市场上需要单一产品的压力增加了。这种单一产品受到出口控制,于是NSA不仅对出口什么,而且也对在美国出售什么都施加了相当大的影响。
  密码学的公开使用面临一种新的挑战,政府建议在可防止涂改的芯片上用一种秘密算法代替广为人知且随处可得的DES,这些芯片将含有政府监控所需的编纂机制。这种“密钥托管”计划的弊病是它潜在地损害了个人隐私,并且以前的软件加密不得不以高价增加硬件来实现。迄今,密钥托管产品正值熊市,这种方案却已经引起了广泛的批评,特别是那些独立的密码学家怨声载道。然而,人们看到更多的是编程技术的未来而不是政治,并且还加倍努力向世界提供更强的密码,这种密码能够实现对公众的监督。
  从出口控制法律取代第一修正案的意见来看,1980年发生了大倒退,当时《Federal Register》(联邦公报)公布了对ITAR的修正,其中提到:“……增加的条款清楚地说明,技术数据出口的规定并不干预第一修正案中个人的权利。”但事实上,第一修正案和出口控制法律的紧张关系还未消除,最近由RSA数据安全公司召开的一次会议清楚地表明了这一点。出口控制办公室的NSA代表表达了如下意见:发表密码程序的人从法律上说是处在“灰色领域”。如果真是这样的话,本书第1版业已曝光,内容也处在“灰色领域”中。本书自身的出口申请已经得到军需品控制委员会当局在出版物条款下的认可,但是,装在磁盘上的程序的出口申请却遭到拒绝。
  NSA的策略从试图控制密码研究到紧紧抓住密码产品的开发和应用的改变,可能是由于认识到即便是世界上所有最好的密码学论文都不能保护哪怕是一位的信息。如果束之高阁,本书也许不比以前的书和文章更好,但若置于程序员编写密码的工作站旁,这本书无疑是最好的。
  Whitfield Diffie
  ……我所读过的关于密码学最好的书……该书是美国国家安全局最不愿意见到出版的书……
  ――《Wired》
  ……不朽的……令人着迷的……计算机程序员必读的密码学上决定性的著作……
  ――《Dr.Dobb's Journal》
  ……该领域勿庸置疑的一本权威之作。
  ――《PC Magazine》
  编码高手的圣经。
  ――The Millennium Whole Earth Catalog
  Applied Cryptography:Protocols,Algorithms,and Source Code in C,Second Edition
  基 础 知 识
  1.1专业术语
  1.1.1发送者和接收者
  假设发送者(sender)想发送消息给接收者(receiver),并且想安全地发送信息:她想确信窃听者不能阅读发送的消息。
  1.1.2消息和加密
  消息(message)称为明文(plaintext)。用某种方法伪装消息以隐藏它的内容的过程称为加密(encryption),被加密的消息称为密文(ciphertext),而把密文转变为明文的过程称为解密(decryption)。图1-1表明了这个过程。
  (如果你遵循ISO 7498―2标准,那就用到术语“译成密码(encipher)”和“解译密码(decipher)”。某些文化似乎认为术语“加密(encrypt)”和“解密(decrypt)”令人生厌,如同陈年腐尸。)
  图1-1加密和解密
  使消息保密的技术和科学叫做密码编码学(cryptography),从事此行的人叫做密码编码者(cryptographer),密码分析者(cryptanalyst)是从事密码分析的专业人员,密码分析学(cryptanalysis)就是破译密文的科学和技术,即揭穿伪装。密码学(cryptology)作为数学的一个分支,包括密码编码学和密码分析学两部分,精于此道的人称为密码学家(cryptologist),现代的密码学家通常也是理论数学家。
  明文用M或P表示,它可能是位序列、文本文件、位图、数字化的语音序列或数字化的视频图像等。对于计算机,M指简单的二进制数据(除了这一章外,本书只涉及二进制数据和计算机密码学)。明文可被传送或存储,无论哪种情况,M指待加密的消息。
  密文用C表示,它也是二进制数据,有时和M一样大,有时比M大(通过压缩和加密的结合,C有可能比P小。仅通过加密通常做不到这点)。加密函数E作用于M得到密文C,可用数学公式表示:
  E(M)=C
  相反地,解密函数D作用于C产生M:
  D(C)=M
  先加密后再解密,原始的明文将恢复,故下面的等式必须成立:
  D(E(M))=M
  1.1.3鉴别、完整性和抗抵赖
  除了提供机密性外,密码学通常还有其他的作用:
770)this.width=770;' />
系列图书推荐 ¥99.00¥69.30
同类热销商品¥35.00¥24.50
订单处理配送
北京奥维博世图书发行有限公司 china-pub,All Rights Reserved君,已阅读到文档的结尾了呢~~
几种密码算法在TMS320C6201上的实现,密码算法,凯撒密码算法,对称密码算法,非对称密码算法,分组密码算法,国产密码算法,安盟双因子密码算法,同步有几种实现方法,人民币上有几种文字
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
几种密码算法在TMS320C6201上的实现
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口48314人阅读
C/C++面试题(6)
经典算法面试题及答案&
1. 时针分针重合几次
表面上有60个小格,每小格代表一分钟,
时针每分钟走1/12小格,分针每分钟走1小格,从第一次重合到第二次重合分针比时针多走一圈即60小格,所以
60/(1-1/12)=720/11
每隔720/11分才重合一次(而并不是每小时重合一次)
1440里有22个720/11,如果说算上0点和24点,那也是重合23次而已,但我觉得0点应该算到前一天的24点头上,所以每一天循环下来重合22次啊
2. 找出字符串的最长不重复子串,输出长度
建一个256个单元的数组,每一个单元代表一个字符,数组中保存上次该字符上次出现的位置;
依次读入字符串,同时维护数组的值;
如果遇到冲突了,就返回冲突字符中保存的位置,继续第二步。也可以用hashmap保存已经出现的字符和字符的位置
3. 说是有一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出
现的前十个词。
先用哈希,统计每个词出现的次数,然后在用在N个数中找出前K大个数的方法找出出现
次数最多的前10个词。
4. 如题3,但是车次文件特别大,没有办法一次读入内存。
1) 直接排序,写文件时,同时写入字符串及其出现
2) 可以用哈希,比如先根据字符串的第一个字符将字符串换分为多个区域,每个区域的字符串写到一个文件内,然后再用哈希+堆统计每个区域内前10个频率最高的字符串,最后求出所有字符串中前10个频率最高的字符串。
5. 有一个整数n,将n分解成若干个整数之和,问如何分解能使这些数的乘积最大,输出这个乘积m。例如:n=12
(1)分解为1+1+1+…+1,12个1, m=1*1*1……*1=1
(2)分解为2+2+…+2,6个2, m=64
(3)分解为3+3+3+3,4个3, m=81
(4)大于等于4时分解时只能分解为2和3,且2最多两个
f(n) = 3*f(n-3) n&4
f(4) = 2*2
f(2) = 2分解为4+4+4,3个4, m=64
6. 求数组n中出现次数超过一半的数
把数组分成[n/2]组,则至少有一组包含重复的数,因为如果无重复数,则最多只有出现次数等于一半的数。算法如下:
while k&3 do
把数组分成[k/2]组;
for i=1 to [k/2] do
&& &if 组内2个数相同,则任取一个数留下;
&& &else 2个数同时扔掉;
k&-剩下的数
&& &then 任取2个数进行比较;
&& & &if 两个数不同,则2个数都扔掉
&& & & else 任取一个数
&& &if k=2 or 1 then 任取一数
7. A文件中最多有n个正整数,而且每个数均小于n,n &=10的七次方。不会出现重复的数。
要求对A文件中的数进行排序,可用内存为1M,磁盘可用空间足够。
不要把任何问题都往很复杂的算法上靠,最直接最简单的解决问题才是工程师应有的素质,
题目给的很有分寸:n个数,都小于n,两两不同,1M=10^6byte=10^7bit的内存,n &10^7
把1M内存看作是一个长度为10^7的位数组,每一位都初始化为0
从头扫描n个数,如果碰到i,就把位数组的第i个位置置为1,
1M内存有点少, (1M = 8M bits), 可以代表8M整数,现在n &=10的七次方,你可以读2遍文件,就可以完成排序了。第一次排n &8M得数, 第2遍排 8M &n &10的七次方的数。
8. 有10亿个杂乱无章的数,怎样最快地求出其中前1000大的数。
1) 建一个1000个数的堆,复杂度为N*(log1000)=10N
2) 1.用每一个BIT标识一个整数的存在与否,这样一个字节可以标识8个整数的存在与否,对于所有32位的整数,需要512Mb,所以开辟一个512Mb的字符数组A,初始全0
&& 2.依次读取每个数n,将A[n&&3]设置为A[n&&3]|(1&&n%8),相当于将每个数的对应位设置为1
&& 3.在A中,从大到小读取1000个值为1的数,就是最大的1000个数了。
这样读文件就只需要1遍,在不考虑内存开销的情况下,应该是速度最快的方法了。
9. 一棵树节点1, 2, 3, ... , n. 怎样实现:
先进行O(n)预处理,然后任给两个节点,用O(1)判断它们的父子关系
dfs一遍,记录每个结点的开始访问时间Si和结束访问时间Ei
对于两个节点i,j,若区间[Si,Ei]包含[Sj,Ej],则i是j的祖先。给每个节点哈夫曼编码也行,但只适合一般的二叉树,而实际问题未必是Binary的,所以编码有局限性
10. 给定一个二叉树,求其中N(N&=2)个节点的最近公共祖先节点。每个节点只有左右孩
针,没有父指针。
后序递归给每个节点打分,每个节点的分数=左分数+右分数+k,如果某孩子是给定节点则+1
最深的得分为N的节点就是所求吧,细节上应该不用递归结束就可以得到这个节点
11. 如何打印如下的螺旋队列:
21 22 。。。。
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13
#include &stdio.h&
#define max(a,b) ((a)&(b)?(b):(a))
#define abs(a) ((a)&0?(a):-(a))
int foo(int x, int y)
int t = max(abs(x), abs(y));
int u = t +
int v = u - 1;
v = v * v +
if (x == -t)
&& &v += u + t -
else if (y == -t)
&& &v += 3 * u + x -
else if (y == t )
&& &v += t -
&& & & & &v += y -
int main()
for (y=-2;y&=2;y++)
&& &for (x=-2;x&=2;x++)
&& & &printf(&%5d&, foo(x, y));
&& &printf(&\n&);
第 0 层规定为中间的那个 1,第 1 层为 2 到 9,第 2 层为 10 到 25,……好像看出一点名堂来了?注意到 1、9、25、……不就是平方数吗?而且是连续奇数(1、3、5、……)的平方数。这些数还跟层数相关,推算一下就可以知道第 t 层之内一共有 (2t-1)^2 个数,因而第 t 层会从 [(2t-1)^2] + 1 开始继续往外螺旋。给定坐标 (x,y),如何知道该点处于第几层?so easy,层数 t = max(|x|,|y|)。
知道了层数,接下来就好办多了,这时我们就知道所求的那点一定在第 t 层这个圈上,顺着往下数就是了。要注意的就是螺旋队列数值增长方向和坐标轴正方向并不一定相同。我们可以分成四种情况——上、下、左、右——或者——东、南、西、北,分别处于四条边上来分析。
东|右:x == t,队列增长方向和 y 轴一致,正东方向(y = 0)数值为 (2t-1)^2 + t,所以 v = (2t-1)^2 + t + y
南|下:y == t,队列增长方向和 x 轴相反,正南方向(x = 0)数值为 (2t-1)^2 + 3t,所以 v = (2t-1)^2 + 3t - x
西|左:x == -t,队列增长方向和 y 轴相反,正西方向(y = 0)数值为 (2t-1)^2 + 5t,所以 v = (2t-1)^2 + 5t - y
北|上:y == -t,队列增长方向和 x 轴一致,正北方向(x = 0)数值为 (2t-1)^2 + 7t,所以 v = (2t-1)^2 + 7t + x
12. 一个整数,知道位数,如何判断它是否能被3整除,不可以使用除法和模运算
首先 3x=2^n+1时 仅当 n 为奇数才可能 因为2^n = 3x + (-1)^n;所以该问题就转化为了
找到最后一个为1的位a,看看向前的一个1(b)和这个位的距离,如果为偶数的距离则不能整除,如果是奇数,去除b之后的位继续判断
13. seq=[a,b,...,z,aa,ab,...,az,ba,bb...,bz,...za,zb,...,zz,aaa...],求[a-z]+(从a到z任意字符组成的字符串)s在seq的位置,即排在第几
本质就是26进制。
大家都知道,看一个数是否能被2整除只需要看它的个位能否被2整除即可。可是你想过为什么吗?这是因为10能被2整除,因此一个数10a+b能被2整除当且仅当b能被2整除。大家也知道,看一个数能否被3整除只需要看各位数之和是否能被3整除。这又是为什么呢?答案或多或少有些类似:因为10^n-1总能被3整除。2345可以写成2*(999+1) + 3*(99+1) + 4*(9+1) + 5,展开就是2*999+3*99+4*9 + 2+3+4+5。前面带了数字9的项肯定都能被3整除了,于是要看2345能否被3整除就只需要看2+3+4+5能否被3整除了。当然,这种技巧只能在10进制下使用,不过类似的结论可以推广到任意进制。
&& & 注意到36是4的整数倍,而ZZZ...ZZ除以7总是得555...55。也就是说,判断一个36进制数能否被4整除只需要看它的个位,而一个36进制数能被7整除当且仅当各位数之和能被7整除。如果一个数同时能被4和7整除,那么这个数就一定能被28整除。于是问题转化为,有多少个连续句子满足各位数字和是7的倍数,同时最后一个数是4的倍数。这样,我们得到了一个O(n)的算法:用P[i]表示前若干个句子除以7的余数为i有多少种情况,扫描整篇文章并不断更新P数组。当某句话的最后一个字能被4整除时,假设以这句话结尾的前缀和除以7余x,则将此时P[x]的值累加到最后的输出结果中(两个前缀的数字和除以7余数相同,则较长的前缀多出来的部分一定整除7)。
&& & 上述算法是我出这道题的本意,但比赛后我见到了其它各种各样新奇的算法。比如有人注意到36^n mod 28总是等于8,利用这个性质也可以构造出类似的线性算法来。还有人用动态规划(或者说递推)完美地解决了这个问题。我们用f[i,j]表示以句子i结束,除以28余数为j的文本片段有多少个;处理下一句话时我们需要对每一个不同的j进行一次扫描,把f[i-1,j]加进对应的f[i,j']中。最后输出所有的f[i,0]的总和即可。这个动态规划可以用滚动数组,因此它的空间同前面的算法一样也是常数的。
&& & 如果你完全不知道我在说什么,你可以看看和进位制、同余相关的文章。另外,我之前还曾出过一道很类似的题(VOJ1090),你可以对比着看一看。
有一个整数n,写一个函数f(n),返回0到n之间出现的&1&的个数。比如f(13)=6,现在f(1)=1,问有哪些n能满足f(n)=n?
例如:f(13)=6, 因为1,2,3,4,5,6,7,8,9,10,11,12,13.数数1的个数,正好是6.
public class Test {
public int n = 2;
public int count = 0;
public void BigestNumber(int num) {
for (int i = 1; i &= i++) {
int m = 0;
while (j & 0) {
m = j % 10;
if (m == 1)
&& &count++;
if (j & 0)
&& &j = j / 10;
System.out.println(&f(& + num + &)=& + count);
public static void main(String args[]) {
Test t = new Test();
long begin = System.currentTimeMillis();
t.BigestNumber();
long end = System.currentTimeMillis();
System.out.println(&总时间& + (end-begin)/1000 + &秒&);
1、将一整数逆序后放入一数组中(要求递归实现)
void convert(int *result, int n) {
&if(n&=10)
&&convert(result+1, n/10);
&*result = n%10;
int main(int argc, char* argv[]) {
&int n = , result[20]={};
&convert(result, n);
&printf(&%d:&, n);
&for(int i=0; i&9; i++)
&&printf(&%d&, result);
2、求高于平均分的学生学号及成绩(学号和成绩人工输入)
double find(int total, int n) {
&int number, score, &
&scanf(&%d&, &number);
&if(number != 0) {
&&scanf(&%d&, &score);
&&average = find(total+score, n+1);
&&if(score &= average)
&& printf(&%d:%d\n&, number, score);
&&printf(&Average=%d\n&, total/n);
&&return total/n;
int main(int argc, char* argv[]) {
&find(0, 0);
3、递归实现回文判断(如:abcdedbca就是回文,判断一个面试者对递归理解的简单程序)
int find(char *str, int n) {
&if(n&=1) return 1;
&else if(str[0]==str[n-1]) return find(str+1, n-2);
&else &return 0;
int main(int argc, char* argv[]) {
&char *str = &abcdedcba&;
&printf(&%s: %s\n&, str, find(str, strlen(str)) ? &Yes& : &No&);
4、组合问题(从M个不同字符中任取N个字符的所有组合)
void find(char *source, char *result, int n) {
&if(n==1) {
&&while(*source)
&& & printf(&%s%c\n&, result, *source++);
&&for(i=0; source != 0; i++);
&&for(j=0; result[j] != 0; j++);
&&for(; i&=n; i--) {
&& result[j] = *source++;
&& result[j+1] = '\0';
&& find(source, result, n-1);
int main(int argc, char* argv[]) {
&int const n = 3;
&char *source = &ABCDE&, result[n+1] = {0};
&if(n&0 && strlen(source)&0 && n&=strlen(source))
&&find(source, result, 3);
5、分解成质因数(如*17*17*3*2,据说是华为笔试题)
void prim(int m, int n) {
&if(m&n) {
&&while(m%n != 0) n++;
&&prim(m, n);
&&printf(&%d*&, n);
int main(int argc, char* argv[]) {
&int n = 435234;
&printf(&%d=&, n);
&prim(n, 2);
6、寻找迷宫的一条出路,o:通路; X:障碍。(大家经常谈到的一个小算法题)
#define MAX_SIZE &8
int H[4] = {0, 1, 0, -1};
int V[4] = {-1, 0, 1, 0}; & & & & &
char Maze[MAX_SIZE][MAX_SIZE] = {{'X','X','X','X','X','X','X','X'},
&& & & & & & & & & & & & & & & & {'o','o','o','o','o','X','X','X'},
&& & & & & & & & & & & & & & & & {'X','o','X','X','o','o','o','X'},
&& & & & & & & & & & & & & & {'X','o','X','X','o','X','X','o'},
&& & & & & & & & & & & & {'X','o','X','X','X','X','X','X'},
{'X','o','X','X','o','o','o','X'},
&& & & & {'X','o','o','o','o','X','o','o'},
&& & & & & & & & & & & & & & & & {'X','X','X','X','X','X','X','X'}};
void FindPath(int X, int Y) {
&& &if(X == MAX_SIZE || Y == MAX_SIZE) {
&& & & for(int i = 0; i & MAX_SIZE; i++)
for(int j = 0; j & MAX_SIZE; j++)
&& & & & & & & & &printf(&%c%c&, Maze[j], j & MAX_SIZE-1 ? ' ' : '\n');
}else for(int k = 0; k & 4; k++)
if(X &= 0 && Y &= 0 && Y & MAX_SIZE && X & MAX_SIZE && 'o' == Maze[X][Y]) {
&& & & & & & & & & Maze[X][Y] = ' ';
&& & & & & & & & & FindPath(X+V[k], Y+H[k]);
&& & & & & & & & & Maze[X][Y] ='o';
int main(int argc, char* argv[]) {
&& &FindPath(1,0);
7、随机分配座位,共50个学生,使学号相邻的同学座位不能相邻(早些时候用C#写的,没有用C改写)。
static void Main(string[] args)
&int Tmp = 0, Count = 50; &
&int[] Seats = new int[Count]; &
&bool[] Students = new bool[Count];
&System.Random RandStudent=new System.Random();
&Students[Seats[0]=RandStudent.Next(0,Count)]=
&for(int i = 1; i & C ) {
&& & Tmp=(int)RandStudent.Next(0,Count);
&& & if((!Students[Tmp])&&(Seats[i-1]-Tmp!=1) && (Seats[i-1] - Tmp) != -1) {
&& Seats[i++] = T
Students[Tmp] =
&foreach(int Student in Seats)
&& & System.Console.Write(Student + & &);
&System.Console.Read();
8、求网格中的黑点分布。现有6*7的网格,在某些格子中有黑点,已知各行与各列中有黑点的点数之和,请在这张网格中画出黑点的位置。(这是一网友提出的题目,说是他笔试时遇到算法题)
#define ROWS 6
#define COLS 7
int iPointsR[ROWS] = {2, 0, 4, 3, 4, 0}; & & & & & // 各行黑点数和的情况
int iPointsC[COLS] = {4, 1, 2, 2, 1, 2, 1}; & & & &// 各列黑点数和的情况
int iCount, iF
int iSumR[ROWS], iSumC[COLS], Grid[ROWS][COLS];
int Set(int iRowNo) {
if(iRowNo == ROWS) {
&& & & &for(int iColNo=0; iColNo & COLS && iSumC[iColNo]==iPointsC[iColNo]; iColNo++)
&& & & & & if(iColNo == COLS-1) {
&& & & & & & & printf(&\nNo.%d:\n&, ++iCount);
&& & & & & & & for(int i=0; i & ROWS; i++)
&& & & & & & & & &for(int j=0; j & COLS; j++)
&& & & & & & & & & & &printf(&%d%c&, Grid[j], (j+1) % COLS ? ' ' : '\n');
&& & & & & & & iFound = 1; // iFound = 1,有解
&& & & & & }
&& &} else {
&& & & &for(int iColNo=0; iColNo & COLS; iColNo++) {
&& & & & & &if(iPointsR[iRowNo] == 0) {
&& & & & & & & &Set(iRowNo + 1);
&& } else if(Grid[iRowNo][iColNo]==0) {
Grid[iRowNo][iColNo] = 1;
iSumR[iRowNo]++; iSumC[iColNo]++; & & & & & & & & & & & & & & & & &if(iSumR[iRowNo]&iPointsR[iRowNo] && iSumC[iColNo]&=iPointsC[iColNo])
&& & & & & & & & & & Set(iRowNo);
else if(iSumR[iRowNo]==iPointsR[iRowNo] && iRowNo & ROWS)
&& & & & & & & & & & Set(iRowNo + 1);
&& & & & & & & &Grid[iRowNo][iColNo] = 0;
&& & & & & & & &iSumR[iRowNo]--;
iSumC[iColNo]--;
&& & & & & &}
return iF & & // 用于判断是否有解
int main(int argc, char* argv[]) {
&& &if(!Set(0))
&& & & &printf(&Failure!&);
9、有4种面值的邮票很多枚,这4种邮票面值分别1, 4, 12, 21,现从多张中最多任取5张进行组合,求取出这些邮票的最大连续组合值。(据说是华为2003年校园招聘笔试题)
#define N 5
#define M 5
int k, Found, Flag[N];
int Stamp[M] = {0, 1, 4, 12, 21};
// 在剩余张数n中组合出面值和Value
int Combine(int n, int Value) {
&if(n &= 0 && Value == 0) {
&&Found = 1;
&&int Sum = 0;
&&for(int i=0; i&N && Flag != 0; i++) {
&& Sum += Stamp[Flag];
&& printf(&%d &, Stamp[Flag]);
&&printf(&\tSum=%d\n\n&, Sum);
&}else for(int i=1; i&M && !Found && n&0; i++)
&&if(Value-Stamp &= 0) {
&& Flag[k++] =
&& Combine(n-1, Value-Stamp);
&& Flag[--k] = 0;
int main(int argc, char* argv[]) {
&for(int i=1; Combine(N, i); i++, Found=0);
10、大整数数相乘的问题。(这是2002年在一考研班上遇到的算法题)
void Multiple(char A[], char B[], char C[]) {
&& &int TMP, In=0, LenA=-1, LenB=-1;
&& &while(A[++LenA] != '\0');
&& &while(B[++LenB] != '\0');
&& &int Index, Start = LenA + LenB - 1;
&& &for(int i=LenB-1; i&=0; i--) {
&& & & &Index = Start--;
&& & & &if(B != '0') {
&& & & & & &for(int In=0, j=LenA-1; j&=0; j--) {
&& & & & & & & &TMP = (C[Index]-'0') + (A[j]-'0') * (B - '0') + In;
&& & & & & & & &C[Index--] = TMP % 10 + '0';
&& & & & & & & &In = TMP / 10;
&& & & & & &}
&& & & & & &C[Index] = In + '0';
int main(int argc, char* argv[]) {
&& &char A[] = &88889&;
&& &char B[] = &99988&;
char C[sizeof(A) + sizeof(B) - 1];
&& &for(int k=0; k&sizeof(C); k++)
&& & & &C[k] = '0';
&& &C[sizeof(C)-1] = '\0';
&& &Multiple(A, B, C);
&& &for(int i=0; C != '\0'; i++)
&& & & &printf(&%c&, C);
11、求最大连续递增数字串(如“ads3sl56ld345AA”中的“456789”)
int GetSubString(char *strSource, char *strResult) {
&& &int iTmp=0, iHead=0, iMax=0;
&& &for(int Index=0, iLen=0; strSource[Index]; Index++) {
&& & & &if(strSource[Index] &= '0' && strSource[Index] &= '9' &&
strSource[Index-1] & '0' && strSource[Index] == strSource[Index-1]+1) {
&& & & & & &iLen++; & & & & & & & & & & & // 连续数字的长度增1
&& & & &} else { & & & & & & & & & & & & &// 出现字符或不连续数字
&& & & & & &if(iLen & iMax) {
&& & & & & &iMax = iL &iHead = iT
&& & & & & &} & & &&
&& & & &// 该字符是数字,但数字不连续
&& & & & & &if(strSource[Index] &= '0' && strSource[Index] &= '9') {
&& & & & & & & &iTmp = I
&& & & & & &}
&& & & &} &&
&& &for(iTmp=0 ; iTmp & iM iTmp++) // 将原字符串中最长的连续数字串赋值给结果串
&& & & &strResult[iTmp] = strSource[iHead++];
&& &strResult[iTmp]='\0';
&& &return iM & & // 返回连续数字的最大长度
int main(int argc, char* argv[]) {
&& &char strSource[]=&ads3sl56ld345AA&, char strResult[sizeof(strSource)];
printf(&Len=%d, strResult=%s \nstrSource=%s\n&,
GetSubString(strSource, strResult), strResult, strSource);
12、四个工人,四个任务,每个人做不同的任务需要的时间不同,求任务分配的最优方案。(日全国计算机软件资格水平考试——软件设计师的算法题)。
#include &stdafx.h&
#define N 4
int Cost[N][N] = { {2, 12, 5, 32}, &// 行号:任务序号,列号:工人序号
&& & & & & & & & & &{8, 15, 7, 11}, &// 每行元素值表示这个任务由不同工人完成所需要的时间
&& & & & & & & & & &{24, 18, 9, 6},
&& & & & & & & & & &{21, 1, 8, 28}};
int MinCost=1000;
int Task[N], TempTask[N], Worker[N];
void Assign(int k, int cost) {
&if(k == N) {
&&MinCost =
&&for(int i=0; i&N; i++)
&& TempTask = T
&&for(int i=0; i&N; i++) {
&& if(Worker==0 && cost+Cost[k] & MinCost) { // 为提高效率而进行剪枝
&& &Worker = 1; Task[k] =
&& &Assign(k+1, cost+Cost[k]);
&& &Worker = 0; Task[k] = 0;
int main(int argc, char* argv[]) {
&Assign(0, 0);
&printf(&最佳方案总费用=%d\n&, MinCost);
&for(int i=0; i&N; i++)&
&&printf(&\t任务%d由工人%d来做:%d\n&, i, TempTask, Cost[TempTask]);
13、八皇后问题,输出了所有情况,不过有些结果只是旋转了90度而已。(回溯算法的典型例题,是数据结构书上算法的具体实现,大家都亲自动手写过这个程序吗?)
#define N 8
int Board[N][N];
int Valid(int i, int j) { &// 判断下棋位置是否有效
&int k = 1;
&for(k=1; i&=k && j&=k;k++)
&&if(Board[i-k][j-k]) return 0;
&for(k=1; i&=k;k++)
&&if(Board[i-k][j]) &return 0;
&for(k=1; i&=k && j+k&N;k++)
&&if(Board[i-k][j+k]) return 0;
&return 1;
void Trial(int i, int n) { &// 寻找合适下棋位置
&if(i == n) {
&&for(int k=0; k&n; k++) {
&& for(int m=0; m&n; m++)
&& &printf(&%d &, Board[k][m]);
&& printf(&\n&);
&&printf(&\n&);
&&for(int j=0; j&n; j++) {
&& Board[j] = 1;
&& if(Valid(i,j))
&& &Trial(i+1, n);
&& Board[j] = 0;
int main(int argc, char* argv[]) {
&Trial(0, N);
14、实现strstr功能,即在父串中寻找子串首次出现的位置。(笔试中常让面试者实现标准库中的一些函数)
char * strstring(char *ParentString, char *SubString) {
&char *pSubString, *pPareS
&for(char *pTmp=ParentS *pT pTmp++) {
&&pSubString = SubS
&&pPareString = pT
&&while(*pSubString == *pPareString && *pSubString != '\0') {
&& pSubString++;
&& pPareString++;
&&if(*pSubString == '\0') &return pT
&return NULL;
int main(int argc, char* argv[]) {
&char *ParentString = &happy birthday to you!&;
&char *SubString = &birthday&;
&printf(&%s&,strstring(ParentString, SubString));
15、现在小明一家过一座桥,过桥的时候是黑夜,所以必须有灯。现在小明过桥要1分,小明的弟弟要3分,小明的爸爸要6分,小明的妈妈要8分,小明的爷爷要12分。每次此桥最多可过两人,而过桥的速度依过桥最慢者而定,而且灯在点燃后30分就会熄灭。问小明一家如何过桥时间最短?(原本是个小小智力题,据说是外企的面试题,在这里用程序来求解)
#include &stdafx.h&
#define N & &5
#define SIZE 64
// 将人员编号:小明-0,弟弟-1,爸爸-2,妈妈-3,爷爷-4
// 每个人的当前位置:0--在桥左边, 1--在桥右边
int Position[N]; &&
// 过桥临时方案的数组下标; 临时方案; 最小时间方案;
int Index, TmpScheme[SIZE], Scheme[SIZE]; &
// 最小过桥时间总和,初始&#;每个人过桥所需要的时间
int MinTime=100, Time[N]={1, 3, 6, 8, 12};&
// 寻找最佳过桥方案。Remnant:未过桥人数; CurTime:当前已用时间;
// Direction:过桥方向,1--向右,0--向左
void Find(int Remnant, int CurTime, int Direction) {
&& &if(Remnant == 0) { & & & & & & & & & & & & & & & // 所有人已经过桥,更新最少时间及方案
&& & & &MinTime=CurT
&& & & &for(int i=0; i&SIZE && TmpScheme&=0; i++)
&& & & & & &Scheme = TmpS
&& &} else if(Direction == 1) { & & & & & & & & & & & &// 过桥方向向右,从桥左侧选出两人过桥
&& & & &for(int i=0; i&N; i++) & & & & & & & & &&
&& & & & & &if(Position == 0 && CurTime + Time & MinTime) {
&& & & & & & & &TmpScheme[Index++] =
&& & & & & & & &Position = 1;
&& & & & & & & &for(int j=0; j&N; j++) {
&& & & & & & & & & &int TmpMax = (Time & Time[j] ? Time : Time[j]);
&& & & & & & & & & &if(Position[j] == 0 && CurTime + TmpMax & MinTime) {
&& & & & & & & & & & & &TmpScheme[Index++] = &&
&& & & & & & & & & & & &Position[j] = 1; & & &&
&& & & & & & & & & & & &Find(Remnant - 2, CurTime + TmpMax, !Direction);
&& & & & & & & & & & & &Position[j] = 0; & & &&
&& & & & & & & & & & & &TmpScheme[--Index] = -1;
&& & & & & & & & & &}
&& & & & & & & &}
&& & & & & & & &Position = 0;
&& & & & & & & &TmpScheme[--Index] = -1;
&& & & & & &}
&& &} else { & & & &// 过桥方向向左,从桥右侧选出一个人回来送灯
&& & & &for(int j=0; j&N; j++) {
&& & & & & &if(Position[j] == 1 && CurTime+Time[j] & MinTime) {
&& & & & & & & &TmpScheme[Index++] =
&& & & & & & & &Position[j] = 0;
&& & & & & & & &Find(Remnant+1, CurTime+Time[j], !Direction);
&& & & & & & & &Position[j] = 1;
&& & & & & & & &TmpScheme[--Index] = -1;
&& & & & & &}
int main(int argc, char* argv[]) {
&& &for(int i=0; i&SIZE; i++) & // 初始方案内容为负值,避免和人员标号冲突
&& & & &Scheme = TmpScheme = -1;
Find(N, 0, 1); & & & &// 查找最佳方案
&& &printf(&MinTime=%d:&, MinTime); // 输出最佳方案
&& &for(int i=0; i&SIZE && Scheme&=0; i+=3)
&& & & &printf(& &%d-%d &%d&, Scheme, Scheme[i+1], Scheme[i+2]);
&& &printf(&\b\b &&);
16、2005年11月金山笔试题。编码完成下面的处理函数。函数将字符串中的字符'*'移到串的前部分,前面的非'*'字符后移,但不能改变非'*'字符的先后顺序,函数返回串中字符'*'的数量。如原始串为:ab**cd**e*12,处理后为*****abcde12,函数并返回值为5。(要求使用尽量少的时间和辅助空间)
int change(char *str) { & &
&int count = 0; & &
&for(int i=0, j=0; i++) {&
&&if(str=='*') { &&
&& for(j=i-1; str[j]!='*'&&j&=0; j--)
&& &str[j+1]=str[j]; & &
&& str[j+1] = '*';
&& count++;
int main(int argc, char* argv[]) {
&char str[] = &ab**cd**e*12&;
&printf(&str1=%s\n&, str);
&printf(&str2=%s, count=%d&, str, change(str));
// 终于得到一个比较高效的算法,一个网友提供,估计应该和金山面试官的想法一致。算法如下:
int change(char *str) {
&int i,j=strlen(str)-1;
&for(i=j; j&=0; j--) {
&&if(str!='*') {
&&} else if(str[j]!='*') {
&& str = str[j];
&& str[j] = '*';
&return i+1;
17、日华为软件研发笔试题。实现一单链表的逆转。
#include &stdafx.h&
typedef char eleT &// 定义链表中的数据类型
typedef struct listnode &{ // 定义单链表结构
&struct listnode *
node *create(int n) { &// 创建单链表,n为节点个数
&node *p = (node *)malloc(sizeof(node));
&node *head = &head-&data = 'A';
&for(int i='B'; i&'A'+n; i++) { &&
&&p = (p-&next = (node *)malloc(sizeof(node)));
&&p-&data =
&&p-&next = NULL;&
void print(node *head) { // 按链表顺序输出链表中元素
&for(; head = head-&next)
&&printf(&%c &, head-&data);
&printf(&\n&);
node *reverse(node *head, node *pre) { // 逆转单链表函数。这是笔试时需要写的最主要函数
&node *p=head-&
&head-&next =
&if(p) return reverse(p, head);
int main(int argc, char* argv[]) {
&node *head = create(6);
&print(head);
&head = reverse(head, NULL);
&print(head);
18、编码实现字符串转整型的函数(实现函数atoi的功能),据说是神州数码笔试题。如将字符串 ”+123”?123, ”-0123”?-123, “123CS45”?123, “123.45CS”?123, “CS123.45”?0
#include &stdafx.h&
int str2int(const char *str) { & &// 字符串转整型函数
&int i=0, sign=1, value = 0;
&if(str==NULL) &return NULL; & &// 空串直接返回 NULL
&if(str[0]=='-' || str[0]=='+') { & // 判断是否存在符号位
&&sign = (str[0]=='-' ? -1 : 1);
&for(; str&='0' && str&='9'; i++) // 如果是数字,则继续转换
&&value = value * 10 + (str - '0');
&return sign *
int main(int argc, char *argv[]) {
&char *str = &-123.45CS67&;
&int &val &= str2int(str);
&printf(&str=%s\tval=%d\n&, str, val);
19、歌德巴赫猜想。任何一个偶数都可以分解为两个素数之和。(其实这是个C二级考试的模拟试题)
#include &stdafx.h&
#include &math.h&
int main(int argc, char* argv[]) {
&int Even=78, Prime1, Prime2, Tmp1, Tmp2;
&for(Prime1=3; Prime1&=Even/2; Prime1+=2) {
&&for(Tmp1=2,Tmp2=sqrt(float(Prime1)); Tmp1&=Tmp2 && Prime1%Tmp1 != 0; Tmp1++);
&&if(Tmp1&=Tmp2)
&&Prime2 = Even-Prime1;
&&for(Tmp1=2,Tmp2=sqrt(float(Prime2)); Tmp1&=Tmp2 && Prime2%Tmp1 != 0; Tmp1++);
&&if(Tmp1&=Tmp2)
&&printf(&%d=%d+%d\n&, Even, Prime1, Prime2);
20、快速排序(东软喜欢考类似的算法填空题,又如堆排序的算法等)
#include &stdafx.h&
#define N 10
int part(int list[], int low, int high) { &// 一趟排序,返回分割点位置
&int tmp = list[low];
&while(low&high) {
&&while(low&high && list[high]&=tmp) --
&&list[low] = list[high];
&&while(low&high && list[low]&=tmp) &++
&&list[high] = list[low];
&list[low] =
void QSort(int list[], int low, int high) { // 应用递归进行快速排序
&if(low&high) {
&&int mid = part(list, low, high);
&&QSort(list, low, mid-1);
&&QSort(list, mid+1, high);
void show(int list[], int n) { & &// 输出列表中元素
&for(int i=0; i&n; i++)
&&printf(&%d &, list);
&printf(&\n&);
int main(int argc, char* argv[]) {
&int list[N] = {23, 65, 26, 1, 6, 89, 3, 12, 33, 8};
&show(list, N); & & &// 输出排序前序列
&QSort(list, 0, N-1); & & // 快速排序
&show(list, N); & & &// 输出排序后序列
21、日慧通笔试题:写一函数判断某个整数是否为回文数,如12321为回文数。可以用判断入栈和出栈是否相同来实现(略微复杂些),这里是将整数逆序后形成另一整数,判断两个整数是否相等来实现的。
#include &stdafx.h&
int IsEchoNum(int num) {
&int tmp = 0;
&for(int n = n/=10)
&&tmp = tmp *10 + n%10;
&return tmp==
int main(int argc, char* argv[]) {
&int num = 12321;
&printf(&%d &%d\n&, num, IsEchoNum(num));
22、删除字符串中的数字并压缩字符串(神州数码以前笔试题),如字符串”abc123de4fg56”处理后变为”abcdefg”。注意空间和效率。(下面的算法只需要一次遍历,不需要开辟新空间,时间复杂度为O(N))
#include &stdafx.h&
void delNum(char *str) {
&int i, j=0;
// 找到串中第一个数字的位子
&for(i=j=0; str && (str&'0' || str&'9'); j=++i);
&// 从串中第一个数字的位置开始,逐个放入后面的非数字字符
&for(; i++) &
&&if(str&'0' || str&'9')
&& str[j++] =
&str[j] = '\0';
int main(int argc, char* argv[]) {
&char str[] = &abc123ef4g4h5&;
&printf(&%s\n&, str);
&delNum(str);
&printf(&%s\n&, str);
23、求两个串中的第一个最长子串(神州数码以前试题)。如&abractyeyt&,&dgdsaeactyey&的最大子串为&actyet&。
#include &stdafx.h&
char *MaxSubString(char *str1, char *str2) {
&int i, j, k, index, max=0;
&for(i=0; str1; i++)
&&for(j=0; str2[j]; j++) {
&& for(k=0; str1[i+k]==str2[j+k] && (str2[i+k] || str1[i+k]); k++);
&& if(k&max) { &// 出现大于当前子串长度的子串,则替换子串位置和程度
&& &index = max =
&char *strResult = (char *)calloc(sizeof(char), max+1);
&for(i=0; i& i++)&
&&strResult = str2[index++];
&return strR
int main(int argc, char* argv[]) {
&char str1[] = &abractyeyt&, str2[] = &dgdsaeactyey&;
&char *strResult = MaxSubString(str1, str2);
&printf(&str1=%s\nstr2=%s\nMaxSubString=%s\n&, str1, str2, strResult);
24、不开辟用于交换数据的临时空间,如何完成字符串的逆序(在技术一轮面试中,有些面试官会这样问)
#include &stdafx.h&
void change(char *str) {
&for(int i=0,j=strlen(str)-1; i&j; i++, j--){
&&str ^= str[j] ^= str ^= str[j];
int main(int argc, char* argv[]) {
&char str[] = &abcdefg&;
&printf(&strSource=%s\n&, str);
&change(str);
&printf(&strResult=%s\n&, str);
&return getchar();
25、删除串中指定的字符(做此题时,千万不要开辟新空间,否则面试官可能认为你不适合做嵌入式开发)
#include &stdafx.h&
void delChar(char *str, char c) {
&int i, j=0;
&for(i=0; i++)
&&if(str!=c) str[j++]=
&str[j] = '\0';
int main(int argc, char* argv[]) {
&char str[] = &abcdefgh&; // 注意,此处不能写成char *str = &abcdefgh&;
&printf(&%s\n&, str);
&delChar(str, 'c');
&printf(&%s\n&, str);
26、判断单链表中是否存在环(网上说的笔试题)
#include &stdafx.h&
typedef char eleT & &// 定义链表中的数据类型
typedef struct listnode &{ & // 定义单链表结构
&struct listnode *
node *create(int n) { & &// 创建单链表,n为节点个数
&node *p = (node *)malloc(sizeof(node));
&node *head = &head-&data = 'A';
&for(int i='B'; i&'A'+n; i++) {
&&p = (p-&next = (node *)malloc(sizeof(node)));
&&p-&data =
&&p-&next = NULL;
void addCircle(node *head, int n) { // 增加环,将链尾指向链中第n个节点
&node *q, *p =
&for(int i=1; p-& i++) {
&&if(i==n) q =
&p-&next =
int isCircle(node *head) { & // 这是笔试时需要写的最主要函数,其他函数可以不写
&node *p=head,*q=
&while( p-&next && q-&next) {
&&if (NULL == (q=q-&next-&next)) return 0;
&&if (p == q) return 1;
&return 0;
int main(int argc, char* argv[]) {
&node *head = create(12);
&addCircle(head, 8); & // 注释掉此行,连表就没有环了
&printf(&%d\n&, isCircle(head));
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:89728次
排名:千里之外
转载:40篇
(1)(2)(1)(1)(1)(1)(2)(1)(3)(4)(10)(13)

我要回帖

更多关于 已知函数f x m x 的文章

 

随机推荐