﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-漫步者-文章分类-算法学习</title><link>http://www.cppblog.com/Walker/category/10284.html</link><description>先学会转文章，在仔细读文章，最后自己写点东西........</description><language>zh-cn</language><lastBuildDate>Thu, 23 Jul 2009 08:33:45 GMT</lastBuildDate><pubDate>Thu, 23 Jul 2009 08:33:45 GMT</pubDate><ttl>60</ttl><item><title>同步/异步与阻塞/非阻塞的区别 （转）</title><link>http://www.cppblog.com/Walker/articles/82900.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Thu, 14 May 2009 00:44:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/82900.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/82900.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/82900.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/82900.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/82900.html</trackback:ping><description><![CDATA[<div class=postTitle><a class=postTitle2 id=viewpost1_TitleUrl href="http://www.cppblog.com/converse/archive/2009/05/13/82879.html"><font color=#1a8bc8>同步/异步与阻塞/非阻塞的区别</font></a> </div>
我喜欢用自己的语言通过联系现实生活中的一些现象解释一些概念,当我能做到这一点时,说明我已经理解了这个概念.今天要解释的概念是:同步/异步与阻塞/非阻塞的区别.<br><br>这两组概念常常让人迷惑,因为它们都是涉及到IO处理,同时又有着一些相类似的地方.<br><br>首先来解释同步和异步的概念,这两个概念与<span style="FONT-WEIGHT: bold">消息的通知机制</span>有关.<br><br>举个例子,比如我去银行办理业务,可能选择排队等候,也可能取一个小纸条上面有我的号码,等到排到我这一号时由柜台的人通知我轮到我去办理业务了.<br>前者(排队等候)就是同步等待消息,而后者(等待别人通知)就是异步等待消息.在异步消息处理中,等待消息者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码)找到等待该事件的人.<br>而在实际的程序中,同步消息处理就好比简单的read/write操作,它们需要等待这两个操作成功才能返回;而异步处理机制就是类似于select/poll之类的多路复用IO操作,当所关注的消息被触发时,由消息触发机制通知触发对消息的处理.<br><br>其次再来解释一下阻塞和非阻塞,这两个概念与<span style="FONT-WEIGHT: bold">程序等待消息(无所谓同步或者异步)时的状态</span>有关.<br>继续上面的那个例子,不论是排队还是使用号码等待通知,如果在这个等待的过程中,等待者除了等待消息之外不能做其它的事情,那么该机制就是阻塞的,表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行.相反,有的人喜欢在银行办理这些业务的时候一边打打电话发发短信一边等待,这样的状态就是非阻塞的,因为他(等待者)没有阻塞在这个消息通知上,而是一边做自己的事情一边等待.但是需要注意了,第一种同步非阻塞形式实际上是效率低下的,想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,如果把打电话和观察排队的位置看成是程序的两个操作的话,这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的;而后者,异步非阻塞形式却没有这样的问题,因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的操作中来回切换.<br><br>很多人会把同步和阻塞混淆,我想是因为很多时候同步操作会以阻塞的形式表现出来,比如很多人会写阻塞的read/write操作,但是别忘了可以对fd设置O_NONBLOCK标志位,这样就可以将同步操作变成非阻塞的了;同样的,很多人也会把异步和非阻塞混淆,因为异步操作一般都不会在真正的IO操作处被阻塞,比如如果用select函数,当select返回可读时再去read一般都不会被阻塞,就好比当你的号码排到时一般都是在你之前已经没有人了,所以你再去柜台办理业务就不会被阻塞.<br><br>可见,同步/异步与阻塞/非阻塞是两组不同的概念,它们可以共存组合,也可以参见这里:<br>http://www.ibm.com/developerworks/cn/linux/l-async/<br>
<img src ="http://www.cppblog.com/Walker/aggbug/82900.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-05-14 08:44 <a href="http://www.cppblog.com/Walker/articles/82900.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转）strlen源码剖析 http://www.cppblog.com/ant/archive/2007/10/12/32886.html</title><link>http://www.cppblog.com/Walker/articles/82347.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Sat, 09 May 2009 01:50:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/82347.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/82347.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/82347.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/82347.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/82347.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 学习高效编程的有效途径之一就是阅读高手写的源代码，CRT(C/C++ Runtime Library)作为底层的函数库，实现必然高效。恰好手中就有glibc和VC的CRT源代码，于是挑了一个相对简单的函数strlen研究了一下，并对各种实现作了简单的效率测试。strlen的函数原形如下：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t strlen(const ...&nbsp;&nbsp;<a href='http://www.cppblog.com/Walker/articles/82347.html'>阅读全文</a><img src ="http://www.cppblog.com/Walker/aggbug/82347.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-05-09 09:50 <a href="http://www.cppblog.com/Walker/articles/82347.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】一个游戏程序员的学习资料 </title><link>http://www.cppblog.com/Walker/articles/81443.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Wed, 29 Apr 2009 07:07:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/81443.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/81443.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/81443.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/81443.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/81443.html</trackback:ping><description><![CDATA[<p align=center><span>一个游戏程序员的学习资料</span></p>
<p>&nbsp;</p>
<p><span>想起写这篇文章是在看<st1:personname w:st="on" productid="侯杰">侯杰</st1:personname>先生的《深入浅出<span>MFC</span>》时<span>,</span>突然觉得自己在大学这几年关于游戏编程方面还算是有些心得，因此写出这篇小文<span>,</span>介绍我眼中的游戏程序员的书单与源代码参考。一则是作为自己今后两年学习目标的备忘录<span>,</span>二来没准对别人也有点参考价值。我的原则是只写自己研究过或准备研究的资料，所以内容无疑会带上强烈的个人喜好色彩<span>,</span>比如对网络<span>,</span>数据库等重要方面完全没有涉及。因为自己主要对三维图形引擎<span>,</span>人工智能算法<span>,</span>脚本系统<span>,</span>反外挂<span>(</span>反反外挂<span>? ^</span>－<span>^)</span>等方面感兴趣。这学期电脑都没联网了<span>,</span>在岳麓山闭关修炼中<span>(^</span>－<span>^),</span>连这篇文章都得在学校图书馆电子阅览室（电影放映室？）上传<span>,</span>内容很多凭记忆写出<span>,</span>如有误差敬请订正。程序员应该在理论学习与实践编程中反复迭代，所以学习资料是一回事，须知尽信书不如无书。</span></p>
<p>&nbsp;</p>
<p><span>一、书籍：</span></p>
<p><span>算法与数据结构：</span></p>
<p><span>《数据结构（<span>C</span>语言版）》——严蔚敏、吴伟民 清华出版社</span></p>
<p><span>我觉得其配套习题集甚至比原书更有价值，每个较难的题都值得做一下。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Introduction to Algorithms</span>》第二版 中文名《算法导论》</span></p>
<p><span>关于算法的标准学习教材与工程参考手册，在去年<span>CSDN</span>网站上其翻译版竟然评为年度二十大技术畅销书，同时《程序员》杂志上开设了&#8220;算法擂台&#8221;栏目，这些溯源固本的举动，不由得使人对中国现今浮躁不堪的所谓&#8220;<span>IT</span>&#8221;业又产生了一线希望。这本厚厚的书，幸亏打折我才买得起。虽然厚达千页，但其英文通俗晓畅，内容深入浅出，可见经典之作往往比一般水准的书还耐读。还能找到<span>MIT</span>的视频教程，第一节课<st1:personname w:st="on" productid="那个老">那个老</st1:personname>教授嘻皮笑脸的，后面就是一长发助教上课了。</span></p>
<p>&nbsp;</p>
<p><span>《<span>C</span>语言名题精选百则 技巧篇》——冼镜光 机械工业出版社</span></p>
<p><span>作者花费一年时间搜集了各种常见<span>C</span>程序段的极具技巧性的编程法，其内容都是大有来头的，而且给出了详细的参考资料。如一个普通的<span>Fibonacci</span>数就给出了非递归解、快速算法、扩充算法等，步步深入，直至几无油水可榨。对于视速度如生命，连一个普通的浮点数转化为整数都另辟蹊径以减少<span>CPU cycle</span>的游戏程序员，怎可不看？</span></p>
<p>&nbsp;</p>
<p><span>《计算机算法基础（第二版）》—— 佘祥宣等 华中科大出版社</span></p>
<p><span>我看到几个学校的研究生拿它作教材（研究生才开算法，太开玩笑了吧）。这本书薄是薄了点，用作者的话来说，倒也&#8220;精辟&#8221;。其实此书是《<span>Fundamentals of Computer Algorithms</span>》的缩写版，不过原书出版太久了，反正我是没找到。</span></p>
<p>&nbsp;</p>
<p><span>《<span>The Art of Computer Programming</span>》<span>Volume 1-3</span></span></p>
<p><span>作者<span>Donald E. Knuth</span>是我心目中与冯<span>.</span>诺依曼、<span>Dijkstra</span>、<span>Shannon</span>并列的四位大师。这本书作者从读大学本科时开始写，一直写到博士时，十年磨一剑，足见其下足了功夫。可作为计算机技术的核心——算法与数据结构的终极参考手册。创新处也颇多，譬如常见的<span>Shell</span>排序他在书中提出可用<span>(3i-1)/2</span>的间隔，这使其稍快于<span>O(n1. 5)</span>。当然这套书描述高度数学化，为此恐怕一般的人（我？）最好还得先看一本数学预备书《<span>Concrete Mathematics</span>》（直译为混凝土数学？<span>^</span>－<span>^</span>）再说。可惜的是这套书才出到第三卷，并没有覆盖全部常见的算法内容。不过好在对于游戏程序员来说，越常见的算法用得越多，这也不算是什么要命的损失。</span></p>
<p>&nbsp;</p>
<p><span>《<span>STL</span>源码剖析》—— 侯捷 华中科大出版社</span></p>
<p><span>侯捷不用介绍了，华人技术作家中的旗舰，说其有世界级水准也不为过。这本书我以为是<span>C++</span>与数据结构的葵花宝典（欲练此功，必先自宫）。也就是说，不下几层地狱很难看懂，因为它要求的预备知识太多了，如<span>STL</span>、数据结构、泛型编程、内存管理都要很扎实（为此是不是还要看看有内存管理设计模式之称的《<span>Small Memory Software</span>》这本书呢？），但是一旦看懂，真会是所向披靡。</span></p>
<p><span>&nbsp;</span></p>
<p><span>《<span>Data Structures for Game Programmers</span>》</span></p>
<p><span>每个数据结构的例程都是一个小游戏，还用<span>SDL</span>库实现了一个算法演示系统。虽然内容失之于浅，但起码让人了解了数据结构在游戏中的作用。</span></p>
<p>&nbsp;</p>
<p><span>其实游戏程序并不比其它程序特殊，甚至要求基本功更加扎实，所以花时间做一些看似与实际应用不甚相干的习题，对今后的工作是大有裨益的。而且有些应用很广的算法，如常被人津津乐道的<span>A*</span>算法及其变种，牵涉到图的检索周游与分枝<span>-</span>限界法，恐怕还得读一些艰深的论文才能充分明白运用，如<span>Donald E. Knuth</span>的《<span>An analysis of alpha-beta cutoffs</span>》。其实还有不少此类的好书，如《<span>Data Structures and Algorithms in C++</span>》、《<span>Programming Pearls</span>》、《<span>More Programming Pearls</span>》（算法珠玑）等，我却以为要先看严谨一点的著作，再看内容随笔一点的书。</span></p>
<p>&nbsp;</p>
<p><span>汇编：</span></p>
<p><span>《<span>IBM-PC </span>汇编语言程序设计》第二版　</span></p>
<p><span>国内经典教材。</span></p>
<p><span>《<span>The Art of Assembly Language</span>》</span></p>
<p><span>这本书足有<span>1600</span>页，噢！</span></p>
<p>&nbsp;</p>
<p><span>C</span><span>语言：</span></p>
<p><span>《<span>The C Programming Language</span>》第二版</span></p>
<p><span>虽然篇幅短小，但每个例程都很经典。（我们老师开始拿它作教材，后面换为谭小强的<span>C</span>语言书，理由为：例子尽是些文本处理。我就纳了闷了，难道现代的计算机程序不是将大量时间消耗在字符串与文本的处理上吗？）</span></p>
<p>&nbsp;</p>
<p><span>C++</span><span>：</span></p>
<p><span>学过<span>C</span>语言，再学<span>C++</span>，先看这本《<span>C++ Primer</span>》的缩写版：</span></p>
<p><span>《<span>Essential C++</span>》</span></p>
<p><span>对<span>C++</span>有个入门了解，再看</span></p>
<p><span>《<span>C++ Common Knowledge: Essential Intermediate Programming</span>》</span></p>
<p><span>就不会有什么重要的知识点完全不知所措了，接下来是</span></p>
<p><span>《<span>The C++ Standard Library : A Tutorial and Reference</span>》</span></p>
<p><span>标准库，当然主要是标准模板库的标准学习参考手册，然后最好平时边写程序边参悟。</span></p>
<p><span>《<span>Effective C++</span>》等</span></p>
<p><span>我是说书名以形容词<span> + C++</span>的那些书，计有七八本，慢慢看吧，罗马不是一日建成的。</span></p>
<p><span>(</span><span>《<span>Essential C++</span>》、《<span>Effective C++</span>》、《<span>More Effective C++</span>》、《<span>Accelerated C++</span>》、《<span>Effective STL</span>》、《<span>Exceptional C++</span>》、《<span>More Exceptional C++</span>》、《<span>Imperfect C++</span>》，虽然书名格式相似，但每一本都绝非马虎之作。<span>)</span></span></p>
<p>&nbsp;</p>
<p><span>谁说<span>C++</span>程序比<span>C</span>程序要慢？那就请看下面：</span></p>
<p><span>《<span>The Design and Evolution of C++</span>》</span></p>
<p><span>知其过去才能知其未来，才能应用。</span></p>
<p><span>《<span>Inside the C++ Object Model</span>》</span></p>
<p><span>揭露<span>C++</span>的编译器模型。</span></p>
<p><span>《<span>Efficient C++ Performance Programming Techniques</span>》</span></p>
<p><span>当算法优化已到极致，在运用汇编之前，最后还可看看此书，有时高级和低阶都能做成相同的事情。</span></p>
<p>&nbsp;</p>
<p><span>还有两本特别的书：</span></p>
<p><span>《<span>Modern C++ Design : Generic Programming and Design Patterns Applied</span>》</span></p>
<p><span>作者想把设计模式和泛型编程结合起来，并写了个尝试提供一切的<span>Loki</span>库来实作<span>,</span>不过其观点并未得到<span>C++</span>社区的普遍响应。尽管如此，本书仍称得上思想前沿性与技术实用性结合的典范。</span></p>
<p>&nbsp;</p>
<p><span>《<span>C++ Template Metaprogramming</span>》</span></p>
<p><span>把编译器当作计算器？本书介绍了<span>Boost</span>库的<span>MPL</span>模板元编程库。当然提到<span>Boost</span>库，对于游戏程序员不能不提到其中的<span>Graph</span>库，有《<span>The Boost Graph Library</span>》一书可看。还有其中<span>Python</span>库，号称国内首款商业三维图形引擎的起点引擎就用了<span>Boost</span>－<span>Python</span>库。说实话我觉得起点引擎还是蛮不错的，那个自制的三维编辑器虽然界面简陋，但功能还算蛮完善，给游戏学院用作教学内容也不错。另有一个号称中国首款自主研发的全套网游解决方案。我看到它那个三维编辑器，心想这不就是国外一个叫<span>freeworld3D</span>的编辑器吗？虽然有点偏门，但我以前还较劲尝试破解过呢。还把英文界面汉化了，大概用<span>exescope</span>这样的资源修改软件就能搞定吧。我又心想为什么要找<span>freeworld3D</span>这个功能并不太强大的编辑器呢？仅仅是因为它便宜到几十美金？它唯一特别一点的地方就是支持导出<span>OGRE</span>图形引擎的场景格式，这样一想不由得使人对它图形引擎的&#8220;自主&#8221;性也产生怀疑了。这样的&#8220;自主&#8221;研发真让人汗颜，只要中国还没封<span>sourceforge</span>这个网站（据说以前和<span>freeBSD</span>网站一起被封过？），国人就能&#8220;自主&#8221;研发。</span></p>
<p>&nbsp;</p>
<p><span>有人还会推荐《<span>C++ Primer</span>》《<span>Thinking in C++</span>》《<span>The C++ Programming Language</span>》等书吧，诚然这些书也很好，但我总觉得它们太大部头了。还不如多花点时间看看国外好的源代码。</span></p>
<p>&nbsp;</p>
<p><span>Windows</span><span>编程</span></p>
<p><span>Operating System Concepts</span><span>第五版</span></p>
<p><span>国内有些操作系统的教程其实就是它的缩写版。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Windows 95 System Programming Secrets</span>》</span></p>
<p><span>深入剖析了<span>Windows</span>操作系统的种种种种，有人爱看《<span>Linux</span>内核完全注释》，有人爱看《自己动手写操作系统》这样煽情的书，但我想作为商业的操作系统，把<span>Windows</span>内核剖析到这地步也高山仰止了。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Programming Applications for Microsoft Windows</span>》第四版</span></p>
<p><span>先进程线程，再虚存管理，再动态链接库，最多讲到消息机制。作者在序言中说：&#8220;我不讲什么<span>ActiveX, COM</span>等等，因为当你了解了这些基础后，那些东西很快就会明白！&#8221;可以作为《<span>Programming Windows</span>》的先修课。</span></p>
<p>&nbsp;</p>
<p><span>计算机体系：</span></p>
<p><span>《<span>Computer Systems : A Programmer</span>&#8217;<span>s Perspective</span>》</span></p>
<p><span>和《<span>The Art of Computer Programming</span>》在我心中是计算机史上两本称得上伟大的书，计算机组成原理，操作系统，汇编，编译原理，计算机网络等等课程汇成这本千页的大书，因为计算机在作者眼中就是一个整体。</span></p>
<p>&nbsp;</p>
<p><span>开源阅读：</span></p>
<p><span>《<span>Code Reading : The Open Source Perspective</span>》</span></p>
<p><span>张大千临摹了几百张明代石涛的山水，画出的画以假乱真，后来他去敦煌潜心临摹几年，回来画风大变，终成大家。程序员其实有<span>40%</span>的时间是在读别人的源代码，<st1:personname w:st="on" productid="侯捷">侯捷</st1:personname>先生说：&#8220;源码面前，了无秘密&#8221;，又说&#8220;天下大事，必作于细&#8221;，可以与他的《上穷碧落下黄泉，源码追踪经验谈》参看。</span></p>
<p>&nbsp;</p>
<p><span>MFC:</span></p>
<p><span>《深入浅出<span>MFC</span>》</span></p>
<p><span>我实在以为没有看过<st1:personname w:st="on" productid="侯捷">侯捷</st1:personname>先生的《深入浅出<span>MFC</span>》的人多半不会懂得<span>MFC</span>编程。其实我是打算用一年多的时间写一个给游戏美工用的三维编辑器，顺便作为毕业设计。图形库就用<span>MFC</span>吧，反正也没得选择。如果要用<span>wxWidgets</span>无非是猎奇而已，还不是<span>MFC</span>的翻版，当然它跨平台了。就象阻击手对自己枪械的零件了如指掌一样，要想用<span>MFC</span>写出非玩具程序的人一定要了解其内部构造。还有一本书叫《<span>MFC</span>深入浅出》，并不是同一本。</span></p>
<p>&nbsp;</p>
<p><span>IDE:</span></p>
<p><span>《<span>Microsoft Visual Studio 2005 Unleashed</span>》</span></p>
<p><span>工欲善其事，必先利其器。当然我认为与其用形如<span>Source Insight</span>、<span>Slick Edit</span>、<span>Code Visualizer</span>之类的代码阅读器、图形化工具，还不如用自己的大脑。但如果你嫌打源代码慢的话，可以用<span>Visual AssistX</span>。如果嫌老是写重复相似的代码的话，可以用<span>Code Smith</span>。单元测试可以用<span>CppUnit</span>，<span>Boost</span>库中的测试框架也不错。有心情可以吧<span>Visual Studio</span>外接<span>Intel</span>的<span>Compiler</span>，内嵌<span>STLport</span>，但不是大工程，性能分析没必要动不动就用下<span>VTune</span>吧。</span></p>
<p>&nbsp;</p>
<p><span>程序员之路：</span></p>
<p><span>《游戏之旅——我的编程感悟》</span></p>
<p><span>云风大哥。在我心目中游戏程序员国外首推卡马克，国内首推云风。也许过两年我会到网易当云风大哥的助理程序员吧。<span>It</span>&#8217;<span>s my dream.</span>（<span>^-^</span>）他写这本书的时候本着只有透彻理解的东西才写出来，因此内容不会很酷新，但是相信我，每读一遍都有新的收获，主要还不是知识上的，因为知识是学无止境的，授人以鱼不如授人以渔，精神上的启迪才是长久的。诚如经典游戏《仙剑奇侠传》的主力程序员兼美术指导姚壮宪（人称姚仙）在序言中所说的&#8220;云风得到的只是一些稿费，而整个中国民族游戏产业得到的将是一次知识的推动&#8221;，此言不虚矣。</span></p>
<p>&nbsp;</p>
<p><span>《编程高手箴言》</span></p>
<p><span>梁肇新是豪杰超级解霸的作者，本来每个合格的程序员（<span>Programmer , </span>而非<span>Coder</span>）都应该掌握的东西，现在变成了编程高手的独家箴言。不知是作者的幸运还是中国<span>IT</span>业的悲哀。知识点还是讲得蛮多的，不过对<span>MFC</span>的地位颇有微词。我实在认为<span>MFC</span>的名声就是那些不懂得用它的人搞臭的。不过作者的牢骚也情有可原，每个具有创造力的程序员都应该不太喜欢<span>framework</span>。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Masters of DOOM: How Two Guys Created an Empire and Transformed Pop Culture</span>》中文名《<span>DOOM</span>启世录》</span></p>
<p><span>卡马克，罗洛斯，这些游戏史上如雷贯耳的名字。（现在卡马克已专注于火箭制造上，罗洛斯则携妻回乡隐居）要不是没上过大学的卡马克和图形学大师亚伯拉罕的功勋，可能到现在游戏中还不知三维为何物。勿庸置疑，在计算机界历史是英雄们所推动的。这本书真实的记录了这些尘世英雄的所为所思。</span></p>
<p>&nbsp;</p>
<p><span>作为程序员的我对这几本策划与美工的书也产生了浓厚兴趣，以前搞过一两年的<span>3DS MAX</span>插件编程，觉得用<span>maxscript</span>还是好过<span>MaxSDK</span>，毕竟游戏开发中所多的是模型场景数据的导入导出，大可不必大动干戈。</span></p>
<p>&nbsp;</p>
<p><span>策划：</span></p>
<p><span>《<span>Creating Emotion in Games : The Craft and Art of Emotioneering</span>》</span></p>
<p><span>在壮丽煊目的宏伟三维世界背后，在残酷的杀戮，动人心魄的情节背后，我们还需要什么来抓住玩家的心？答对了，就是<span>emotion.</span>真正打动人心的，才是深入骨髓的。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Ultimate Game Design : Building Game Worlds</span>》</span></p>
<p><span>从名字可以看出，写给关卡设计师的，特别是讲室外自然场景的构建颇有可取之处。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Developing Online Games : An Insider</span>&#8217;<span>s Guide</span>》</span></p>
<p><span>就象名为反模式的书讲软件团队运营一样，这本书讲商业运作多过技术。一个历经艰难，现在盛大的游戏程序员，翻译了这本书。</span></p>
<p>&nbsp;</p>
<p><span>美工：</span></p>
<p><span>《<span>Digital Cinematography &amp; Directing</span>》</span></p>
<p><span>数字摄影导演术，每当你在<span>3DS MAX</span>或者<span>Maya</span>等三维创作软件中摆放摄影机，设计其运动轨迹时，你可曾想过你也站在导演的位置上了？</span></p>
<p>&nbsp;</p>
<p><span>《<span>The Animator</span>&#8217;<span>s Survival Kit</span>》</span></p>
<p><span>看着这本讲卡通角色运动规律的书，一边产生温习《猫和老鼠》的念头，一边继续对前不久新闻联播中关于中国产生了某计算机自动卡通动画生成软件报道的蔑视，这条报道称此举可大大加快中国卡通动画的产量。我且不从技术上探讨其是否是在放卫星（其实我知道得很清楚，前文已表，本人搞过一两年的卡通动画辅助软件编程），但计算机机械生成的动画怎可代替人类充满灵性的创作？</span></p>
<p>&nbsp;</p>
<p><span>《<span>The Dark Side of Game Texturing</span>》</span></p>
<p><span>用<span>Photoshop</span>制作材质贴图，还真有些学问。</span></p>
<p>&nbsp;</p>
<p><span>三维图形学：</span></p>
<p><span>搞三维图形学首先还是要扎扎实实的先看解析几何、线性代数、计算几何的教材，后面的习题一个都不能少。国内数学书还是蛮好的。苏步青大师的《计算几何》称得上具有世界级水准，可惜中国<span>CAD</span>的宏图被盗版给击垮了。现在是我们接过接力棒的时候了。<span>It</span>&#8217;<span>s time!</span></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span>《<span>Computer Graphics Geometrical Tools</span>》<span> </span></span></p>
<p><span>《计算机图形学几何工具算法详解》算法很多，纰漏处也不少。</span></p>
<p>&nbsp;</p>
<p><span>《<span>3D Math Primer for Graphics and Game Development</span>》</span></p>
<p><span>浅易，可作为三维数学的&#8220;速食&#8220;。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Mathematics for 3D Game Programming &amp; Computer Graphics</span>》第二版</span></p>
<p><span>比上面那本深入一些，证明推理的数学气也浓一些，可作为专业的数学书与编程实践一个过渡的桥梁吧。内容涉猎也广，射线追踪，光照计算，可视裁剪，碰撞检测，多边形技术，阴影算法，刚体物理，流体水波，数值方法，曲线曲面，还真够丰富。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Vector Game Math Processors</span>》</span></p>
<p><span>想学<span>MMX,SSE</span>吗，那就看它吧，不过从基础讲起的，要耐心哦。</span></p>
<p>&nbsp;</p>
<p><span>&nbsp;DirectX:</span></p>
<p><span>《<span>Introduction to 3D Game Programming with DirectX 9.0</span>》</span></p>
<p><span>DirectX</span><span>入门的龙书，作者自己写的简单示例框架，后面我干脆用<span>State</span>模式，把所有例子绑到一块儿去了。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Beginning Direct3D Game Programming</span>》</span></p>
<p><span>作者取得律师学位后变成了游戏程序员，真是怪也哉。本书虽定位为入门级书，内容颇有独特可取之处。它用到的示例框架是<span>DXSDK Sample Framework</span>，而不是现在通行的<span>DXUT</span>。要想编译有两种办法吧，一是自己改写成用<span>DXUT</span>的。二是找旧的<span>Sample Framework</span>。我又懒得为了一个示例框架下载整个早期版本的<span>DirectX</span>，后面在<span>Nvidia SDK 9.5</span>中发现了。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Advanced Animation with DirectX</span>》</span></p>
<p><span>DirectX</span><span>高级动画技术。骨骼系统，渐变关键帧动画，偶人技术，表情变形，粒子系统，布料柔体，动态材质，不一而足。我常常在想，从三维创作软件导出的种种效果，变成一堆<span>text</span>或<span>binary</span>，先加密压缩打包再解包解压解密，再用游戏程序重建一个<span>Lite</span>动画系统，游戏程序员也真是辛苦。</span></p>
<p>&nbsp;</p>
<p><span>OpenGL:</span></p>
<p><span>《<span>NeHe OpenGL Tutorials</span>》</span></p>
<p><span>虽是网络教程，不比正式的书逊，本来学<span>OpenGL</span>就不过是看百来条<span>C</span>函数文档的工夫吧<span>,</span>如果图形学基础知识扎实的话。</span></p>
<p>&nbsp;</p>
<p><span>《<span>OpenGL Shading Language</span>》</span></p>
<p><span>OpenGL</span><span>支持最新显卡技术要靠修修补补的插件扩展，所以还要配合</span></p>
<p><span>《<span>Nvidia OpenGL Extension Specifications</span>》</span></p>
<p><span>来看为上。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Focus on 3D Models</span>》</span></p>
<p><span>《<span>Focus on 3D Terrain Programming</span>》</span></p>
<p><span>《<span>Focus on Curves and Surfaces</span>》<span> </span></span></p>
<p><span>顾名思义，三本专论，虽然都很不深，但要对未知三维模型格式作反向工程前，研读<span>Geomipmapping</span>地形算法论文前，<span>CAD</span>前，还是要看看它们为上，如果没从别处得过到基础的话。</span></p>
<p>&nbsp;</p>
<p><span>脚本：</span></p>
<p><span>先看</span></p>
<p><span>《<span>Game Scripting Mastery</span>》<span> </span></span></p>
<p><span>等自己了解了虚拟机的构造，可以设计出简单的脚本解释执行系统了。</span></p>
<p><span>再去查<span>Python , Lua </span>，<span>Ruby</span>的手册吧，会事半半功倍倍的。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Programming Role Playing Games with DirectX 8.0</span>》</span></p>
<p><span>一边教学一边用<span>DirectX</span>写出了一个<span>GameCore</span>库，初具引擎稚形。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Isometric Game Programming with DirectX 7.0</span>》</span></p>
<p><span>三维也是建立在二维的基础上，这就是这本书现在还值得看的原因。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Visual C++</span>网络游戏建模与实现》</span></p>
<p><span>联众的程序员写的，功力很扎实，讲棋牌类游戏编程，特别讲了<span>UML</span>建模和<span>Rotional Rose</span>。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Object-Oriented Game Development</span>》</span></p>
<p><span>套用某人的话：&#8220;<span>I like this book.</span>&#8221;</span></p>
<p>&nbsp;</p>
<p><span>Shader:</span></p>
<p><span>要入门可先看</span></p>
<p><span>《<span>Shaders for Game Programmers and Artists</span>》</span></p>
<p><span>讲在<span>RenderMonkey</span>中用<span>HLSL</span>高级着色语言写<span>Shader.</span></span></p>
<p>&nbsp;</p>
<p><span>再看</span></p>
<p><span>《<span>Direct3D ShaderX : Vertex and Pixel Shander Tips and Tricks</span>》</span></p>
<p><span>用汇编着色语言，纯银赤金。</span></p>
<p>&nbsp;</p>
<p><span>三大宝库：</span></p>
<p><span>《<span>Game Programming Gems</span>》</span></p>
<p><span>我只见到<span>1-6</span>本，据说第<span>7</span>、<span>8</span>本也出来了？附带的源代码常有<span>bug</span>，不过瑕不掩瑜，这套世界顶级游戏程序员每年一度的技术文集，涉及游戏开发的各个方面，我觉得富有开发经验的人更能在其中找到共鸣。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Graphics Gems</span>》全五本</span></p>
<p><span>图形学编程<span>Bible</span>，看了这套书你会明白计算机领域的科学家和工程师区别之所在。科学家总是说，这个东西在理论上可行。工程师会说，要使问题在<span>logN</span>的时限内解决我只能忍痛割爱，舍繁趋简。</span></p>
<p>&nbsp;</p>
<p><span>《<span>GPU Gems</span>》出了二本</span></p>
<p><span>Nvidia</span><span>公司召集图形学<span>Gurus</span>写的，等到看懂的那一天，我也有心情跑去<span>Siggraph</span>国际图形学大会上投文章碰运气。</span></p>
<p>&nbsp;</p>
<p><span>游戏引擎编程：</span></p>
<p><span>《<span>3D Game Engine Programming</span>》</span></p>
<p><span>是<span>ZFXEngine</span>引擎的设计思路阐释，很平实，冇太多惊喜。</span></p>
<p>&nbsp;</p>
<p><span>《<span>3D Game Engine Design</span>》</span></p>
<p><span>数学物理的理论知识讲解较多，本来这样就够了，还能期待更多吗？</span></p>
<p>&nbsp;</p>
<p><span>人工智能：</span></p>
<p><span>《<span>AI Techniques for Game Programming</span>》</span></p>
<p><span>讲遗传算法，人工神经网络，主要用到位数组，图算法。书的原型是根据作者发表到<span>GameDev.net</span>论坛上的内容整理出来的，还比较切中实际。</span></p>
<p>&nbsp;</p>
<p><span>《<span>AI Game Programming Wisdom</span>》</span></p>
<p><span>相当于<span>AI</span>编程的<span>Gems</span>。</span></p>
<p>&nbsp;</p>
<p><span>《<span>PC</span>游戏编程<span>(</span>人机博弈<span>)</span>》</span></p>
<p><span>以象棋程序为蓝本，介绍了很多种搜索算法，除了常见的极大极小值算法及其改进<span>--</span>负极大值算法，还有深度优先搜索以外。更提供了多种改进算法，如：<span>Alpha-Beta,Fail-soft alpha-beta,Aspiration Search, Minimal Window Search,Zobrist Hash,Iterative Deepening,History Heuristic,Killer Heuristic,SSS*,DUAL*,MFD and more.</span>琳琅满目，实属难得。</span></p>
<p>&nbsp;</p>
<p><span>反外挂：</span></p>
<p><span>《加密与解密<span>(</span>第二版<span>)</span>》 看雪论坛站长 段钢</span></p>
<p><span>破解序列号与反外挂有关系么？不过，世上哪两件事情之间又没有关系呢？</span></p>
<p>&nbsp;</p>
<p><span>《<span>UML Distilled</span>》 <span>Martin Fowler</span></span></p>
<p><span>很多人直到看了这本书才真正学懂<span>UML</span>。</span></p>
<p><span>Martin Fowler</span><span>是真正的大师<span>,</span>从早期的分析模式<span>,</span>到这本<span>UML</span>精粹<span>,</span>革命性的重构都是他提出的<span>,</span>后来又写了企业模式一书。现在领导一个软件开发咨询公司，去年<span>JavaOne</span>中国大会他作为专家来华了吧。个人网站：<span>MartinFowler.com</span></span></p>
<p>&nbsp;</p>
<p><span>设计模式三剑客：</span></p>
<p><span>《<span>Design Patterns Elements of Reusable Object-Oriented Software</span>》</span></p>
<p><span>《<span>Design Patterns Explained</span>》</span></p>
<p><span>《<span>Head First Design Patterns</span>》<span>&nbsp;</span></span></p>
<p>&nbsp;</p>
<p><span>重构三板斧：</span></p>
<p><span>《<span>Refactoring : Improving the Design of Existing Code</span>》</span></p>
<p><span>《<span>Refactoring to Patterns</span>》</span></p>
<p><span>《<span>Refactoring Workbook</span>》</span></p>
<p>&nbsp;</p>
<p><span>软件工程<span>:</span></span></p>
<p><span>《<span>Extreme Programming Explained : Embrace Change</span>》第二版</span></p>
<p><span>其中<span>Simplicity</span>的<span>Value</span>真是振聋发聩，这就是我什么都喜欢轻量级的原因。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Agile Software Development Principles,Patterns,and Practices</span>》</span></p>
<p><span>敏捷真是炒得够火的，连企业都有敏捷一说，不过大师是不会这么<span>advertising</span>的。</span></p>
<p>&nbsp;</p>
<p><span>《<span>Code Complete</span>》第二版</span></p>
<p><span>名著。</span></p>
<p>&nbsp;</p>
<p><span>数学：</span></p>
<p><span>《数学，确定性的丧失》<span>M.</span>克莱因</span></p>
<p><span>原来数学也只不过是人类的发明与臆造，用不着供入神殿，想起历史上那么多不食人间烟火的科学家（多半是数学家），自以为发现了宇宙运作的奥秘，是时候走下神坛了。</span></p>
<p>&nbsp;</p>
<p><span>物理：</span></p>
<p><span>《普通物理学》第一册<span> += </span>《<span>Physics for Game Developers</span>》</span></p>
<p><span>物理我想就到此为此吧，再复杂我可要用<span>Newton Engine,ODE</span>了，等待物理卡<span>PPU</span>普及的那天，就可充分发挥<span>PhysX</span>的功效了，看过最新的《细胞分裂》游戏<span>Demo</span>演示，成千上万个<span>Box</span>疯狂<span>Collide</span>，骨灰级玩家该一边摸钱包一边流口水了。</span></p>
<p>&nbsp;</p>
<p><span>二、开源代码：</span></p>
<p><span>Irrlicht</span></p>
<p><span>著名的鬼火引擎，从两年前第一眼看到它，这个轻量级的三维图形引擎，就喜欢上了它。源代码优雅，高效，且不故弄玄虚。值得每个<span>C++</span>程序员一读，并不限于图形编程者。它的周边中也有不少轻量级的东西。如<span>Lightfeather</span>扩展引擎，<span>ICE</span>、<span>IrrlichtRPG</span>、<span>IrrWizard.</span>还有<span>IrrEdit</span>、<span>IrrKlang</span>、<span>IrrXML</span>可用。（可能是为了效率原因，很多开源作者往往喜欢自己写<span>XML</span>解析库，如以上的<span>IrrXML</span>库<span>,</span>即使有现成的<span>tinyXML</span>库可用。这真会让<span>tomcat</span>里面塞<span>Axis</span>，<span>Axis</span>里面塞<span>JUDDI</span>，弄得像俄罗斯套娃玩具的<span>Java Web Service Coder</span>们汗颜。）</span></p>
<p>&nbsp;</p>
<p><span>OGRE</span></p>
<p><span>排名第一的开源图形引擎，当然规模是很大的，周边也很多。除了以<span>C#</span>写就的<span>OgreStudio </span>，<span>ofusion</span>嵌入<span>3DS MAX</span>作为<span>WYSWYG</span>式的三维编辑器也是棒棒的，特别是其几个场景、地形插件值得研究。以至于《<span>Pro OGRE 3D Programming</span>》一书专论其用法。搜狐的《天龙八部》游戏就是以其作为图形引擎，当然还另外开发了引擎插块啦。我早知道<span>OGRE</span>开发组中有一个中国人谢程序员，他以前做了很多年的传统软件编程。有一次天龙八部游戏的图形模块的出错信息中包含了一串某程序员的工作目录，有一个文件夹名即是谢程序员的英文名，我据此推断谢程序员即是搜狐北京的主程。看来中国对开源事业还是有所贡献的嘛，王开源哥哥的努力看来不会白费！（<span>^-^</span>）不过我侦测的手法也有些像网站数据库爆库了，非君子之所为作。</span></p>
<p>&nbsp;</p>
<p><span>RakNet</span></p>
<p><span>基于<span>UDI</span>的网络库，竟还支持声音传输，以后和<span>OpenVision</span>结合起来做个视聊程序试试。</span></p>
<p><span>&nbsp;</span></p>
<p><span>Blender</span></p>
<p><span>声誉最盛的开源三维动画软件，竟还带一个游戏引擎。虽然操作以快捷键驱动，也就是说要背上百来个快捷键才能熟练使用。但是作为从商业代码变为开源之作，威胁三维商业巨头的轻骑兵，历经十年锤炼，代码达百万行，此代码只应天上有，人间哪得几回看，怎可不作为长期的源码参考？</span></p>
<p>&nbsp;</p>
<p><span>风魂</span></p>
<p><span>二维图形库。云风大哥的成名之作。虽然不代表其最高水平（最高水平作为商业代码保存在广州网易互动的<span>SVN</span>里呢），但是也可以一仰风采了。</span></p>
<p>&nbsp;</p>
<p><span>圣剑英雄传</span></p>
<p><span>二维<span>RPG</span>。几个作者已成为成都锦天的主力程序员。锦天的老总从一百万发家，三年时间身价过亿，也是一代枭雄了。这份代码作为几年前的学生作品也算可以了，因为一个工程讲究的是四平八稳，并不一定要哪个模块多么出彩。反正我是没有时间写这么一个东东，连个美工都找不到，只能整天想着破解别人的资源（<span>^-^</span>）。</span></p>
<p>&nbsp;</p>
<p><span>Boost</span></p>
<p><span>C++</span><span>准标准库，我想更多的时候可以参考学习其源代码。</span></p>
<p>&nbsp;</p>
<p><span>Yake</span></p>
<p><span>我遇到的最好的轻量级游戏框架了。在以前把一个工程中的图形引擎从<span>Irrlicht</span>换成<span>OGRE</span>的尝试中，遇到了它。<span>OGRE</span>的周边工程在我看来都很庸肿，没有完善文档的情况下看起来和<span>Linux</span>内核差不多。不过这个<span>Yake</span>引擎倒是很喜欢。它以一个<span>FSM</span>有限状态机作为实时程序的调度核心，然后每个模块：物理、图形、网络、脚本、<span>GUI</span>、输入等等都提供一个接口，接口之下再提供到每种具体开源引擎的接口，然后再接具体引擎。通过这样层层抽象，此时你是接<span>Newton Engine,ODE</span>还是<span>PysX</span>都可以；是接<span>OGRE,Crystal Space</span>还是<span>Irrlicht</span>都可以；是接<span>RakNet</span>还是<span>LibCurl</span>都可以；是接<span>Python</span>，<span>Lua</span>还是<span>Ruby</span>都可以，是接<span>CEGUI</span>还是<span>others</span>，是接<span>OIS</span>还是<span>others</span>（呵呵<span>,</span>记不起来<span>others</span>）都可以。所以<span>Yake</span>本质上不是<span>OGRE</span>的周边。虽然用<span>Neoengine</span>的人都倒向了它，但是现在版本还很早。特别是我认为，学习研究时一定要有这种抽象之抽象，接口之接口的东西把思维从具体的绑定打开，而开发时抽象要有限度的，就像蔡学镛在《<span>Java</span>夜未眠》中讲的，面向对象用得过滥也会得<span>OOOO</span>症<span>(</span>面向对象过敏强迫症<span>)</span>。</span></p>
<p>&nbsp;</p>
<p><span>Quake Doom</span><span>系列</span></p>
<p><span>据说很经典，卡马克这种开源的黑客精神就值得赞许。把商业源代码放出来，走自己的创新之路，让别人追去吧。不过<span>Quake</span>与<span>Unreal</span>引擎的三维编辑器是现在所有编辑器的鼻祖，看来要好好看看了。</span></p>
<p>&nbsp;</p>
<p><span>Nvidia SDK 9.X</span></p>
<p><span>三维图形编程的大宝库，这些<span>Diret3D</span>与<span>OpenGL</span>的示例程序都是用来展示其最新的显卡技术的。硬件厂商往往对软件产品不甚在意，源代码给你看<span>,</span>东西给你用去吧，学完了还得买我的硬件。<span>Intel</span>的编译器，<span>PhysX</span>物理引擎大概也都是这样。<span>Havok</span>会把它的<span>Havok</span>物理引擎免费给别人用吗？别说试用版，连个<span>Demo</span>都看不到。所以这套<span>SDK</span>的内容可比<span>MS DirectX SDK</span>里面那些入门级的示例酷多了，反正我是如获至宝，三月不知愁滋味。不过显卡要<span>so-so</span>哦。我的<span>GeForce 6600</span>有两三个跑不过去<span>,</span>差强人意。</span></p>
<p>&nbsp;</p>
<p><span>三、网站：</span></p>
<p><span>www.CSDN.net</span></p>
<p><span>程序员大本营吧，软文与&#8220;新技术秀&#8221;讨厌了点，<span>blog</span>和社区是精华之所在。</span></p>
<p>&nbsp;</p>
<p><span>www.GameRes.com</span></p>
<p><span>游戏程序员基地，文档库中还有点东西。投稿的接收者<span>Seabug</span>与圣剑英雄传的主程<span>Seabug</span>会是同一个人吗？一个在成都锦天担当技术重担的高手还有时间维护网站吗？我不得而知。</span></p>
<p>&nbsp;</p>
<p><span>&#8220;何苦做游戏&#8221;网站</span></p>
<p><span>名字很个性，站长也是历尽几年前产业发展初期的艰难才出此名字。</span></p>
<p>&nbsp;</p>
<p><span>www.66rpg.com</span></p>
<p><span>二维游戏图片资源很多，站长柳柳主推的<span>RPGMaker </span>软件也可以玩一玩吧，但对于专业开发者来说不可当真。</span></p>
<p>&nbsp;</p>
<p><span>www.GameDev.net</span></p>
<p><span>论坛中有不少热心的国外高手在活动。</span></p>
<p>&nbsp;</p>
<p><span>www.SourceForge.net</span></p>
<p><span>不用说了，世界最大的开源代码库，入金山怎可空手而返？看到国外那些学生项目动不动就像模像样的。（<span>DirectX</span>的稚形就是英国的学生项目，在学校还被判为不合格。）</span></p>
<p>&nbsp;</p>
<p><span>www.koders.com</span></p>
<p><span>源代码搜索引擎<span>,</span>支持正则表达式<span>,google Lab</span>中也有。当你某种功能写不出来时<span>,</span>可以看一下开源代码怎么写的<span>,</span>当然不过是仅供参考<span>,</span>开源代码未必都有产品级的强度。说到<span>google,</span>可看《<span>Google Power Tools Bible</span>》一书，你会发现，<span>google</span>的众多产品原来也有这么多使用门道。</span></p>
<p>&nbsp;</p>
<p><span>这篇小文足足写了一天半的时间，不由得使我对侯捷一样的技术作家长期伏案辛勤劳作深深敬佩了。看来对于书籍或者软件，都应该尊重作者或者<span>programmer</span>的才智劳动</span></p>
<img src ="http://www.cppblog.com/Walker/aggbug/81443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-29 15:07 <a href="http://www.cppblog.com/Walker/articles/81443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转）C、C++ 时间 </title><link>http://www.cppblog.com/Walker/articles/81194.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Mon, 27 Apr 2009 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/81194.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/81194.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/81194.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/81194.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/81194.html</trackback:ping><description><![CDATA[<h1 class=postTitle><a class=postTitle2 id=AjaxHolder_ctl01_TitleUrl href="http://www.cnblogs.com/Kane_zzt/archive/2009/04/23/1442387.html"><font color=#bd1717>C++ 时间</font></a> </h1>
<div class=clear></div>
<div class=postBody>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本文从介绍基础概念入手，探讨了在C/C++中对日期和时间操作所用到的数据结构和函数，并对计时、时间的获取、时间的计算和显示格式等方面进行了阐述。本文还通过大量的实例向你展示了time.h头文件中声明的各种函数和数据结构的详细使用方法。&nbsp;&nbsp;</p>
<p>关键字：UTC（世界标准时间），Calendar Time（日历时间），epoch（时间点），clock tick（时钟计时单元）&nbsp;&nbsp;</p>
<p>1．概念&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在C/C++中，对字符串的操作有很多值得注意的问题，同样，C/C++对时间的操作也有许多值得大家注意的地方。最近，在技术群中有很多网友也多次问到 过C++语言中对时间的操作、获取和显示等等的问题。下面，在这篇文章中，笔者将主要介绍在C/C++中时间和日期的使用方法.&nbsp;&nbsp;</p>
<p>通过学习许多C/C++库，你可以有很多操作、使用时间的方法。但在这之前你需要了解一些&#8220;时间&#8221;和&#8220;日期&#8221;的概念，主要有以下几个：&nbsp;&nbsp;</p>
<p>Coordinated Universal Time（UTC）：协调世界时，又称为世界标准时间，也就是大家所熟知的格林威治标准时间（Greenwich Mean Time，GMT）。比如，中国内地的时间与UTC的时差为+8，也就是UTC+8。美国是UTC-5。&nbsp;&nbsp;</p>
<p>Calendar Time：日历时间，是用&#8220;从一个标准时间点到此时的时间经过的秒数&#8221;来表示的时间。这个标准时间点对不同的编译器来说会有所不同，但对一个编译系统来 说，这个标准时间点是不变的，该编译系统中的时间对应的日历时间都通过该标准时间点来衡量，所以可以说日历时间是&#8220;相对时间&#8221;，但是无论你在哪一个时区， 在同一时刻对同一个标准时间点来说，日历时间都是一样的。&nbsp;&nbsp;</p>
<p>epoch：&nbsp;&nbsp;&nbsp; 时间点。时间点在标准C/C++中是一个整数，它用此时的时间和标准时间点相差的秒数（即日历时间）来表示。&nbsp;&nbsp;</p>
<p>clock tick：时钟计时单元（而不把它叫做时钟滴答次数），一个时钟计时单元的时间长短是由CPU控制的。一个clock tick不是CPU的一个时钟周期，而是C/C++的一个基本计时单位。&nbsp;&nbsp;</p>
<p>我们可以使用ANSI标准库中的time.h头文件。这个头文件中定义的时间和日期所使用的方法，无论是在结构定义，还是命名，都具有明显的C语言风格。下面，我将说明在C/C++中怎样使用日期的时间功能。&nbsp;&nbsp;</p>
<p>2． 计时&nbsp;&nbsp;</p>
<p>C/C++中的计时函数是clock()，而与其相关的数据类型是clock_t。在MSDN中，查得对clock函数定义如下：&nbsp;&nbsp;</p>
<p>clock_t clock( void );&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 这 个函数返回从&#8220;开启这个程序进程&#8221;到&#8220;程序中调用clock()函数&#8221;时之间的CPU时钟计时单元（clock tick）数，在MSDN中称之为挂钟时间（wal-clock）。其中clock_t是用来保存时间的数据类型，在time.h文件中，我们可以找到对 它的定义：&nbsp;&nbsp;</p>
<p>#ifndef _CLOCK_T_DEFINED&nbsp;&nbsp;<br>typedef long clock_t;&nbsp;&nbsp;<br>#define _CLOCK_T_DEFINED&nbsp;&nbsp;<br>#endif&nbsp;&nbsp;</p>
<p>很明显，clock_t是一个长整形数。在time.h文件中，还定义了一个常量CLOCKS_PER_SEC，它用来表示一秒钟会有多少个时钟计时单元，其定义如下：&nbsp;&nbsp;</p>
<p>#define CLOCKS_PER_SEC ((clock_t)1000)&nbsp;&nbsp;</p>
<p>可以看到每过千分之一秒（1毫秒），调用clock（）函数返回的值就加1。下面举个例子，你可以使用公式clock()/CLOCKS_PER_SEC来计算一个进程自身的运行时间：&nbsp;&nbsp;</p>
<p>void elapsed_time()&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC);&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>当然，你也可以用clock函数来计算你的机器运行一个循环或者处理其它事件到底花了多少时间：&nbsp;&nbsp;</p>
<p>#include &#8220;stdio.h&#8221;&nbsp;&nbsp;<br>#include &#8220;stdlib.h&#8221;&nbsp;&nbsp;<br>#include &#8220;time.h&#8221;&nbsp;&nbsp;</p>
<p>int main( void )&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>long i = 10000000L;&nbsp;&nbsp;<br>clock_t start, finish;&nbsp;&nbsp;<br>double duration;&nbsp;&nbsp;<br>/* 测量一个事件持续的时间*/&nbsp;&nbsp;<br>printf( "Time to do %ld empty loops is ", i );&nbsp;&nbsp;<br>start = clock();&nbsp;&nbsp;<br>while( i-- ) ;&nbsp;&nbsp;<br>finish = clock();&nbsp;&nbsp;<br>duration = (double)(finish - start) / CLOCKS_PER_SEC;&nbsp;&nbsp;<br>printf( "%f seconds\n", duration );&nbsp;&nbsp;<br>system("pause");&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>在笔者的机器上，运行结果如下：&nbsp;&nbsp;</p>
<p>Time to do 10000000 empty loops is 0.03000 seconds&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 上面我们看到时钟计时单元的长度为1毫秒，那么计时的精度也为1毫秒，那么我们可不可以通过改变CLOCKS_PER_SEC的定义，通过把它定义的大一些，从而使计时精度更高呢？通过尝试，你会发现这样是不行的。在标准C/C++中，最小的计时单位是一毫秒。&nbsp;&nbsp;</p>
<p>3．与日期和时间相关的数据结构&nbsp;&nbsp;</p>
<p>在标准C/C++中，我们可通过tm结构来获得日期和时间，tm结构在time.h中的定义如下：&nbsp;&nbsp;</p>
<p>#ifndef _TM_DEFINED&nbsp;&nbsp;<br>struct tm {&nbsp;&nbsp;<br>int tm_sec; /* 秒 &#8211; 取值区间为[0,59] */&nbsp;&nbsp;<br>int tm_min; /* 分 - 取值区间为[0,59] */&nbsp;&nbsp;<br>int tm_hour; /* 时 - 取值区间为[0,23] */&nbsp;&nbsp;<br>int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */&nbsp;&nbsp;<br>int tm_mon; /* 月份（从一月开始，0代表一月） - 取值区间为[0,11] */&nbsp;&nbsp;<br>int tm_year; /* 年份，其值等于实际年份减去1900 */&nbsp;&nbsp;<br>int tm_wday; /* 星期 &#8211; 取值区间为[0,6]，其中0代表星期天，1代表星期一，以此类推 */&nbsp;&nbsp;<br>int tm_yday; /* 从每年的1月1日开始的天数 &#8211; 取值区间为[0,365]，其中0代表1月1日，1代表1月2日，以此类推 */&nbsp;&nbsp;<br>int tm_isdst; /* 夏令时标识符，实行夏令时的时候，tm_isdst为正。不实行夏令时的进候，tm_isdst为0；不了解情况时，tm_isdst()为负。*/&nbsp;&nbsp;<br>};&nbsp;&nbsp;<br>#define _TM_DEFINED&nbsp;&nbsp;<br>#endif&nbsp;&nbsp;</p>
<p>ANSI C标准称使用tm结构的这种时间表示为分解时间(broken-down time)。&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;而日历时间（Calendar Time）是通过time_t数据类型来表示的，用time_t表示的时间（日历时间）是从一个时间点（例如：1970年1月1日0时0分0秒）到此时的秒数。在time.h中，我们也可以看到time_t是一个长整型数：&nbsp;&nbsp;</p>
<p>#ifndef _TIME_T_DEFINED&nbsp;&nbsp;<br>typedef long time_t; /* 时间值 */&nbsp;&nbsp;<br>#define _TIME_T_DEFINED /* 避免重复定义 time_t */&nbsp;&nbsp;<br>#endif&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 大 家可能会产生疑问：既然time_t实际上是长整型，到未来的某一天，从一个时间点（一般是1970年1月1日0时0分0秒）到那时的秒数（即日历时间） 超出了长整形所能表示的数的范围怎么办？对time_t数据类型的值来说，它所表示的时间不能晚于2038年1月18日19时14分07秒。为了能够表示 更久远的时间，一些编译器厂商引入了64位甚至更长的整形数来保存日历时间。比如微软在Visual C++中采用了__time64_t数据类型来保存日历时间，并通过_time64()函数来获得日历时间（而不是通过使用32位字的time()函 数），这样就可以通过该数据类型保存3001年1月1日0时0分0秒（不包括该时间点）之前的时间。&nbsp;&nbsp;</p>
<p>在time.h头文件中，我们还可以看到一些函数，它们都是以time_t为参数类型或返回值类型的函数：&nbsp;&nbsp;</p>
<p>double difftime(time_t time1, time_t time0);&nbsp;&nbsp;<br>time_t mktime(struct tm * timeptr);&nbsp;&nbsp;<br>time_t time(time_t * timer);&nbsp;&nbsp;<br>char * asctime(const struct tm * timeptr);&nbsp;&nbsp;<br>char * ctime(const time_t *timer);&nbsp;&nbsp;</p>
<p>此外，time.h还提供了两种不同的函数将日历时间（一个用time_t表示的整数）转换为我们平时看到的把年月日时分秒分开显示的时间格式tm：&nbsp;&nbsp;</p>
<p>struct tm * gmtime(const time_t *timer);&nbsp;&nbsp;<br>struct tm * localtime(const time_t * timer);&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通 过查阅MSDN，我们可以知道Microsoft C/C++ 7.0中时间点的值（time_t对象的值）是从1899年12月31日0时0分0秒到该时间点所经过的秒数，而其它各种版本的Microsoft C/C++和所有不同版本的Visual C++都是计算的从1970年1月1日0时0分0秒到该时间点所经过的秒数。&nbsp;&nbsp;</p>
<p>4．与日期和时间相关的函数及应用&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在本节，我将向大家展示怎样利用time.h中声明的函数对时间进行操作。这些操作包括取当前时间、计算时间间隔、以不同的形式显示时间等内容。&nbsp;&nbsp;</p>
<p>4.1 获得日历时间&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们可以通过time()函数来获得日历时间（Calendar Time），其原型为：<br>time_t time(time_t * timer);&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如 果你已经声明了参数timer，你可以从参数timer返回现在的日历时间，同时也可以通过返回值返回现在的日历时间，即从一个时间点（例如：1970年 1月1日0时0分0秒）到现在此时的秒数。如果参数为空（NUL），函数将只通过返回值返回现在的日历时间，比如下面这个例子用来显示当前的日历时间： &nbsp;&nbsp;</p>
<p>#include "time.h"&nbsp;&nbsp;<br>#include "stdio.h"&nbsp;&nbsp;<br>int main(void)&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>struct tm *ptr;&nbsp;&nbsp;<br>time_t lt;&nbsp;&nbsp;<br>lt =time(NUL);&nbsp;&nbsp;<br>printf("The Calendar Time now is %d\n",lt);&nbsp;&nbsp;<br>return 0;&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>运行的结果与当时的时间有关，我当时运行的结果是：&nbsp;&nbsp;</p>
<p>The Calendar Time now is 1122707619&nbsp;&nbsp;</p>
<p>其中1122707619就是我运行程序时的日历时间。即从1970年1月1日0时0分0秒到此时的秒数。&nbsp;&nbsp;</p>
<p>4.2 获得日期和时间&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里说的日期和时间就是我们平时所说的年、月、日、时、分、秒等信息。从第2节我们已经知道这些信息都保存在一个名为tm的结构体中，那么如何将一个日历时间保存为一个tm结构的对象呢？&nbsp;&nbsp;</p>
<p>其中可以使用的函数是gmtime()和localtime()，这两个函数的原型为：&nbsp;&nbsp;</p>
<p>struct tm * gmtime(const time_t *timer);&nbsp;&nbsp;<br>struct tm * localtime(const time_t * timer);&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其 中gmtime()函数是将日历时间转化为世界标准时间（即格林尼治时间），并返回一个tm结构体来保存这个时间，而localtime()函数是将日历 时间转化为本地时间。比如现在用gmtime()函数获得的世界标准时间是2005年7月30日7点18分20秒，那么我用localtime()函数在 中国地区获得的本地时间会比世界标准时间晚8个小时，即2005年7月30日15点18分20秒。下面是个例子：&nbsp;&nbsp;</p>
<p>#include "time.h"&nbsp;&nbsp;<br>#include "stdio.h"&nbsp;&nbsp;<br>int main(void)&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>struct tm *local;&nbsp;&nbsp;<br>time_t t;&nbsp;&nbsp;<br>t=time(NUL);&nbsp;&nbsp;<br>local=localtime(&amp;t);&nbsp;&nbsp;<br>printf("Local hour is: %d\n",local-&gt;tm_hour);&nbsp;&nbsp;<br>local=gmtime(&amp;t);&nbsp;&nbsp;<br>printf("UTC hour is: %d\n",local-&gt;tm_hour);&nbsp;&nbsp;<br>return 0;&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>运行结果是：&nbsp;&nbsp;</p>
<p>Local hour is: 15&nbsp;&nbsp;<br>UTC hour is: 7&nbsp;&nbsp;</p>
<p>4.3 固定的时间格式&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们可以通过asctime()函数和ctime()函数将时间以固定的格式显示出来，两者的返回值都是char*型的字符串。返回的时间格式为：&nbsp;&nbsp;</p>
<p>星期几 月份 日期 时:分:秒 年\n\0&nbsp;&nbsp;<br>例如：Wed Jan 02 02:03:55 1980\n\0&nbsp;&nbsp;</p>
<p>其中\n是一个换行符，\0是一个空字符，表示字符串结束。下面是两个函数的原型：&nbsp;&nbsp;</p>
<p>char * asctime(const struct tm * timeptr);&nbsp;&nbsp;<br>char * ctime(const time_t *timer);&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其 中asctime()函数是通过tm结构来生成具有固定格式的保存时间信息的字符串，而ctime()是通过日历时间来生成时间字符串。这样的话， asctime（）函数只是把tm结构对象中的各个域填到时间字符串的相应位置就行了，而ctime（）函数需要先参照本地的时间设置，把日历时间转化为 本地时间，然后再生成格式化后的字符串。在下面，如果t是一个非空的time_t变量的话，那么：&nbsp;&nbsp;</p>
<p>printf(ctime(&amp;t));&nbsp;&nbsp;</p>
<p>等价于：&nbsp;&nbsp;</p>
<p>struct tm *ptr;&nbsp;&nbsp;<br>ptr=localtime(&amp;t);&nbsp;&nbsp;<br>printf(asctime(ptr));&nbsp;&nbsp;</p>
<p>那么，下面这个程序的两条printf语句输出的结果就是不同的了（除非你将本地时区设为世界标准时间所在的时区）：&nbsp;&nbsp;</p>
<p>#include "time.h"&nbsp;&nbsp;<br>#include "stdio.h"&nbsp;&nbsp;<br>int main(void)&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>struct tm *ptr;&nbsp;&nbsp;<br>time_t lt;&nbsp;&nbsp;<br>lt =time(NUL);&nbsp;&nbsp;<br>ptr=gmtime(&lt;);&nbsp;&nbsp;<br>printf(asctime(ptr));&nbsp;&nbsp;<br>printf(ctime(&lt;));&nbsp;&nbsp;<br>return 0;&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>运行结果：&nbsp;&nbsp;</p>
<p>Sat Jul 30 08:43:03 2005&nbsp;&nbsp;<br>Sat Jul 30 16:43:03 2005&nbsp;&nbsp;</p>
<p>4.4 自定义时间格式&nbsp;&nbsp;</p>
<p>我们可以使用strftime（）函数将时间格式化为我们想要的格式。它的原型如下：&nbsp;&nbsp;</p>
<p>size_t strftime(&nbsp;&nbsp;<br>char *strDest,&nbsp;&nbsp;<br>size_t maxsize,&nbsp;&nbsp;<br>const char *format,&nbsp;&nbsp;<br>const struct tm *timeptr&nbsp;&nbsp;<br>);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们可以根据format指向字符串中格式命令把timeptr中保存的时间信息放在strDest指向的字符串中，最多向strDest中存放maxsize个字符。该函数返回向strDest指向的字符串中放置的字符数。&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 函 数strftime()的操作有些类似于sprintf()：识别以百分号(%)开始的格式命令集合，格式化输出结果放在一个字符串中。格式化命令说明串 strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列在下面，它们是区分大小写的。&nbsp;&nbsp;</p>
<p>%a 星期几的简写&nbsp;&nbsp;<br>%A 星期几的全称&nbsp;&nbsp;<br>%b 月分的简写&nbsp;&nbsp;<br>%B 月份的全称&nbsp;&nbsp;<br>%c 标准的日期的时间串&nbsp;&nbsp;<br>%C 年份的后两位数字&nbsp;&nbsp;<br>%d 十进制表示的每月的第几天&nbsp;&nbsp;<br>%D 月/天/年&nbsp;&nbsp;<br>%e 在两字符域中，十进制表示的每月的第几天&nbsp;&nbsp;<br>%F 年-月-日&nbsp;&nbsp;<br>%g 年份的后两位数字，使用基于周的年&nbsp;&nbsp;<br>%G 年分，使用基于周的年&nbsp;&nbsp;<br>%h 简写的月份名&nbsp;&nbsp;<br>%H 24小时制的小时&nbsp;&nbsp;<br>%I 12小时制的小时&nbsp;&nbsp;<br>%j 十进制表示的每年的第几天&nbsp;&nbsp;<br>%m 十进制表示的月份&nbsp;&nbsp;<br>%M 十时制表示的分钟数&nbsp;&nbsp;<br>%n 新行符&nbsp;&nbsp;<br>%p 本地的AM或PM的等价显示&nbsp;&nbsp;<br>%r 12小时的时间&nbsp;&nbsp;<br>%R 显示小时和分钟：hh:mm&nbsp;&nbsp;<br>%S 十进制的秒数&nbsp;&nbsp;<br>%t 水平制表符&nbsp;&nbsp;<br>%T 显示时分秒：hh:mm:ss&nbsp;&nbsp;<br>%u 每周的第几天，星期一为第一天 （值从0到6，星期一为0）&nbsp;&nbsp;<br>%U 第年的第几周，把星期日做为第一天（值从0到53）&nbsp;&nbsp;<br>%V 每年的第几周，使用基于周的年&nbsp;&nbsp;<br>%w 十进制表示的星期几（值从0到6，星期天为0）&nbsp;&nbsp;<br>%W 每年的第几周，把星期一做为第一天（值从0到53）&nbsp;&nbsp;<br>%x 标准的日期串&nbsp;&nbsp;<br>%X 标准的时间串&nbsp;&nbsp;<br>%y 不带世纪的十进制年份（值从0到99）&nbsp;&nbsp;<br>%Y 带世纪部分的十进制年份&nbsp;&nbsp;<br>%z，%Z 时区名称，如果不能得到时区名称则返回空字符。&nbsp;&nbsp;<br>%% 百分号&nbsp;&nbsp;</p>
<p>如果想显示现在是几点了，并以12小时制显示，就象下面这段程序：&nbsp;&nbsp;</p>
<p>#include &#8220;time.h&#8221;&nbsp;&nbsp;<br>#include &#8220;stdio.h&#8221;&nbsp;&nbsp;<br>int main(void)&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>struct tm *ptr;&nbsp;&nbsp;<br>time_t lt;&nbsp;&nbsp;<br>char str[80];&nbsp;&nbsp;<br>lt=time(NUL);&nbsp;&nbsp;<br>ptr=localtime(&lt;);&nbsp;&nbsp;<br>strftime(str,100,"It is now %I %p",ptr);&nbsp;&nbsp;<br>printf(str);&nbsp;&nbsp;<br>return 0;&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>其运行结果为：&nbsp;&nbsp;<br>It is now 4PM&nbsp;&nbsp;</p>
<p>而下面的程序则显示当前的完整日期：&nbsp;&nbsp;</p>
<p>#include &lt;stdio.h&gt;&nbsp;&nbsp;<br>#include &lt;time.h&gt;&nbsp;&nbsp;</p>
<p>void main( void )&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>struct tm *newtime;&nbsp;&nbsp;<br>char tmpbuf[128];&nbsp;&nbsp;<br>time_t lt1;&nbsp;&nbsp;<br>time( &lt;1 );&nbsp;&nbsp;<br>newtime=localtime(&lt;1);&nbsp;&nbsp;<br>strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);&nbsp;&nbsp;<br>printf(tmpbuf);&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>运行结果：&nbsp;&nbsp;</p>
<p>Today is Saturday, day 30 of July in the year 2005.&nbsp;&nbsp;</p>
<p>4.5 计算持续时间的长度&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有时候在实际应用中要计算一个事件持续的时间长度，比如计算打字速度。在第1节计时部分中，我已经用clock函数举了一个例子。Clock()函数可以精确到毫秒级。同时，我们也可以使用difftime()函数，但它只能精确到秒。该函数的定义如下：&nbsp;&nbsp;</p>
<p>double difftime(time_t time1, time_t time0);&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然该函数返回的以秒计算的时间间隔是double类型的，但这并不说明该时间具有同double一样的精确度，这是由它的参数觉得的（time_t是以秒为单位计算的）。比如下面一段程序：&nbsp;&nbsp;</p>
<p>#include "time.h"&nbsp;&nbsp;<br>#include "stdio.h"&nbsp;&nbsp;<br>#include "stdlib.h"&nbsp;&nbsp;<br>int main(void)&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>time_t start,end;&nbsp;&nbsp;<br>start = time(NUL);&nbsp;&nbsp;<br>system("pause");&nbsp;&nbsp;<br>end = time(NUL);&nbsp;&nbsp;<br>printf("The pause used %f seconds.\n",difftime(end,start));//&lt;-&nbsp;&nbsp;<br>system("pause");&nbsp;&nbsp;<br>return 0;&nbsp;&nbsp;<br>}&nbsp;&nbsp;</p>
<p>运行结果为：&nbsp;&nbsp;<br>请按任意键继续. . .&nbsp;&nbsp;<br>The pause used 2.000000 seconds.&nbsp;&nbsp;<br>请按任意键继续. . .&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以想像，暂停的时间并不那么巧是整整2秒钟。其实，你将上面程序的带有&#8220;//&lt;-&#8221;注释的一行用下面的一行代码替换：&nbsp;&nbsp;</p>
<p>printf("The pause used %f seconds.\n",end-start);&nbsp;&nbsp;</p>
<p>其运行结果是一样的。&nbsp;&nbsp;</p>
<p>4.6 分解时间转化为日历时间&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里说的分解时间就是以年、月、日、时、分、秒等分量保存的时间结构，在C/C++中是tm结构。我们可以使用mktime（）函数将用tm结构表示的时间转化为日历时间。其函数原型如下：&nbsp;&nbsp;</p>
<p>time_t mktime(struct tm * timeptr);&nbsp;&nbsp;</p>
<p>其返回值就是转化后的日历时间。这样我们就可以先制定一个分解时间，然后对这个时间进行操作了，下面的例子可以计算出1997年7月1日是星期几：&nbsp;&nbsp;</p>
<p>#include "time.h"&nbsp;&nbsp;<br>#include "stdio.h"&nbsp;&nbsp;<br>#include "stdlib.h"&nbsp;&nbsp;<br>int main(void)&nbsp;&nbsp;<br>{&nbsp;&nbsp;<br>struct tm t;&nbsp;&nbsp;<br>time_t t_of_day;&nbsp;&nbsp;<br>t.tm_year=1997-1900;&nbsp;&nbsp;<br>t.tm_mon=6;&nbsp;&nbsp;<br>t.tm_mday=1;&nbsp;&nbsp;<br>t.tm_hour=0;&nbsp;&nbsp;<br>t.tm_min=0;&nbsp;&nbsp;<br>t.tm_sec=1;&nbsp;&nbsp;<br>t.tm_isdst=0;&nbsp;&nbsp;<br>t_of_day=mktime(&amp;t);&nbsp;&nbsp;<br>printf(ctime(&amp;t_of_day));&nbsp;&nbsp;<br>return 0;&nbsp;&nbsp;<br>}&nbsp;&nbsp;<br>运行结果：&nbsp;&nbsp;<br>Tue Jul 01 00:00:01 1997&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; 现在注意了，有了mktime()函数，是不是我们可以操作现在之前的任何时间呢？你可以通过这种办法算出1945年8月15号是星期几吗？答案是否定的。因为这个时间在1970年1月1日之前，所以在大多数编译器中，这样的程序虽然可以编译通过，但运行时会异常终止。 <br>5．总结 <br>本文介绍了标准C/C++中的有关日期和时间的概念，并通过各种实例讲述了这些函数和数据结构的使用方法。笔者认为，和时间相关的一些概念是相当重要的，理解这些概念是理解各种时间格式的转换的基础，更是应用这些函数和数据结构的基础。</p>
</div>
<img src ="http://www.cppblog.com/Walker/aggbug/81194.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-27 11:11 <a href="http://www.cppblog.com/Walker/articles/81194.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转） 排序算法总结</title><link>http://www.cppblog.com/Walker/articles/81101.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Sun, 26 Apr 2009 02:19:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/81101.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/81101.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/81101.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/81101.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/81101.html</trackback:ping><description><![CDATA[花了很长时间终于把排序的基础学了一下，这段时间学了很多东西，总结一下：<br>学的排序算法有：插入排序，合并排序，冒泡排序，选择排序，希尔排序，堆排序，快速排序，计数排序，基数排序，桶排序（没有实现）。比较一下学习后的心得。<br>我不是很清楚他们的时间复杂度，也真的不知道他们到底谁快谁慢，因为书上的推导我确实只是小小了解，并没有消化。也没有完全理解他们的精髓，所以又什么错误的还需要高手指点。呵呵。<br>1.普及一下排序稳定，所谓排序稳定就是指：如果两个数相同，对他们进行的排序结果为他们的相对顺序不变。例如A={<span style="COLOR: red">1</span>,<span style="COLOR: red">2</span>,<span style="COLOR: #2000ff">1</span>,<span style="COLOR: #2000ff">2</span>,1}这里排序之后是A = {<span style="COLOR: red">1</span>,<span style="COLOR: #2000ff">1</span>,1,<span style="COLOR: red">2</span>,<span style="COLOR: #2000ff">2</span>} 稳定就是排序后第一个1就是排序前的第一个1，第二个1就是排序前第二个1，第三个1就是排序前的第三个1。同理2也是一样。这里用颜色标明了。不稳定呢就是他们的顺序不应和开始顺序一致。也就是可能会是A={<span style="COLOR: #2000ff">1</span>,1,<span style="COLOR: #ff0000">1</span>,<span style="COLOR: #ff0000">2</span>,<span style="COLOR: #0000ff">2</span>}这样的结果。<br>2.普及一下原地排序：原地排序就是指不申请多余的空间来进行的排序，就是在原来的排序数据中比较和交换的排序。例如快速排序，堆排序等都是原地排序，合并排序，计数排序等不是原地排序。<br>3.感觉谁最好，在我的印象中快速排序是最好的，时间复杂度：n*log(n)，不稳定排序。原地排序。他的名字很棒，快速嘛。当然快了。我觉得他的思想很不错，分治，而且还是原地排序，省去和很多的空间浪费。速度也是很快的，n*log(n)。但是有一个软肋就是如果已经是排好的情况下时间复杂度就是n*n,不过在加入随机的情况下这种情况也得以好转，而且他可以做任意的比较，只要你能给出两个元素的大小关系就可以了。适用范围广，速度快。<br>4.插入排序：n*n的时间复杂度，稳定排序，原地排序。插入排序是我学的第一个排序，速度还是很快的，特别是在数组已排好了之后，用它的思想来插入一个数据，效率是很高的。因为不用全部排。他的数据交换也很少，只是数据后移，然后放入要插入的数据。（这里不是指调用插入排序，而是用它的思想）。我觉得，在数据大部分都排好了，用插入排序会给你带来很大的方便。数据的移动和交换都很少。<br>5.冒泡排序，n*n的时间复杂度，稳定排序，原地排序。冒泡排序的思想很不错，一个一个比较，把小的上移，依次确定当前最小元素。因为他简单，稳定排序，而且好实现，所以用处也是比较多的。还有一点就是加上哨兵之后他可以提前退出。<br>6.选择排序，n*n的时间复杂度， 稳定排序，原地排序。选择排序就是冒泡的基本思想，从小的定位，一个一个选择，直到选择结束。他和插入排序是一个相反的过程，插入是确定一个元素的位置，而选择是确定这个位置的元素。他的好处就是每次只选择确定的元素，不会对很多数据进行交换。所以在数据交换量上应该比冒泡小。<br>7.插入排序，选择排序，冒泡排序的比较，他们的时间复杂度都是n*n。我觉得他们的效率也是差不多的，我个人喜欢冒泡一些，因为要用它的时候数据多半不多，而且可以提前的返回已经排序好的数组。而其他两个排序就算已经排好了，他也要做全部的扫描。在数据的交换上，冒泡的确比他们都多。呵呵。举例说明插入一个数据在末尾后排序，冒泡只要一次就能搞定，而选择和插入都必须要n*n的复杂度才能搞定。就看你怎么看待咯。<br>8.合并排序：n*log(n)的时间复杂度， 稳定排序，非原地排序。他的思想是分治，先分成小的部分，排好部分之后合并，因为我们另外申请的空间，在合并的时候效率是0(n)的。速度很快。貌似他的上限是n*log(n)，所以如果说是比较的次数的话，他比快速排序要少一些。对任意的数组都能有效地在n*log(n)排好序。但是因为他是非原地排序，所以虽然他很快，但是貌似他的人气没有快速排序高。<br>9.堆排序：n*log(n)的时间复杂度， 非稳定排序，原地排序。他的思想是利用的堆这种数据结构，堆可以看成一个完全二叉树，所以在排序中比较的次数可以做到很少。加上他也是原地排序，不需要申请额外的空间，效率也不错。可是他的思想感觉比快速难掌握一些。还有就是在已经排好序的基础上添加一个数据再排序，他的交换次数和比较次数一点都不会减少。虽然堆排序在使用的中没有快速排序广泛，但是他的数据结构和思想真的很不错，而且用它来实现优先队列，效率没得说。堆，还是要好好学习掌握的。<br>10.希尔排序：n*log(n)的时间复杂度<span style="COLOR: red">(这里是错误的，应该是n^lamda(1 &lt; lamda &lt; 2), lamda和每次步长选择有关。)</span>， 非稳定排序，原地排序。主要思想是分治，不过他的分治和合并排序的分治不一样，他是按步长来分组的，而不是想合并那样左一半右一半。开始步长为整个的长度的一半。分成nLen/2个组，然后每组排序。接个步长减为原来的一半在分组排序，直到步长为1，排序之后希尔排序就完成了。这个思路很好，据说是插入排序的升级版，所以在实现每组排序的时候我故意用了插入排序。我觉得他是一个特别好的排序方法了。他的缺点就是两个数可能比较多次，因为两个数据会多次分不过他们不会出现数据的交换。效率也是很高的。<br>11.快速排序，堆排序，合并排序，希尔排序的比较，他们的时间复杂的都是n*log(n)，我认为在使用上快速排序最广泛，他原地排序，虽然不稳定，可是很多情况下排序根本就不在意他是否稳定。他的比较次数是比较小的，因为他把数据分成了大和小的两部分。每次都确定了一个数的位置，所以理论上说不会出现两个数比较两次的情况，也是在最后在交换数据，说以数据交换上也很少。合并排序和堆排序也有这些优点，但是合并排序要申请额外的空间。堆排序堆已经排好的数据交换上比快速多。所以目前快速排序用的要广泛的多。还有他很容易掌握和实现。<br>12.计数排序：n的时间复杂度，稳定排序，非原地排序。他的思想比较新颖，就是先约定数据的范围不是很大，而且数据都是整数(或能定位到整数)的情况，然后直接申请一个空间。把要排序的数组A的元素值与申请空间B的下标对应，然后B中存放该下标元素值的个数，从而直接定位A中每个元素的位置。这样效率只为n。因为比较很特殊，虽然很快，但是用的地方并不多。<br>13.基数排序：n的时间复杂度，稳定排序，非原地排序。他的思想是数据比较集中在一个范围，例如都是4位数，都是5位数，或数据有多个关键字，我们先从各位开始排，然后排十位，依次排到最高位，因为我们可以用一个n的方法排一位，所以总的方法为d*n的复杂度。关键字也一样，我们先排第3个关键字，在排第3个关键字，最后排第一个关键字。只有能保证每个关键字在n的时间复杂度完成，那么整个排序就是一个d*n的时间复杂度。所以总的速度是很快的。不过有一点就是要确保关键字能在n的时间复杂度完成。<br>14.桶排序：n的时间复杂度，稳定排序，非原地排序。主要思路和基数排序一样，也是假设都在一个范围例如概率都在0-1，而且分布还挺均匀，那么我们也是和基数排序一样对一个数把他划分在他指定的区域。然后在连接这些区域就可以了。书上对每个区域使用链表的存储，我认为在寸小区域的时候也会有时间在里面。所以只是理论上的n时间复杂度。这种思路是不错的。呵呵。<br>15.计数排序，基数排序，桶排序的比较，我觉得他们都很有思想，不过都是在特定情况下才能发挥最大的效果。虽然效率很高，但是用的不会很广泛。他们之间我更喜欢计数排序，来个映射的方式就直接找到了自己的位置，很高明。和基数排序和同排序只是理论上的n时间复杂度，基数排序要确定一个关键字的排序是n复杂度的，桶排序要确定每个区域的排序是n复杂度的。<br>16.排序算法的最后感悟：黑格尔说过：存在即合理。所以这些排序的算法都是很好的，他确实给了我们思想上的帮助。感谢前人把精华留给了我们。我得到的收获很大，总结一下各自排序的收获：<br>冒泡：好实现，速度不慢，使用于轻量级的数据排序。<br>插入排序：也使用于小数据的排序，但是我从他的思想中学到怎么插入一个数据。呵呵，这样就知道在排好的数据里面，不用再排序了，而是直接调用一下插入就可以了。<br>选择排序：我学会了怎么去获得最大值，最小值等方法。只要选择一下，不就可以了。<br>合并排序：我学会分而治之的方法，而且在合并两个数组的时候很适用。<br>堆排序：可以用它来实现优先队列，而且他的思想应该给我加了很多内力。<br>快速排序：本来就用的最多的排序，对我的帮助大的都不知道怎么说好。<br>希尔排序：也是分治，让我看到了分治的不同，原来还有这种思想的存在。<br>计数排序，基数排序，桶排序：特殊情况特殊处理。<br>附上我学习这里排序的连接 <br>
<meta content=Word.Document name=ProgId>
<meta content="Microsoft Word 11" name=Generator>
<meta content="Microsoft Word 11" name=Originator>
<link href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C07%5Cclip_filelist.xml" rel=File-List>
<style>
<!--
/* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-alt:SimSun;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
@font-face
{font-family:"\@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 135135232 16 0 262145 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
mso-pagination:none;
font-size:10.5pt;
mso-bidi-font-size:12.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:宋体;
mso-font-kerning:1.0pt;}
a:link, span.MsoHyperlink
{color:blue;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{color:purple;
text-decoration:underline;
text-underline:single;}
/* Page Definitions */
@page
{mso-page-border-surround-header:no;
mso-page-border-surround-footer:no;}
@page Section1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.Section1
{page:Section1;}
-->
</style>
<p><a href="http://www.cppblog.com/shongbee2/archive/2009/04/23/80885.html">快速排序学习1</a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.cppblog.com/shongbee2/archive/2009/04/23/80887.html">快速排序学习2（随机化版本）</a> </p>
<p><a href="http://www.cppblog.com/shongbee2/archive/2009/04/23/80888.html">快速排序学习3（最初版）</a>&nbsp; <a href="http://www.cppblog.com/shongbee2/archive/2009/04/23/80891.html">快速排序学习4（最初版加随机版）</a></p>
<p><a href="http://www.cppblog.com/shongbee2/archive/2009/03/31/78441.html">插入排序</a> &nbsp;&nbsp;<a href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81038.html">冒泡排序</a> &nbsp;&nbsp;&nbsp;<a href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81040.html">选择排序</a></p>
<p><a href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81046.html">希尔排序</a>&nbsp;&nbsp; <a href="http://www.cppblog.com/shongbee2/archive/2009/03/31/78456.html">合并排序</a>&nbsp; <a href="http://www.cppblog.com/shongbee2/archive/2009/04/21/80639.html">堆排序</a>&nbsp; <a href="http://www.cppblog.com/shongbee2/archive/2009/04/22/80765.html">用堆实现优先队列</a></p>
<a href="http://www.cppblog.com/shongbee2/archive/2009/04/24/80992.html">基数排序</a> &nbsp;<a href="http://www.cppblog.com/shongbee2/archive/2009/04/24/80991.html">计数排序</a> <br>
<p class=postfoot>posted on 2009-04-25 19:30 <a href="http://www.cppblog.com/shongbee2/"><font size=2>shongbee2</font></a> 阅读(313) <a href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81058.html#Post"><font size=2>评论(5)</font></a> &nbsp;<a href="http://www.cppblog.com/shongbee2/admin/EditPosts.aspx?postid=81058"><font size=2>编辑</font></a>&nbsp;<a href="http://www.cppblog.com/shongbee2/AddToFavorite.aspx?id=81058"><font size=2>收藏</font></a> <a href="http://www.cppblog.com/shongbee2/services/trackbacks/81058.aspx"><font size=2>引用</font></a> 所属分类: <a href="http://www.cppblog.com/shongbee2/category/10031.html"><font size=2>数据结构和算法</font></a> </p>
<img height=1 src="http://www.cppblog.com/shongbee2/aggbug/81058.html?webview=1" width=1> <!--
<rdf:rdf xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:description
rdf:about="http://www.cppblog.com/shongbee2/archive/2009/04/25/81058.html"
dc:identifier="http://www.cppblog.com/shongbee2/archive/2009/04/25/81058.html"
dc:title="排序算法总结"
trackback:ping="http://www.cppblog.com/shongbee2/services/trackbacks/81058.aspx" />
</rdf:rdf>
-->
<script type=text/javascript>
//<![cdata[
Sys.WebForms.PageRequestManager._initialize('AjaxHolder$scriptmanager1', document.getElementById('Form1'));
Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tAjaxHolder$UpdatePanel1'], [], [], 90);
//]]&gt;
</script>
<div id=AjaxHolder_UpdatePanel1><a name=pagedcomment></a><a name=评论>
<div id=comments>
<h3>评论</h3>
<h4><a title="permalink: re: 排序算法总结[未登录]" href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81058.html#81073"><font size=2>#</font></a>&nbsp;<a name=81073></a>re: 排序算法总结[未登录] <span><font color=#999999>2009-04-25 22:10 </font></span><a id=AjaxHolder_Comments_CommentList_ctl00_NameLink target=_blank>R</a> </h4>
<p>shell sort 复杂度是n^lamda, lamda是大于1小于2的实数, 并非nlogn. &nbsp;&nbsp;<a onclick='return SetReplyAuhor("R")' href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81058.html#post">回复</a>&nbsp;&nbsp;<a title=查看该作者发表过的评论 href="http://www.cppblog.com/comment?author=R" target=_blank>更多评论</a> <a id=AjaxHolder_Comments_CommentList_ctl00_DeleteLink href="javascript:__doPostBack('AjaxHolder$Comments$CommentList$ctl00$DeleteLink','')"></a>&nbsp;&nbsp;<a id=AjaxHolder_Comments_CommentList_ctl00_EditLink></a> </p>
<h4><a title="permalink: re: 排序算法总结" href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81058.html#81083"><font size=2>#</font></a>&nbsp;<a name=81083></a>re: 排序算法总结 <span><font color=#999999>2009-04-26 00:30 </font></span><a id=AjaxHolder_Comments_CommentList_ctl01_NameLink href="http://www.cppblog.com/shongbee2/" target=_blank><font size=2>shongbee2</font></a> </h4>
<p>@R <br>哦。谢谢，原来跟lamda有关系哈。呵呵，因为我每次都是折半，所以就误认为是nlogn了。嘻嘻，谢谢哈。&nbsp;&nbsp;<a onclick='return SetReplyAuhor("shongbee2")' href="http://www.cppblog.com/shongbee2/archive/2009/04/25/81058.html#post">回复</a>&nbsp;&nbsp;<a title=查看该作者发表过的评论 href="http://www.cppblog.com/comment?author=shongbee2" target=_blank>更多评论</a> <a id=AjaxHolder_Comments_CommentList_ctl01_DeleteLink href="javascript:__doPostBack('AjaxHolder$Comments$CommentList$ctl01$DeleteLink','')"></a>&nbsp;&nbsp;<a id=AjaxHolder_Comments_CommentList_ctl01_EditLink></a> </p>
</div>
</div>
<img src ="http://www.cppblog.com/Walker/aggbug/81101.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-26 10:19 <a href="http://www.cppblog.com/Walker/articles/81101.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员应该读的论文</title><link>http://www.cppblog.com/Walker/articles/81018.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Sat, 25 Apr 2009 02:41:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/81018.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/81018.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/81018.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/81018.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/81018.html</trackback:ping><description><![CDATA[<p>言归正传，看看是哪10篇论文入了Feathers大师的法眼吧：</p>
<ol>
    <li><a href="http://sunnyday.mit.edu/16.355/parnas-criteria.html"><font color=#336699>On the criteria to be used in decomposing systems into modules</font></a> &#8211; David Parnas
    <li><a href="http://research.sun.com/techrep/1994/abstract-29.html"><font color=#336699>A Note On Distributed Computing</font></a> &#8211; Jim Waldo, Geoff Wyant, Ann Wollrath, Sam Kendall
    <li><a href="http://portal.acm.org/citation.cfm?id=365257"><font color=#336699>The Next 700 Programming Languages</font></a> &#8211; P. J. Landin
    <li><a href="http://portal.acm.org/citation.cfm?id=359579"><font color=#336699>Can Programming Be Liberated from the von Neumann Style?</font></a> &#8211; John Backus
    <li><a href="http://cm.bell-labs.com/who/ken/trust.html"><font color=#336699>Reflections on Trusting Trust</font></a> &#8211; Ken Thompson
    <li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.6083"><font color=#336699>Lisp: Good News, Bad News, How to Win Big</font></a> &#8211; Richard Gabriel
    <li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.29.363"><font color=#336699>An experimental evaluation of the assumption of independence in multiversion programming</font></a> &#8211; John Knight and Nancy Leveson
    <li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.7565"><font color=#336699>Arguments and Results</font></a> &#8211; James Noble
    <li><a href="http://c2.com/doc/oopsla89/paper.html"><font color=#336699>A Laboratory For Teaching Object-Oriented Thinking</font></a> &#8211; Kent Beck, Ward Cunningham
    <li><a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.31.562"><font color=#336699>Programming as an Experience: the inspiration for Self</font></a> &#8211; David Ungar, Randall B. Smith </li>
</ol>
<p>Feathers的文章显然成了这几天网上的热门话题，我们另外一本已经获得版权的书《SOA Patterns》（Manning，2009）的作者Arnon Rotem-Gal-Oz受他启发，写了<a href="http://www.rgoarchitects.com/nblog/2009/02/27/10PapersEverySoftwareArchitectShouldReadAtLeastTwice.aspx"><font color=#336699>&#8220;所有架构师都应该至少读上两遍的十篇论文&#8221;</font></a>：</p>
<p>1. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fresearch.microsoft.com%2fen-us%2fum%2fpeople%2flamport%2fpubs%2fbyz.pdf"><font color=#336699>The Byzantine Generals Problem</font></a> (1982) by Leslie Lamport, Robert Shostak and Marshall Pease<br>2. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fwww.u.arizona.edu%2f%257Erubinson%2fcopyright_violations%2fGo_To_Considered_Harmful.html"><font color=#336699>Go To statements considered harmfull</font></a> (1968) - by Edsger W. Dijkstra <br>3.<a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fresearch.sun.com%2ftechrep%2f1994%2fabstract-29.html"><font color=#336699> A Note on Distributed Computing</font></a> (1994) - by Samuel C. Kendall, Jim Waldo, Ann Wollrath and Geoff Wyant <br>4. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fwww.laputan.org%2fmud%2f"><font color=#336699>Big Ball of Mud</font></a> (1999) - Brian Foote and Joseph Yoder <a href="http://www.rgoarchitects.com/nblog/2007/11/28/BigBallOfMudAndOtherArchitecturalDisastersNot.aspx"><br></a>5. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fwww.lips.utexas.edu%2fee382c-15005%2fReadings%2fReadings1%2f05-Broo87.pdf"><font color=#336699>No Silver Bullet Essence and Accidents of Software Engineering</font></a> (1987) - Frederick P. Brooks <br>6. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fwww.objectmentor.com%2fresources%2farticles%2focp.pdf"><font color=#336699>The Open Closed Principle</font></a> (1996) - Robert C. Martin (Uncle Bob) <br>7. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fstandards.ieee.org%2freading%2fieee%2fstd_public%2fdescription%2fse%2f1471-2000_desc.html"><font color=#336699>IEEE1471-2000 A recommended practice for architectural description of software intensive systems</font></a> (2000) <br>8. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fciteseerx.ist.psu.edu%2fviewdoc%2fsummary%3fdoi%3d10.1.1.33.411"><font color=#336699>Harvest, Yield, and Scalable Tolerant Systems</font></a> (1999) Armando Fox, Eric A. Brewer <br>9. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fwww.cs.cmu.edu%2fafs%2fcs%2fproject%2fvit%2fftp%2fpdf%2fintro_softarch.pdf"><font color=#336699>An Introduction to Software Architecture</font></a> (1993) - David Garlan and Mary Shaw <br>10. <a href="http://www.rgoarchitects.com/nblog/ct.ashx?id=ee9b28a4-7f61-4d7b-8796-b82420097c96&amp;url=http%3a%2f%2fmartinfowler.com%2fieeeSoftware%2fwhoNeedsArchitect.pdf"><font color=#336699>Who Needs an Architect?</font></a> (2003) Martin Fowler </p>
<img src ="http://www.cppblog.com/Walker/aggbug/81018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-25 10:41 <a href="http://www.cppblog.com/Walker/articles/81018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转）A*算法入门</title><link>http://www.cppblog.com/Walker/articles/80564.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Mon, 20 Apr 2009 12:29:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/80564.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/80564.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/80564.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/80564.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/80564.html</trackback:ping><description><![CDATA[<p><span>在看下面这篇文章之前，先介绍几个理论知识，有助于理解<span>A*</span>算法。</span></p>
<p>&nbsp;</p>
<p><strong><span>启发式搜索</span></strong><span>：启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估，得到最好的位置，再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径，提到了效率。在启发式搜索中，对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。</span></p>
<p><strong><span>估价函数</span></strong><span>：从当前节点移动到目标节点的预估费用；这个估计就是启发式的。在寻路问题和迷宫问题中，我们通常用曼哈顿（<span>manhattan</span>）估价函数（下文有介绍）预估费用。</span></p>
<p><strong><span>A*</span></strong><strong><span>算法与<span>BFS</span></span></strong><span>：可以这样说，<span>BFS</span>是<span>A*</span>算法的一个特例。对于一个<span>BFS</span>算法，从当前节点扩展出来的每一个节点（如果没有被访问过的话）都要放进队列进行进一步扩展。也就是说<span>BFS</span>的估计函数<span>h</span>永远等于<span>0</span>，没有一点启发式的信息，可以认为<span>BFS</span>是&#8220;最烂的&#8221;<span>A*</span>算法。</span></p>
<p><strong><span>选取最小估价：</span></strong><span>如果学过数据结构的话，应该可以知道，对于每次都要选取最小估价的节点，应该用到最小优先级队列（也叫最小二叉堆）。在<span>C++</span>的<span>STL</span>里有现成的数据结构<span>priority_queue</span>，可以直接使用。当然不要忘了重载自定义节点的比较操作符。</span></p>
<p><strong><span>A*</span></strong><strong><span>算法的特点：</span></strong><span>A*</span><span>算法在理论上是时间最优的，但是也有缺点：它的空间增长是指数级别的。</span></p>
<p><strong><span>IDA*</span></strong><strong><span>算法：</span></strong><span>这种算法被称为迭代加深<span>A*</span>算法，可以有效的解决<span>A*</span>空间增长带来的问题，甚至可以不用到优先级队列。如果要知道详细：<span>google</span>一下。</span></p>
<br>&nbsp;
<p align=center><strong><span>A*</span></strong><strong><span>寻路初探（转载）</span></strong></p>
<p align=center><strong>&nbsp;</strong></p>
<p align=center><strong><span>作者：<span>Patrick Lester</span></span></strong></p>
<p align=center><strong><span>译者：<span>Panic2005</span>年</span></strong></p>
<p align=center><strong>&nbsp;</strong></p>
<p align=left><span>译者序：很久以前就知道了<span>A*</span>算法，但是从未认真读过相关的文章，也没有看过代码，只是脑子里有个模糊的概念。这次决定从头开始，研究一下这个被人推崇备至的简单方法，作为学习人工智能的开始。</span></p>
<p align=left><span>这篇文章非常知名，国内应该有不少人翻译过它，我没有查找，觉得翻译本身也是对自身英文水平的锻炼。经过努力，终于完成了文档，也明白的<span>A*</span>算法的原理。毫无疑问，作者用形象的描述，简洁诙谐的语言由浅入深的讲述了这一神奇的算法，相信每个读过的人都会对此有所认识（如果没有，那就是偶的翻译太差了<span>--b</span>）。</span></p>
<p align=left><span>现在是年月日的版本，应原作者要求，对文中的某些算法细节做了修改。</span></p>
<p align=left><span>原文链接：<span>http:<span>//www.gamedev.net/reference/articles/article2003.asp</span></span></span></p>
<p align=left><span>原作者文章链接：<span>http:<span>//www.policyalmanac.org/games/aStarTutorial.htm</span></span></span></p>
<p align=center><strong><span>以下是翻译的正文</span></strong></p>
<p align=left><span>会者不难，<span>A*(</span>念作<span>A</span>星<span>)</span>算法对初学者来说的确有些难度。这篇文章并不试图对这个话题作权威的陈述。取而代之的是，它只是描述算法的原理，使你可以在进一步的阅读中理解其他相关的资料。最后，这篇文章没有程序细节。你尽可以用任意的计算机程序语言实现它。如你所愿，我在文章的末尾包含了一个指向例子程序的链接。压缩包包括<span>C++</span>和<span>Blitz Basic</span>两个语言的版本，如果你只是想看看它的运行效果，里面还包含了可执行文件。我们正在提高自己。让我们从头开始。。。</span></p>
<p align=left>&nbsp;</p>
<p align=center><strong><span>序：搜索区域</span></strong></p>
<p align=left><span>假设有人想从<span>A</span>点移动到一墙之隔的<span>B</span>点，如下图，绿色的是起点<span>A</span>，红色是终点<span>B</span>，蓝色方块是中间的墙。</span></p>
<p align=center><img style="WIDTH: 447px; HEIGHT: 238px" height=238 alt="" src="http://www.cppblog.com/images/cppblog_com/mythit/1.jpg" width=447 border=0></p>
<p align=center><span>[</span><span>图<span>-1]</span></span></p>
<p align=left><span>你首先注意到，搜索区域被我们划分成了方形网格。像这样，简化搜索区域，是寻路的第一步。这一方法把搜索区域简化成了一个二维数组。数组的每一个元素是网格的一个方块，方块被标记为可通过的和不可通过的。路径被描述为从<span>A</span>到<span>B</span>我们经过的方块的集合。一旦路径被找到，我们的人就从一个方格的中心走向另一个，直到到达目的地。</span></p>
<p align=left><span>这些中点被称为</span><span>&#8220;</span><span>节点</span><span>&#8221;</span><span>。当你阅读其他的寻路资料时，你将经常会看到人们讨论节点。为什么不把他们描述为方格呢？因为有可能你的路径被分割成其他不是方格的结构。他们完全可以是矩形，六角形，或者其他任意形状。节点能够被放置在形状的任意位置－可以在中心，或者沿着边界，或其他什么地方。我们使用这种系统，无论如何，因为它是最简单的。</span></p>
<p align=center><strong><span>开始搜索</span></strong></p>
<p align=left><span>正如我们处理上图网格的方法，一旦搜索区域被转化为容易处理的节点，下一步就是去引导一次找到最短路径的搜索。在<span>A*</span>寻路算法中，我们通过从点<span>A</span>开始，检查相邻方格的方式，向外扩展直到找到目标。</span></p>
<p align=left><span>我们做如下操作开始搜索：</span></p>
<p align=left>&nbsp;</p>
<p align=left><span><span>&nbsp;&nbsp; </span>1</span><span>，从点<span>A</span>开始，并且把它作为待处理点存入一个</span><span>&#8220;</span><span>开启列表</span><span>&#8221;</span><span>。开启列表就像一张购物清单。尽管现在列表里只有一个元素，但以后就会多起来。你的路径可能会通过它包含的方格，也可能不会。基本上，这是一个待检查方格的列表。</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>2</span><span>，寻找起点周围所有可到达或者可通过的方格，跳过有墙，水，或其他无法通过地形的方格。也把他们加入开启列表。为所有这些方格保存点<span>A</span>作为</span><span>&#8220;</span><span>父方格</span><span>&#8221;</span><span>。当我们想描述路径的时候，父方格的资料是十分重要的。后面会解释它的具体用途。</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>3</span><span>，从开启列表中删除点<span>A</span>，把它加入到一个</span><span>&#8220;</span><span>关闭列表</span><span>&#8221;</span><span>，列表中保存所有不需要再次检查的方格。在这一点，你应该形成如图的结构。在图中，暗绿色方格是你起始方格的中心。它被用浅蓝色描边，以表示它被加入到关闭列表中了。所有的相邻格现在都在开启列表中，它们被用浅绿色描边。每个方格都有一个灰色指针反指他们的父方格，也就是开始的方格。</span></p>
<p align=center><img style="WIDTH: 281px; HEIGHT: 137px" height=137 alt="" src="http://www.cppblog.com/images/cppblog_com/mythit/2.jpg" width=281 border=0></p>
<p align=center><span>[</span><span>图<span>-2]</span></span></p>
<p align=left><span>接着，我们选择开启列表中的临近方格，大致重复前面的过程，如下。但是，哪个方格是我们要选择的呢？是那个<span>F</span>值最低的。</span></p>
<p align=center><strong><span>路径评分</span></strong></p>
<p align=left><span>选择路径中经过哪个方格的关键是下面这个等式：<span>F = G + H</span></span></p>
<p align=left><span>这里：</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>* G = </span><span>从起点<span>A</span>，沿着产生的路径，移动到网格上指定方格的移动耗费。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>* H = </span><span>从网格上那个方格移动到终点<span>B</span>的预估移动耗费。这经常被称为启发式的，可能会让你有点迷惑。这样叫的原因是因为它只是个猜测。我们没办法事先知道路径的长度，因为路上可能存在各种障碍<span>(</span>墙，水，等等<span>)</span>。虽然本文只提供了一种计算<span>H</span>的方法，但是你可以在网上找到很多其他的方法。</span></p>
<p align=left><span>我们的路径是通过反复遍历开启列表并且选择具有最低<span>F</span>值的方格来生成的。文章将对这个过程做更详细的描述。首先，我们更深入的看看如何计算这个方程。</span></p>
<p align=left><span>正如上面所说，<span>G</span>表示沿路径从起点到当前点的移动耗费。在这个例子里，我们令水平或者垂直移动的耗费为，对角线方向耗费为。我们取这些值是因为沿对角线的距离是沿水平或垂直移动耗费的的根号（别怕），或者约<span>.414</span>倍。为了简化，我们用和近似。比例基本正确，同时我们避免了求根运算和小数。这不是只因为我们怕麻烦或者不喜欢数学。使用这样的整数对计算机来说也更快捷。你不就就会发现，如果你不使用这些简化方法，寻路会变得很慢。</span></p>
<p align=left><span>既然我们在计算沿特定路径通往某个方格的<span>G</span>值，求值的方法就是取它父节点的<span>G</span>值，然后依照它相对父节点是对角线方向或者直角方向<span>(</span>非对角线<span>)</span>，分别增加和。例子中这个方法的需求会变得更多，因为我们从起点方格以外获取了不止一个方格。</span></p>
<p align=left><span>H</span><span>值可以用不同的方法估算。我们这里使用的方法被称为曼哈顿方法，它计算从当前格到目的格之间水平和垂直的方格的数量总和，忽略对角线方向，然后把结果乘以<span>10</span>。这被称为曼哈顿方法是因为它看起来像计算城市中从一个地方到另外一个地方的街区数，在那里你不能沿对角线方向穿过街区。很重要的一点，我们忽略了一切障碍物。这是对剩余距离的一个估算，而非实际值，这也是这一方法被称为启发式的原因。想知道更多？你可以在这里找到方程和额外的注解。</span></p>
<p align=left><span>F</span><span>的值是<span>G</span>和<span>H</span>的和。第一步搜索的结果可以在下面的图表中看到。<span>F,G</span>和<span>H</span>的评分被写在每个方格里。正如在紧挨起始格右侧的方格所表示的，<span>F</span>被打印在左上角，<span>G</span>在左下角，<span>H</span>则在右下角。</span></p>
<p align=center><img style="WIDTH: 459px; HEIGHT: 219px" height=219 alt="" src="http://www.cppblog.com/images/cppblog_com/mythit/3.jpg" width=459 border=0></p>
<p align=center><span>[</span><span>图<span>-3]</span></span></p>
<p align=left><span>现在我们来看看这些方格。写字母的方格里，<span>G = 10</span>。这是因为它只在水平方向偏离起始格一个格距。紧邻起始格的上方，下方和左边的方格的<span>G</span>值都等于。对角线方向的<span>G</span>值是。</span></p>
<p align=left><span>H</span><span>值通过求解到红色目标格的曼哈顿距离得到，其中只在水平和垂直方向移动，并且忽略中间的墙。用这种方法，起点右侧紧邻的方格离红色方格有格距离，<span>H</span>值就是。这块方格上方的方格有格距离<span>(</span>记住，只能在水平和垂直方向移动<span>)</span>，<span>H</span>值是。你大致应该知道如何计算其他方格的<span>H</span>值了～。每个格子的<span>F</span>值，还是简单的由<span>G</span>和<span>H</span>相加得到</span></p>
<p align=center><strong><span>继续搜索</span></strong></p>
<p align=left><span>为了继续搜索，我们简单的从开启列表中选择<span>F</span>值最低的方格。然后，对选中的方格做如下处理：</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>4</span><span>，把它从开启列表中删除，然后添加到关闭列表中。</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>5</span><span>，检查所有相邻格子。跳过那些已经在关闭列表中的或者不可通过的<span>(</span>有墙，水的地形，或者其他无法通过的地形<span>)</span>，把他们添加进开启列表，如果他们还不在里面的话。把选中的方格作为新的方格的父节点。</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>6</span><span>，如果某个相邻格已经在开启列表里了，检查现在的这条路径是否更好。换句话说，检查如果我们用新的路径到达它的话，<span>G</span>值是否会更低一些。如果不是，那就什么都不做。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>另一方面，如果新的<span>G</span>值更低，那就把相邻方格的父节点改为目前选中的方格（在上面的图表中，把箭头的方向改为指向这个方格）。最后，重新计算<span>F</span>和<span>G</span>的值。如果这看起来不够清晰，你可以看下面的图示。</span></p>
<p align=left><span>好了，让我们看看它是怎么运作的。我们最初的格方格中，在起点被切换到关闭列表中后，还剩格留在开启列表中。这里面，<span>F</span>值最低的那个是起始格右侧紧邻的格子，它的<span>F</span>值是。因此我们选择这一格作为下一个要处理的方格。在紧随的图中，它被用蓝色突出显示。</span></p>
<p align=center><img style="WIDTH: 392px; HEIGHT: 385px" height=385 alt="" src="http://www.cppblog.com/images/cppblog_com/mythit/4.jpg" width=392 border=0></p>
<p align=center><span>[</span><span>图<span>-4]</span></span></p>
<p align=left><span>首先，我们把它从开启列表中取出，放入关闭列表<span>(</span>这就是他被蓝色突出显示的原因<span>)</span>。然后我们检查相邻的格子。哦，右侧的格子是墙，所以我们略过。左侧的格子是起始格。它在关闭列表里，所以我们也跳过它。</span></p>
<p align=left><span>其他格已经在开启列表里了，于是我们检查<span>G</span>值来判定，如果通过这一格到达那里，路径是否更好。我们来看选中格子下面的方格。它的<span>G</span>值是。如果我们从当前格移动到那里，<span>G</span>值就会等于<span>(</span>到达当前格的<span>G</span>值是，移动到上面的格子将使得<span>G</span>值增加<span>)</span>。因为<span>G</span>值大于，所以这不是更好的路径。如果你看图，就能理解。与其通过先水平移动一格，再垂直移动一格，还不如直接沿对角线方向移动一格来得简单。</span></p>
<p align=left><span>当我们对已经存在于开启列表中的个临近格重复这一过程的时候，我们发现没有一条路径可以通过使用当前格子得到改善，所以我们不做任何改变。既然我们已经检查过了所有邻近格，那么就可以移动到下一格了。</span></p>
<p align=left><span>于是我们检索开启列表，现在里面只有<span>7</span>格了，我们仍然选择其中<span>F</span>值最低的。有趣的是，这次，有两个格子的数值都是。我们如何选择？这并不麻烦。从速度上考虑，选择最后添加进列表的格子会更快捷。这种导致了寻路过程中，在靠近目标的时候，优先使用新找到的格子的偏好。但这无关紧要。（对相同数值的不同对待，导致不同版本的<span>A*</span>算法找到等长的不同路径）那我们就选择起始格右下方的格子，如图：</span></p>
<p align=center><img style="WIDTH: 405px; HEIGHT: 290px" height=290 alt="" src="http://www.cppblog.com/images/cppblog_com/mythit/5.jpg" width=405 border=0></p>
<p align=center><span>[</span><span>图<span>-5]</span></span></p>
<p align=left><span>这次，当我们检查相邻格的时候，发现右侧是墙，于是略过。上面一格也被略过。我们也略过了墙下面的格子。为什么呢？因为你不能在不穿越墙角的情况下直接到达那个格子。你的确需要先往下走然后到达那一格，按部就班的走过那个拐角。<span>(</span>注解：穿越拐角的规则是可选的。它取决于你的节点是如何放置的。<span>)</span></span></p>
<p align=left><span>这样一来，就剩下了其他格。当前格下面的另外两个格子目前不在开启列表中，于是我们添加他们，并且把当前格指定为他们的父节点。其余格，两个已经在关闭列表中（起始格，和当前格上方的格子，在表格中蓝色高亮显示<span>),</span>于是我们略过它们。最后一格，在当前格的左侧，将被检查通过这条路径，<span>G</span>值是否更低。不必担心，我们已经准备好检查开启列表中的下一格了。</span></p>
<p align=left><span>我们重复这个过程，直到目标格被添加进关闭列表<span>(</span>注解<span>)</span>，就如在下面的图中所看到的。</span></p>
<p align=center><img height=311 alt="" src="http://www.cppblog.com/images/cppblog_com/mythit/6.jpg" width=408 border=0></p>
<p align=center><span>[</span><span>图<span>-6]</span></span></p>
<p align=left><span>注意，起始格下方格子的父节点已经和前面不同的。之前它的<span>G</span>值是，并且指向右上方的格子。现在它的<span>G</span>值是，指向它上方的格子。这在寻路过程中的某处发生，当应用新路径时，<span>G</span>值经过检查变得低了－于是父节点被重新指定，<span>G</span>和<span>F</span>值被重新计算。尽管这一变化在这个例子中并不重要，在很多场合，这种变化会导致寻路结果的巨大变化。</span></p>
<p align=left><span>那么，我们怎么确定这条路径呢？很简单，从红色的目标格开始，按箭头的方向朝父节点移动。这最终会引导你回到起始格，这就是你的路径！看起来应该像图中那样。从起始格<span>A</span>移动到目标格<span>B</span>只是简单的从每个格子（节点）的中点沿路径移动到下一个，直到你到达目标点。就这么简单。</span></p>
<p align=center><img height=312 alt="" src="http://www.cppblog.com/images/cppblog_com/mythit/7.jpg" width=415 border=0></p>
<p align=center><span>[</span><span>图<span>-7]</span></span></p>
<p align=center><strong><span>A*</span></strong><strong><span>方法总结</span></strong></p>
<p align=left><span>好，现在你已经看完了整个说明，让我们把每一步的操作写在一起：</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>1</span><span>，把起始格添加到开启列表。</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>2</span><span>，重复如下的工作：</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>a) </span><span>寻找开启列表中<span>F</span>值最低的格子。我们称它为当前格。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>b) </span><span>把它切换到关闭列表。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>c) </span><span>对相邻的格中的每一个？</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>* </span><span>如果它不可通过或者已经在关闭列表中，略过它。反之如下。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>* </span><span>如果它不在开启列表中，把它添加进去。把当前格作为这一格的父节点。记录这一格的<span>F,G,</span>和<span>H</span>值。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>* </span><span>如果它已经在开启列表中，用<span>G</span>值为参考检查新的路径是否更好。更低的<span>G</span>值意味着更好的路径。如果是这样，就把这一格的父节点改成当前格，并且重新计算这一格的<span>G</span>和<span>F</span>值。如果你保持你的开启列表按<span>F</span>值排序，改变之后你可能需要重新对开启列表排序。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>d) </span><span>停止，当你</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>* </span><span>把目标格添加进了关闭列表<span>(</span>注解<span>)</span>，这时候路径被找到，或者</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>* </span><span>没有找到目标格，开启列表已经空了。这时候，路径不存在。</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>3.</span><span>保存路径。从目标格开始，沿着每一格的父节点移动直到回到起始格。这就是你的路径。</span></p>
<p align=left>&nbsp;</p>
<p align=left><span>(</span><span>注解<span>:</span>在这篇文章的较早版本中，建议的做法是当目标格（或节点）被加入到开启列表，而不是关闭列表的时候停止寻路。这么做会更迅速，而且几乎总是能找到最短的路径，但不是绝对的。当从倒数第二个节点到最后一个（目标节点）之间的移动耗费悬殊很大时－例如刚好有一条河穿越两个节点中间，这时候旧的做法和新的做法就会有显著不同。<span>)</span></span></p>
<p align=left>&nbsp;</p>
<p align=center><strong><span>题外话</span></strong></p>
<p align=left><span>离题一下，见谅，值得一提的是，当你在网上或者相关论坛看到关于<span>A*</span>的不同的探讨，你有时会看到一些被当作<span>A*</span>算法的代码而实际上他们不是。要使用<span>A*</span>，你必须包含上面讨论的所有元素－－特定的开启和关闭列表，用<span>F,G</span>和<span>H</span>作路径评价。有很多其他的寻路算法，但他们并不是<span>A*</span>，<span>A*</span>被认为是他们当中最好的。<span>Bryan Stout</span>在这篇文章后面的参考文档中论述了一部分，包括他们的一些优点和缺点。有时候特定的场合其他算法会更好，但你必须很明确你在作什么。好了，够多的了。回到文章。</span></p>
<p align=left>&nbsp;</p>
<p align=center><strong><span>实现的注解</span></strong></p>
<p align=left><span>现在你已经明白了基本原理，写你的程序的时候还得考虑一些额外的东西。下面这些材料中的一些引用了我用<span>C++</span>和<span>Blitz Basic</span>写的程序，但对其他语言写的代码同样有效。</span></p>
<p align=left><span>1.</span><span>其他单位<span>(</span>避免碰撞<span>)</span>：如果你恰好看了我的例子代码，你会发现它完全忽略了其他单位。我的寻路者事实上可以相互穿越。取决于具体的游戏，这也许可以，也许不行。如果你打算考虑其他单位，希望他们能互相绕过，我建议你只考虑静止或那些在计算路径时临近当前单位的单位，把它们当前的位置标志为可通过的。对于临近的运动着的单位，你可以通过惩罚它们各自路径上的节点，来鼓励这些寻路者找到不同的路径<span>(</span>更多的描述见<span>#2).</span></span></p>
<p align=left><span>如果你选择了把其他正在移动并且远离当前寻路单位的那些单位考虑在内，你将需要实现一种方法及时预测在何时何地碰撞可能会发生，以便恰当的避免。否则你极有可能得到一条怪异的路径，单位突然转弯试图避免和一个已经不存在的单位发生碰撞。</span></p>
<p align=left><span>当然，你也需要写一些碰撞检测的代码，因为无论计算的时候路径有多完美，它也会因时间而改变。当碰撞发生时，一个单位必须寻找一条新路径，或者，如果另一个单位正在移动并且不是正面碰撞，在继续沿当前路径移动之前，等待那个单位离开。</span></p>
<p align=left><span>这些提示大概可以让你开始了。如果你想了解更多，这里有些你可能会觉得有用的链接：</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>*</span><span>自治角色的指导行为：<span>Craig Reynold</span>在指导能力上的工作和寻路有些不同，但是它可以和寻路整合从而形成更完整的移动和碰撞检测系统。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>*</span><span>电脑游戏中的长短距指导：指导和寻路方面著作的一个有趣的考察。这是一个<span>pdf</span>文件。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>*</span><span>协同单位移动：一个两部分系列文章的第一篇，内容是关于编队和基于分组的移动，作者是帝国时代<span>(Age of Empires)</span>的设计者<span>Dave Pottinger.</span></span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>*</span><span>实现协同移动：<span>Dave Pottinger</span>文章系列的第二篇。</span></p>
<p align=left><span>2. </span><span>不同的地形损耗：在这个教程和我附带的程序中，地形只能是二者之－可通过的和不可通过的。但是你可能会需要一些可通过的地形，但是移动耗费更高－沼泽，小山，地牢的楼梯，等等。这些都是可通过但是比平坦的开阔地移动耗费更高的地形。类似的，道路应该比自然地形移动耗费更低。</span></p>
<p align=left><span>这个问题很容易解决，只要在计算任何地形的<span>G</span>值的时候增加地形损耗就可以了。简单的给它增加一些额外的损耗就可以了。由于<span>A*</span>算法已经按照寻找最低耗费的路径来设计，所以很容易处理这种情况。在我提供的这个简单的例子里，地形只有可通过和不可通过两种，<span>A*</span>会找到最短，最直接的路径。但是在地形耗费不同的场合，耗费最低的路径也许会包含很长的移动距离－就像沿着路绕过沼泽而不是直接穿过它。</span></p>
<p align=left><span>一种需额外考虑的情况是被专家称之为</span><span>&#8220;</span><span>influence mapping</span><span>&#8221;</span><span>的东西（暂译为影响映射图）。就像上面描述的不同地形耗费一样，你可以创建一格额外的分数系统，并把它应用到寻路的<span>AI</span>中。假设你有一张有大批寻路者的地图，他们都要通过某个山区。每次电脑生成一条通过那个关口的路径，它就会变得更拥挤。如果你愿意，你可以创建一个影响映射图对有大量屠杀事件的格子施以不利影响。这会让计算机更倾向安全些的路径，并且帮助它避免总是仅仅因为路径短<span>(</span>但可能更危险<span>)</span>而持续把队伍和寻路者送到某一特定路径。</span></p>
<p align=left><span>另一个可能得应用是惩罚周围移动单位路径上得节点。<span>A*</span>的一个底限是，当一群单位同时试图寻路到接近的地点，这通常会导致路径交叠。以为一个或者多个单位都试图走相同或者近似的路径到达目的地。对其他单位已经</span><span>&#8220;</span><span>认领</span><span>&#8221;</span><span>了的节点增加一些惩罚会有助于你在一定程度上分离路径，降低碰撞的可能性。然而，如果有必要，不要把那些节点看成不可通过的，因为你仍然希望多个单位能够一字纵队通过拥挤的出口。同时，你只能惩罚那些临近单位的路径，而不是所有路径，否则你就会得到奇怪的躲避行为例如单位躲避路径上其他已经不在那里的单位。还有，你应该只惩罚路径当前节点和随后的节点，而不应处理已经走过并甩在身后的节点。</span></p>
<p align=left><span>3. </span><span>处理未知区域：你是否玩过这样的<span>PC</span>游戏，电脑总是知道哪条路是正确的，即使它还没有侦察过地图？对于游戏，寻路太好会显得不真实。幸运的是，这是一格可以轻易解决的问题。</span></p>
<p align=left><span>答案就是为每个不同的玩家和电脑（每个玩家，而不是每个单位－－那样的话会耗费大量的内存）创建一个独立的</span><span>&#8220;</span><span>knownWalkability</span><span>&#8221;</span><span>数组，每个数组包含玩家已经探索过的区域，以及被当作可通过区域的其他区域，直到被证实。用这种方法，单位会在路的死端徘徊并且导致错误的选择直到他们在周围找到路。一旦地图被探索了，寻路就像往常那样进行。</span></p>
<p align=left><span>4. </span><span>平滑路径：尽管<span>A*</span>提供了最短，最低代价的路径，它无法自动提供看起来平滑的路径。看一下我们的例子最终形成的路径（在图）。最初的一步是起始格的右下方，如果这一步是直接往下的话，路径不是会更平滑一些吗？有几种方法来解决这个问题。当计算路径的时候可以对改变方向的格子施加不利影响，对<span>G</span>值增加额外的数值。也可以换种方法，你可以在路径计算完之后沿着它跑一遍，找那些用相邻格替换会让路径看起来更平滑的地方。想知道完整的结果，查看<span>Toward More Realistic Pathfinding</span>，一篇<span>(</span>免费，但是需要注册<span>)Marco Pinter</span>发表在<span>Gamasutra.com</span>的文章</span></p>
<p align=left><span>5. </span><span>非方形搜索区域：在我们的例子里，我们使用简单的<span>D</span>方形图。你可以不使用这种方式。你可以使用不规则形状的区域。想想冒险棋的游戏，和游戏中那些国家。你可以设计一个像那样的寻路关卡。为此，你可能需要建立一个国家相邻关系的表格，和从一个国家移动到另一个的<span>G</span>值。你也需要估算<span>H</span>值的方法。其他的事情就和例子中完全一样了。当你需要向开启列表中添加新元素的时候，不需使用相邻的格子，取而代之的是从表格中寻找相邻的国家。</span></p>
<p align=left><span>类似的，你可以为一张确定的地形图创建路径点系统，路径点一般是路上，或者地牢通道的转折点。作为游戏设计者，你可以预设这些路径点。两个路径点被认为是相邻的如果他们之间的直线上没有障碍的话。在冒险棋的例子里，你可以保存这些相邻信息在某个表格里，当需要在开启列表中添加元素的时候使用它。然后你就可以记录关联的<span>G</span>值（可能使用两点间的直线距离），<span>H</span>值（可以使用到目标点的直线距离），其他都按原先的做就可以了。<span>Amit Patel </span>写了其他方法的摘要。另一个在非方形区域搜索<span>RPG</span>地图的例子，查看我的文章<span>Two-Tiered A* Pathfinding</span>。<span>(</span>译者注：译文：<span> A*</span>分层寻路<span>)</span></span></p>
<p align=left><span>6. </span><span>一些速度方面的提示：当你开发你自己的<span>A*</span>程序，或者改写我的，你会发现寻路占据了大量的<span>CPU</span>时间，尤其是在大地图上有大量对象在寻路的时候。如果你阅读过网上的其他材料，你会明白，即使是开发了星际争霸或帝国时代的专家，这也无可奈何。如果你觉得寻路太过缓慢，这里有一些建议也许有效：</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>* </span><span>使用更小的地图或者更少的寻路者。</span></p>
<p align=left><span><span>&nbsp;&nbsp; </span>&nbsp;* </span><span>不要同时给多个对象寻路。取而代之的是把他们加入一个队列，把寻路过程分散在几个游戏周期中。如果你的游戏以周期每秒的速度运行，没人能察觉。但是当大量寻路者计算自己路径的时候<span>,</span>他们会发觉游戏速度突然变慢。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>* </span><span>尽量使用更大的地图网格。这降低了寻路中搜索的总网格数。如果你有志气，你可以设计两个或者更多寻路系统以便使用在不同场合，取决于路径的长度。这也正是专业人士的做法，用大的区域计算长的路径，然后在接近目标的时候切换到使用小格子<span>/</span>区域的精细寻路。如果你对这个观点感兴趣，查阅我的文章<span>Two-Tiered A* Pathfinding</span>。<span>(</span>译者注：译文<span>:A*</span>分层寻路<span>)</span></span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>* </span><span>使用路径点系统计算长路径，或者预先计算好路径并加入到游戏中。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>* </span><span>预处理你的地图，表明地图中哪些区域是不可到达的。我把这些区域称作</span><span>&#8220;</span><span>孤岛</span><span>&#8221;</span><span>。事实上，他们可以是岛屿或其他被墙壁包围等无法到达的任意区域。<span>A*</span>的下限是，当你告诉它要寻找通往那些区域的路径时，它会搜索整个地图，直到所有可到达的方格<span>/</span>节点都被通过开启列表和关闭列表的计算。这会浪费大量的<span>CPU</span>时间。可以通过预先确定这些区域（比如通过<span>flood-fill</span>或类似的方法<span>)</span>来避免这种情况的发生<span>,</span>用某些种类的数组记录这些信息，在开始寻路前检查它。</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>* </span><span>在一个拥挤的类似迷宫的场合，把不能连通的节点看作死端。这些区域可以在地图编辑器中预先手动指定，或者如果你有雄心壮志，开发一个自动识别这些区域的算法。给定死端的所有节点可以被赋予一个唯一的标志数字。然后你就可以在寻路过程中安全的忽略所有死端，只有当起点或者终点恰好在死端的某个节点的时候才需要考虑它们。</span></p>
<p align=left><span>7. </span><span>维护开启列表：这是<span>A*</span>寻路算法最重要的组成部分。每次你访问开启列表，你都需要寻找<span>F</span>值最低的方格。有几种不同的方法实现这一点。你可以把路径元素随意保存，当需要寻找<span>F</span>值最低的元素的时候，遍历开启列表。这很简单，但是太慢了，尤其是对长路径来说。这可以通过维护一格排好序的列表来改善，每次寻找<span>F</span>值最低的方格只需要选取列表的首元素。当我自己实现的时候，这种方法是我的首选。</span></p>
<p align=left><span>在小地图。这种方法工作的很好，但它并不是最快的解决方案。更苛求速度的<span>A*</span>程序员使用叫做二叉堆的方法，这也是我在代码中使用的方法。凭我的经验，这种方法在大多数场合会快～倍，并且在长路经上速度呈几何级数提升<span>(10</span>倍以上速度<span>)</span>。如果你想了解更多关于二叉堆的内容，查阅我的文章，<span>Using Binary Heaps in A* Pathfinding</span>。<span>(</span>译者注：译文：在<span>A*</span>寻路中使用二叉堆<span>)</span></span></p>
<p align=left><span>另一个可能的瓶颈是你在多次寻路之间清除和保存你的数据结构的方法。我个人更倾向把所有东西都存储在数组里面。虽然节点可以以面向对象的风格被动态的产生，记录和保存，我发现创建和删除对象所增加的大量时间，以及多余的管理层次减慢的整个过程的速度。但是，如果你使用数组，你需要在调用之间清理数据。这中情形你想做的最后一件事就是在寻路调用之后花点时间把一切归零，尤其是你的地图很大的时候。</span></p>
<p align=left><span>我通过使用一个叫做<span>whichList(x,y)</span>的二维数组避免这种开销，数组的每个元素表明了节点在开启列表还是在关闭列表中。尝试寻路之后，我没有清零这个数组。取而代之的是，我在新的寻路中重置<span>onClosedList</span>和<span>onOpenList</span>的数值，每次寻路两个都<span>+5</span>或者类似其他数值。这种方法，算法可以安全的跳过前面寻路留下的脏数据。我还在数组中储存了诸如<span>F,G</span>和<span>H</span>的值。这样一来，我只需简单的重写任何已经存在的值而无需被清除数组的操作干扰。将数据存储在多维数组中需要更多内存，所以这里需要权衡利弊。最后，你应该使用你最得心应手的方法。</span></p>
<p align=left><span>8. Dijkstra</span><span>的算法：尽管<span>A*</span>被认为是通常最好的寻路算法<span>(</span>看前面的</span><span>&#8220;</span><span>题外话</span><span>&#8221;</span><span>),</span><span>还是有一种另外的算法有它的可取之处<span>-Dijkstra</span>算法。<span>Dijkstra</span>算法和<span>A*</span>本质是相同的，只有一点不同，就是<span>Dijkstra</span>算法没有启发式<span>(H</span>值总是<span>)</span>。由于没有启发式，它在各个方向上平均搜索。正如你所预料，由于<span>Dijkstra</span>算法在找到目标前通常会探索更大的区域，所以一般会比<span>A*</span>更慢一些。</span></p>
<p align=left><span>那么为什么要使用这种算法呢？因为有时候我们并不知道目标的位置。比如说你有一个资源采集单位，需要获取某种类型的资源若干。它可能知道几个资源区域，但是它想去最近的那个。这种情况，<span>Dijkstra</span>算法就比<span>A*</span>更适合，因为我们不知道哪个更近。用<span>A*</span>，我们唯一的选择是依次对每个目标许路并计算距离，然后选择最近的路径。我们寻找的目标可能会有不计其数的位置，我们只想找其中最近的，而我们并不知道它在哪里，或者不知道哪个是最近的。</span></p>
<p align=left><span><span><br>&nbsp; </p>
<p align=left><span>看完上面的介绍，再来看一个比较经典的题目<span>:knight moves</span>。貌似也叫汉密尔顿路径，具体的我也不记得了。对这个问题我用<span>A*</span>算法来求解，正所谓光说不练是没有用的<br></span></p>
<p align=left><a href="http://acm.pku.edu.cn/JudgeOnline/problem?id=2243"><span style="COLOR: #0000ff"><u>http://acm.pku.edu.cn/JudgeOnline/problem?id=2243</u></span></a><br>problem statement</p>
<p align=left><span>A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.<br>Of course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part. </span></p>
<p align=left><span>Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.</span><span> </span></p>
<p align=left><strong><span>Input Specification</span></strong><strong></strong></p>
<p align=left><span>The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard. </span></p>
<p align=left><strong><span>Output Specification</span></strong><strong></strong></p>
<p align=left><span>For each test case, print one line saying "To get from xx to yy takes n knight moves.". </span></p>
<p align=left><strong><span>Sample Input</span></strong><strong></strong></p>
<p align=left><span>e2 e4</span></p>
<p align=left><span>a1 b2</span></p>
<p align=left><span>b2 c3</span></p>
<p align=left><span>a1 h8</span></p>
<p align=left><span>a1 h7</span></p>
<p align=left><span>h8 a1</span></p>
<p align=left><span>b1 c3</span></p>
<p align=left><span>f6 f6 </span></p>
<p align=left><strong><span>Sample Output</span></strong><strong></strong></p>
<p align=left><span>To get from e2 to e4 takes 2 knight moves.</span></p>
<p align=left><span>To get from a1 to b2 takes 4 knight moves.</span></p>
<p align=left><span>To get from b2 to c3 takes 2 knight moves.</span></p>
<p align=left><span>To get from a1 to h8 takes 6 knight moves.</span></p>
<p align=left><span>To get from a1 to h7 takes 5 knight moves.</span></p>
<p align=left><span>To get from h8 to a1 takes 6 knight moves.</span></p>
<p align=left><span>To get from b1 to c3 takes 1 knight moves.</span></p>
<p align=left><span>To get from f6 to f6 takes 0 knight moves.<br></span><span>题目的意思大概是说：</span><span>在国际象棋的棋盘上，一匹马共有</span><span>8</span><span>个可能的跳跃方向，求从起点到目标点之间的最少跳跃次数。<br>A* code:<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">queue</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000">&nbsp;std;<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;knight{<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;x,y,step;<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;g,h,f;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">operator</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;knight&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;k)&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">重载比较运算符</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;f&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;k.f;<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">}k;<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;visited[</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">][</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">已访问标记(关闭列表)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;x1,y1,x2,y2,ans;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">起点(x1,y1),终点(x2,y2),最少移动次数ans</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;dirs[</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">][</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">{{</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">},{</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">},{</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">},{</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">},{</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">},{</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">},{</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">},{</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">}};</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">8个移动方向</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">priority_queue</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">knight</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;que;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">最小优先级队列(开启列表)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;knight&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;a){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">判断knight是否在棋盘内</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(a.x</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;a.y</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;a.x</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;a.y</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;Heuristic(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;knight&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">a){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">manhattan估价函数</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;(abs(a.x</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">x2)</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">abs(a.y</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">y2))</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Astar(){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">A*算法</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">26</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;knight&nbsp;t,s;<br></span><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">que.empty()){<br></span><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">que.top(),que.pop(),visited[t.x][t.y]</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">29</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(t.x</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">x2&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;t.y</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">y2){<br></span><span style="COLOR: #008080">30</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ans</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">t.step;<br></span><span style="COLOR: #008080">31</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">32</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">33</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">){<br></span><span style="COLOR: #008080">34</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.x</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">t.x</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">dirs[i][</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">],s.y</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">t.y</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">dirs[i][</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">];<br></span><span style="COLOR: #008080">35</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">(s)&nbsp;</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">visited[s.x][s.y]){<br></span><span style="COLOR: #008080">36</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.g&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;t.g&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">23</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">23表示根号5乘以10再取其ceil</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">37</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.h&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Heuristic(s);<br></span><span style="COLOR: #008080">38</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.f&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;s.g&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;s.h;<br></span><span style="COLOR: #008080">39</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.step&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;t.step&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">40</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;que.push(s);<br></span><span style="COLOR: #008080">41</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">42</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">43</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">44</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">45</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main(){<br></span><span style="COLOR: #008080">46</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;line[</span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">];<br></span><span style="COLOR: #008080">47</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(gets(line)){<br></span><span style="COLOR: #008080">48</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x1</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">line[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">a</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">,y1</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">line[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">,x2</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">line[</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">a</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">,y2</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">line[</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">49</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(visited,</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">,</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(visited));<br></span><span style="COLOR: #008080">50</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k.x</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">x1,k.y</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">y1,k.g</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">k.step</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,k.h</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">Heuristic(k),k.f</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">k.g</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">k.h;<br></span><span style="COLOR: #008080">51</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">que.empty())&nbsp;que.pop();<br></span><span style="COLOR: #008080">52</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;que.push(k);<br></span><span style="COLOR: #008080">53</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Astar();<br></span><span style="COLOR: #008080">54</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">To&nbsp;get&nbsp;from&nbsp;%c%c&nbsp;to&nbsp;%c%c&nbsp;takes&nbsp;%d&nbsp;knight&nbsp;moves.\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,line[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">],line[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">],line[</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">],line[</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">],ans);<br></span><span style="COLOR: #008080">55</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">56</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">57</span>&nbsp;<span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">58</span>&nbsp;</div>
</span></span></span>
<img src ="http://www.cppblog.com/Walker/aggbug/80564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-20 20:29 <a href="http://www.cppblog.com/Walker/articles/80564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Debug函数的实现（转）</title><link>http://www.cppblog.com/Walker/articles/80471.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Sun, 19 Apr 2009 13:04:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/80471.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/80471.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/80471.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/80471.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/80471.html</trackback:ping><description><![CDATA[&nbsp;#define DBGPRT(fmt,args...) \<br>&nbsp;&nbsp; do{ \<br>&nbsp;&nbsp;&nbsp; FILE* fp= fopen("/home/debug.log","a+"); \<br>&nbsp;&nbsp;&nbsp; if( fp != NULL ) \<br>&nbsp;&nbsp;&nbsp; { \<br>&nbsp;&nbsp;&nbsp;&nbsp; fprintf(fp," \n %s(%d)-%s: \n",__FILE__,__LINE__,__FUNCTION__); \<br>&nbsp;&nbsp;&nbsp;&nbsp; fprintf(fp,fmt,##args); \<br>&nbsp;&nbsp;&nbsp;&nbsp; fclose(fp); \<br>&nbsp;&nbsp;&nbsp;&nbsp; } \<br>&nbsp;&nbsp; }while(0);
<img src ="http://www.cppblog.com/Walker/aggbug/80471.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-19 21:04 <a href="http://www.cppblog.com/Walker/articles/80471.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 函数指针与软件设计</title><link>http://www.cppblog.com/Walker/articles/80469.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Sun, 19 Apr 2009 12:49:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/80469.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/80469.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/80469.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/80469.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/80469.html</trackback:ping><description><![CDATA[<p style="TEXT-INDENT: 2em">记得刚开始工作时，一位高手告诉我，说，longjmp和setjmp玩得不熟，就不要自称为C语言高手。当时我半信半疑，为了让自己向高手方向迈进，还是花了一点时间去学习longjmp和setjmp的用法。后来明白那不单是跳来跳去那样简单，而是一种高级的异常处理机制，在某些情况下确实很有用。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">为了显示自己的技巧，也在自己的程序中用过几次。渐渐发现这样的技巧带来的好处是有代价的，破坏了程序的结构化设计，程序变得很难读，尤其对新手来说。终于明白这种技巧不过是一种调味料，在少数情况使用几次，可以简化对问题的处理。如果把调味拿来当饭吃，一定会本末倒置，写出的程序会呈现营养不良之状。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">事实上，longjmp和setjmp玩得熟不熟与是不是C语言高手，不是因果关系。但是，如果可以套用那位高手的话，我倒想说如果函数指针玩得不熟，就不要自称为C语言高手。为什么这么说呢，函数指针有那么复杂吗？当然不是，任何一个稍有编程常识的人，不管他懂不懂C语言，在10分钟内，我想他一定可以明白C语言中的函数指针是怎么回事。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">原因在于，难的不是函数指针的概念和语法本身，而是在什么时候，什么地方该使用它。函数指针不仅是语法上的问题，更重要的是它是一个设计范畴。真正的高手当然不单应该懂得语法层面上的技巧，更应该懂得设计上的方法。不懂设计，能算高手吗？怀疑我在夸大其辞吗？那我们先看看函数指针与哪些设计方法有关：</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em"><strong>与分层设计有关。</strong>分层设计早就不是什么新的概念，分层的好处是众所周知的，比较明显好处就是简化复杂度、隔离变化。采用分层设计，每层都只需关心自己的东西，这减小了系统的复杂度，层与层之间的交互仅限于一个很窄的接口，只要接口不变，某一层的变化不会影响其它层，这隔离了变化。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">分层的一般原则是，上层可以直接调用下层的函数，下层则不能直接调用上层的函数。这句话说来简单，在现实中，下层常常要反过来调用上层的函数。比如你在拷贝文件时，在界面层调用一个拷贝文件函数。界面层是上层，拷贝文件函数是下层，上层调用下层，理所当然。但是如果你想在拷贝文件时还要更新进度条，问题就来了。一方面，只有拷贝文件函数才知道拷贝的进度，但它不能去更新界面的进度条。另外一方面，界面知道如何去更新进度条，但它又不知道拷贝的进度。怎么办？常见的做法，就是界面设置一个回调函数给拷贝文件函数，拷贝文件函数在适当的时候调用这个回调函数来通知界面更新状态。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em"><strong>与抽象有关。</strong>抽象是面向对象中最重要的概念之一，也是面向对象威力强大之处。面向对象只是一种思想，大家都知道，用C语言一样可以实现面向对象的编程。这可不是为了赶时髦，而是一种实用的方法。如果你对此表示怀疑，可以去看看GTK+、linux kernel等开源代码。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">接口是最高级的抽象。在linux kernel里面，接口的概念无处不在，像虚拟文件系统(VFS)，它定义一个文件系统的接口，只要按照这种接口的规范，你可以自己开发一个文件系统挂上去。设备驱动程序更是如此，不同的设备驱动程序有自己一套不同的接口规范。在自己开发设备开发驱动程序时，只要遵循相应的接口规范就行了。接口在C语言中如何表示？很简单，就是一组函数指针。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em"><strong>与接口与实现分开有关</strong>。针对接口编程，而不是针对实现编程，此为《设计模式》的第一条设计准则。分开接口与实现的目标是要隔离变化。软件是变化的，如果不能把变化的东西隔离开来，导致牵一发而动全身，代价是巨大的。这是大家所不愿看到的。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">C语言既然可以实现面向对象的编程，自然可以利用设计模式来分离接口与实现。像桥接模式、策略模式、状态模式、代理模式等等，在C语言中，无一不需要利用函数指针来实现。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em"><strong>与松耦合原则有关</strong>。面向过程与面向对象相比，之所以显得苍白无力，原因之一就是它不像面向对象一样，可以直观的把现实模型映射到计算机中。面向过程讲的是层层控制，而面向对象更强调的对象间的分工合作。现实世界中的对象处于层次关系的较少，处于对等关系的居多。也就是说，对象间的交互往往是双向的。这会加强对象间的耦合性。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">耦合本身没有错，实际上耦合是必不可少的，没有耦合就没有协作，对象之间无法形成一个整体，什么事也做不了。关键在于耦合要恰当，在实现预定功能的前提下，耦合要尽可能的松散。这样，系统的一部分变化对其它部分的影响会很少。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">函数指针是解耦对象关系的最佳利器。Signal(如boost的signal和glib中的signal)机制是一个典型的例子，一个对象自身的状态可能是在变化的（或者会触发一些事件），而其它对象关心它的变化。一旦该对象有变化发生，其它对象要执行相应的操作。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">如果该对象直接去调用其它对象的函数，功能是完成了，但对象之间的耦合太紧了。如何把这种耦合降到最低呢，signal机制是很好的办法。它的原理大致如下：其它关注该对象变化的对象主动注册一个回调函数到该对象中。一旦该对象有变化发生，就调用这些回调函数通知其它对象。功能同样实现了，但它们之间的耦合度降低了。</p>
<p style="TEXT-INDENT: 2em">&nbsp;</p>
<p style="TEXT-INDENT: 2em">在C语言中，要解决以上这些问题，不采用函数指针，将是非常困难的。在编程中，如果你从没有想到用函数指针，很难想像你是一个C语言高手。</p>
<img src ="http://www.cppblog.com/Walker/aggbug/80469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-19 20:49 <a href="http://www.cppblog.com/Walker/articles/80469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> （转）经典的位运算实例</title><link>http://www.cppblog.com/Walker/articles/80466.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Sun, 19 Apr 2009 12:44:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/80466.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/80466.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/80466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/80466.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/80466.html</trackback:ping><description><![CDATA[<p>1) int型变量循环左移k次，即a=a &lt; &lt;k |a&gt;&gt;16-k&nbsp; (设sizeof(int)=16) <br>(2) int型变量a循环右移k次，即a=a&gt;&gt;k |a &lt; &lt;16-k&nbsp; (设sizeof(int)=16) <br>(3)整数的平均值 <br>对于两个整数x,y，如果用 (x+y)/2 求平均值，会产生溢出，因为 x+y 可能会大于INT_MAX，但是我们知道它们的平均值是肯定不会溢出的，我们用如下算法： <br>int average(int x, int y)&nbsp; //返回X,Y 的平均值 <br>{&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; return (x&amp;y)+((x^y)&gt;&gt;1); <br>} <br>(4)判断一个整数是不是2的幂,对于一个数 x &gt;= 0，判断他是不是2的幂 <br>boolean power2(int x) <br>{ <br>&nbsp;&nbsp;&nbsp; return ((x&amp;(x-1))==0)&amp;&amp;(x!=0)； <br>} <br>(5)不用temp交换两个整数 <br>void swap(int x , int y) <br>{ <br>&nbsp;&nbsp;&nbsp; x ^= y; <br>&nbsp;&nbsp;&nbsp; y ^= x; <br>&nbsp;&nbsp;&nbsp; x ^= y; <br>} <br>(6)计算绝对值 <br>int abs( int x ) <br>{ <br>int y ; <br>y = x &gt;&gt; 31 ; <br>return (x^y)-y ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //or: (x+y)^y <br>} <br>(7)取模运算转化成位运算 (在不产生溢出的情况下) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a % (2^n) 等价于 a &amp; (2^n - 1) <br>(8)乘法运算转化成位运算 (在不产生溢出的情况下) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a * (2^n) 等价于 a &lt; &lt; n <br>(9)除法运算转化成位运算 (在不产生溢出的情况下) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a / (2^n) 等价于 a&gt;&gt; n <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例: 12/8 == 12&gt;&gt;3 <br>(10) a % 2 等价于 a &amp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>(11) if (x == a) x= b; <br>　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else x= a; <br>　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 等价于 x= a ^ b ^ x; <br>(12) x 的 相反数 表示为 (~x+1) </p>
<p>(13)求从x位（高）到y位（低）间共有多少个1 </p>
<p>public static int FindChessNum(int x, int y, ushort k) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int re = 0; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = y; i &lt;= x; i++) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; re += ((k &gt;&gt; (i - 1)) &amp; 1); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return re; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>(14)<br>/*将32位数分解为4个8位数处理后再合成32位数返回*/<br>DWORD GetDW(DWORD dw)<br>{<br>&nbsp;DWORD dwRet=0;<br>&nbsp;if (dw!=0)<br>&nbsp;{<br>&nbsp;&nbsp;BYTE b1=(dw&gt;&gt;24)&amp;0xff,b2=(dw&gt;&gt;16)&amp;0xff,b3=(dw&gt;&gt;8)&amp;0xff,b4=dw&amp;0xff;<br>&nbsp;&nbsp;//分别处理 b1,b2,b3,b4<br>&nbsp;&nbsp;dwRet=b1;<br>&nbsp;&nbsp;dwRet=(dwRet&lt;&lt;8)+b2;<br>&nbsp;&nbsp;dwRet=(dwRet&lt;&lt;8)+b3;<br>&nbsp;&nbsp;dwRet=(dwRet&lt;&lt;8)+b4;</p>
<p>&nbsp;&nbsp;return dwRet;<br>&nbsp;}<br>&nbsp;else{<br>&nbsp;&nbsp;return 0;<br>&nbsp;}<br>}<br><br><br>&nbsp;&nbsp;检测一个无符号数是不为2^n-1(^为幂)：&nbsp;&nbsp;&nbsp;x&amp;(x+1)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;将最右侧0位改为1位：&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(x+1)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;二进制补码运算公式：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;-x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;~x&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;~(x-1)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;~x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;-x-1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;-(~x)&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x+1&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;~(-x)&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x-1&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x+y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;~y&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x|y)+(x&amp;y)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x-y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;~y&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x|~y)-(~x&amp;y)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x^y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x|y)-(x&amp;y)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x|y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&amp;~y)+y&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&amp;y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(~x|y)-~x&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x==y:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~(x-y|y-x)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x!=y:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x-y|y-x&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&lt;&nbsp;&nbsp;&nbsp;y:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(x-y)^((x^y)&amp;((x-y)^x))&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&lt;=y:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(x|~y)&amp;((x^y)|~(y-x))&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&lt;&nbsp;&nbsp;&nbsp;y:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(~x&amp;y)|((~x|y)&amp;(x-y))//无符号x,y比较&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&lt;=y:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(~x|y)&amp;((x^y)|~(y-x))//无符号x,y比较&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;使用位运算的无分支代码：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;计算绝对值&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;abs(&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&gt;&gt;&nbsp;&nbsp;&nbsp;31&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;(x^y)-y&nbsp;&nbsp;&nbsp;;//or:&nbsp;&nbsp;&nbsp;(x+y)^y&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;符号函数：sign(x)&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;-1,&nbsp;&nbsp;&nbsp;x&lt;0;&nbsp;&nbsp;&nbsp;0,&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;==&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;1,&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&gt;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;sign(int&nbsp;&nbsp;&nbsp;x)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;(x&gt;&gt;31)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(unsigned(-x))&gt;&gt;31&nbsp;&nbsp;&nbsp;;//x=-2^31时失败(^为幂)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;三值比较：cmp(x,y)&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;-1,&nbsp;&nbsp;&nbsp;x&lt;y;&nbsp;&nbsp;&nbsp;0,&nbsp;&nbsp;&nbsp;x==y;&nbsp;&nbsp;&nbsp;1,&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&gt;&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;cmp(&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;x,&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;(x&gt;y)-(x-y)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;doz=x-y,&nbsp;&nbsp;&nbsp;x&gt;=y;&nbsp;&nbsp;&nbsp;0,&nbsp;&nbsp;&nbsp;x&lt;y&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;doz(int&nbsp;&nbsp;&nbsp;x,&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;d&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;d&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x-y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;d&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;((~(d^((x^y)&amp;(d^x))))&gt;&gt;31)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;max(int&nbsp;&nbsp;&nbsp;x,&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x-y)&gt;&gt;31&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;~m&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;不使用第三方交换x,y:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;1.x&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;2.x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x+y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x-y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x-y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;3.x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x-y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;y+x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;y-x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;4.x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;y-x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;y-x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x+y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;双值交换:x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;a,&nbsp;&nbsp;&nbsp;x==b;&nbsp;&nbsp;&nbsp;b,&nbsp;&nbsp;&nbsp;x==a//常规编码为x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x==a&nbsp;&nbsp;&nbsp;?&nbsp;&nbsp;&nbsp;b&nbsp;&nbsp;&nbsp;:a&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;1.x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;a+b-x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;2.x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;a^b^x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;下舍入到2的k次方的倍数:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;1.x&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;((-1)&lt;&lt;k)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;2.(((unsigned)x)&gt;&gt;k)&lt;&lt;k&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;上舍入：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;1.&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(1&lt;&lt;k)-1&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x+t)&amp;~t&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;2.t&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(-1)&lt;&lt;k&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x-t-1)&amp;t&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;位计数,统计1位的数量：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;1.&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;pop(unsigned&nbsp;&nbsp;&nbsp;x)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x-((x&gt;&gt;1)&amp;0x55555555)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&amp;0x33333333)&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;((x&gt;&gt;2)&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x33333333&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x+(x&gt;&gt;4))&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x0f0f0f0f&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;(x&gt;&gt;8)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;(x&gt;&gt;16)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x0000003f&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;2.&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;pop(unsigned&nbsp;&nbsp;&nbsp;x)&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;static&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;table[256]&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;0,1,1,2,&nbsp;&nbsp;&nbsp;1,2,2,3,&nbsp;&nbsp;&nbsp;....,&nbsp;&nbsp;&nbsp;6,7,7,8&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;table[x&amp;0xff]+table[(x&gt;&gt;8)&amp;0xff]+table[(x&gt;&gt;16)&amp;0xff]+table[(x&gt;&gt;24)]&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;奇偶性计算:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;x&gt;&gt;1&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;x&gt;&gt;2&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;x&gt;&gt;4&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;x&gt;&gt;8&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;x&gt;&gt;16&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;结果中位于x最低位，对无符号x,结果的第i位是原数第i位到最左侧位的奇偶性&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;位反转：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;rev(unsigned&nbsp;&nbsp;&nbsp;x)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x55555555)&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(x&gt;&gt;1)&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x55555555&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x33333333)&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(x&gt;&gt;2)&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x33333333&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x0f0f0f0f)&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(x&gt;&gt;4)&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x0f0f0f0f&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&lt;&lt;24)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;((x&amp;0xff00)&lt;&lt;8)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;((x&gt;&gt;8)&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0xff00)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(x&gt;&gt;24)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;递增位反转后的数：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;inc_r(unsigned&nbsp;&nbsp;&nbsp;x)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;0x80000000&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;if(&nbsp;&nbsp;&nbsp;(int)x&nbsp;&nbsp;&nbsp;&gt;=&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;do&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;&gt;&gt;=&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;while(&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&lt;&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;混选位：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;abcd&nbsp;&nbsp;&nbsp;efgh&nbsp;&nbsp;&nbsp;ijkl&nbsp;&nbsp;&nbsp;mnop&nbsp;&nbsp;&nbsp;ABCD&nbsp;&nbsp;&nbsp;EFGH&nbsp;&nbsp;&nbsp;IJKL&nbsp;&nbsp;&nbsp;MNOP-&gt;aAbB&nbsp;&nbsp;&nbsp;cCdD&nbsp;&nbsp;&nbsp;eEfF&nbsp;&nbsp;&nbsp;gGhH&nbsp;&nbsp;&nbsp;iIjJ&nbsp;&nbsp;&nbsp;kKlL&nbsp;&nbsp;&nbsp;mMnN&nbsp;&nbsp;&nbsp;oOpP&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;ps(unsigned&nbsp;&nbsp;&nbsp;x)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(x&gt;&gt;8))&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x0000ff00;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(t&lt;&lt;8)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(x&gt;&gt;4))&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x00f000f0;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(t&lt;&lt;4)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(x&gt;&gt;2))&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x0c0c0c0c;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(t&lt;&lt;2)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(x&gt;&gt;1))&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;0x22222222;&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(t&lt;&lt;1)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;位压缩：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;选择并右移字x中对应于掩码m的1位的位,如：compress(abcdefgh,01010101)=0000bdfh&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;compress_left(x,m)操作与此类似，但结果位在左边:&nbsp;&nbsp;&nbsp;bdfh0000.&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;compress(unsigned&nbsp;&nbsp;&nbsp;x,&nbsp;&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;m)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;mk,&nbsp;&nbsp;&nbsp;mp,&nbsp;&nbsp;&nbsp;mv,&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;i&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&amp;=&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mk&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;~m&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;for(&nbsp;&nbsp;&nbsp;i&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;i&nbsp;&nbsp;&nbsp;&lt;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;++i&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;mk&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;mk&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;1)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;^=&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;&lt;&lt;&nbsp;&nbsp;&nbsp;16&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mv&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;mp&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;m&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;mv&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(mv&nbsp;&nbsp;&nbsp;&gt;&gt;&nbsp;&nbsp;&nbsp;(1&lt;&lt;i)&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;mv&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;t&nbsp;&nbsp;&nbsp;&gt;&gt;&nbsp;&nbsp;&nbsp;(&nbsp;&nbsp;&nbsp;1&lt;&lt;i)&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;mk&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;mk&nbsp;&nbsp;&nbsp;&amp;&nbsp;&nbsp;&nbsp;~mp&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;位置换：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;用32个5位数表示从最低位开始的位的目标位置，结果是一个32*5的位矩阵，&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;将该矩阵沿次对角线转置后用5个32位字p[5]存放。&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;SAG(x,m)&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;compress_left(x,m)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;compress(x,~m)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;准备工作：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;init(&nbsp;&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;*p&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;p[1]&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;p[1],&nbsp;&nbsp;&nbsp;p[0]&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;p[2]&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;p[2],&nbsp;&nbsp;&nbsp;p[0]),&nbsp;&nbsp;&nbsp;p[1]&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;p[3]&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;p[3],&nbsp;&nbsp;&nbsp;p[0]&nbsp;&nbsp;&nbsp;),&nbsp;&nbsp;&nbsp;p[1]),&nbsp;&nbsp;&nbsp;p[2]&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;p[4]&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;SAG(&nbsp;&nbsp;&nbsp;p[4],&nbsp;&nbsp;&nbsp;p[0]&nbsp;&nbsp;&nbsp;),&nbsp;&nbsp;&nbsp;p[1])&nbsp;&nbsp;&nbsp;,p[2]),&nbsp;&nbsp;&nbsp;p[3]&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;实际置换：&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;rep(&nbsp;&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(x,p[0]);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(x,p[1]);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(x,p[2]);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(x,p[3]);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;SAG(x,p[4]);&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;二进制码到GRAY码的转换:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;B2G(unsigned&nbsp;&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(B&gt;&gt;1)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;GRAY码到二进制码:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;G2B(unsigned&nbsp;&nbsp;&nbsp;G)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;G&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(G&gt;&gt;1)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;G&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(G&gt;&gt;2)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;G&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(G&gt;&gt;4)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;G&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(G&gt;&gt;8)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;G&nbsp;&nbsp;&nbsp;^&nbsp;&nbsp;&nbsp;(G&gt;&gt;16)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;B&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;找出最左0字节的位置:&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;zbytel(&nbsp;&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;x&nbsp;&nbsp;&nbsp;)&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;static&nbsp;&nbsp;&nbsp;cahr&nbsp;&nbsp;&nbsp;table[16]&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;4,3,2,2,&nbsp;&nbsp;&nbsp;1,1,1,1,&nbsp;&nbsp;&nbsp;0,0,0,0,&nbsp;&nbsp;&nbsp;0,0,0,0&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;(x&amp;0x7f7f7f7f)&nbsp;&nbsp;&nbsp;+&nbsp;&nbsp;&nbsp;0x7f7f7f7f&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;y&nbsp;&nbsp;&nbsp;=&nbsp;&nbsp;&nbsp;~(y|x|0x7f7f7f7f)&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;return&nbsp;&nbsp;&nbsp;table[y*0x00204081&nbsp;&nbsp;&nbsp;&gt;&gt;&nbsp;&nbsp;&nbsp;28]&nbsp;&nbsp;&nbsp;;//乘法可用移位和加完成&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br><br><br></p>
<p>C\C++支持比较低阶的位运算，在是众人皆知的了。每本C\C++的教科书都会说到这部分的内容，不过都很简略，我想会有很多人不知道位运算用在什么地方。这个帖子就简略说说位运算的用处，更进一步的用法要大家自己去体会。而主要说的是操作标志值方面。</p>
<p>&nbsp;</p>
<p>&nbsp;/****************************************/</p>
<p>#define&nbsp;BTI_MSK(bit)&nbsp;&nbsp;&nbsp;&nbsp;(1&nbsp;&lt;&lt;&nbsp;(bit))<br>#define&nbsp;BIT_SET(x,bit)&nbsp;&nbsp;((x)&nbsp;|=&nbsp;&nbsp;BTI_MSK&nbsp;(bit))<br>#define&nbsp;BIT_CLR(x,bit)&nbsp;&nbsp;((x)&nbsp;&amp;=&nbsp;~BTI_MSK&nbsp;(bit))<br>#define&nbsp;BIT_TST(x,bit)&nbsp;&nbsp;((x)&nbsp;&amp;&nbsp;&nbsp;&nbsp;BTI_MSK&nbsp;(bit))</p>
<p>&nbsp;/****************************************/</p>
<p>&nbsp;</p>
<p>考虑一个事物、一个系统、或者一个程序可能会出现一种或者几种状态。为了在不同的状态下，作出不同的行为，你可以设立一些标志值，再根据标志值来做判断。比如C++的文件流，你就可以设定一些标志值，ios::app,&nbsp;ios::ate,&nbsp;ios::binary,&nbsp;ios::in,&nbsp;ios::out,&nbsp;ios::trunc，并且可以将它用|组合起来创建一个恰当的文件流。你可能会将这些标志值定义为bool类型，不过这样要是设置的标志值一多，就会很浪费空间。<br><br>而假如定义一个整型数值，unsigned&nbsp;int&nbsp;flags;&nbsp;在现在的系统，flags应该是32位,&nbsp;用1,2,3....32将位进行编号，我们可以进行这样的判断,&nbsp;当位1取1时，表示用读方式打开文件，当位2取1时，表示用写方式打开文件，当位3取1时，用二进制方式打开文件....因为flags有32位，就可以设置32个不同的状态值，也相当于32个bool类型。这样一方面省了空间,&nbsp;另一方面也多了个好处，就是如前面所说的，可以将标志值组合起来。<br>//&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;<br><br>好啦，上面有点不清不楚的。下面看看到底怎么操作这些标志值。<br>设想C++的类ios这样定义,&nbsp;其实没有这个类，只有ios_basic类，typedef&nbsp;basic_ios&lt;char&gt;&nbsp;ios;<br><br>class&nbsp;ios<br>{<br>public:<br>&nbsp;&nbsp;&nbsp;&nbsp;enum&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;app&nbsp;=&nbsp;0x0001,&nbsp;ate&nbsp;=&nbsp;0x0002,&nbsp;binary&nbsp;=&nbsp;0x0004,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in&nbsp;=&nbsp;0x0008,&nbsp;&nbsp;out&nbsp;=&nbsp;0x0010,&nbsp;trunc&nbsp;=&nbsp;0x0020&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;....<br>private:<br>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;int&nbsp;flags;<br>};<br><br>注意上面enum语句中，每一个数值只有1位是1，其余是0，这个很重要，你可以将它化成2进制看看。<br><br>现在将flags相应的位设置为1,&nbsp;可以这样做&nbsp;flags&nbsp;|=&nbsp;app。这个等于flags&nbsp;=&nbsp;flags&nbsp;|&nbsp;app,&nbsp;为什么呢?&nbsp;app只有1位是1，其余是0，因为0&nbsp;|&nbsp;1&nbsp;=&nbsp;0，&nbsp;0&nbsp;|&nbsp;0&nbsp;=&nbsp;0，&nbsp;这样0对应的位是不变的。而1&nbsp;|&nbsp;1&nbsp;=&nbsp;1,&nbsp;1&nbsp;|&nbsp;0&nbsp;=&nbsp;1,&nbsp;1对应的位不论原来是什么状态，都一定为1。如果想要将几个位都设置为1，可以这样做&nbsp;flags&nbsp;|=&nbsp;(app&nbsp;|&nbsp;ate&nbsp;|&nbsp;binary)。因为每个enum常数各有一位为1,&nbsp;与运算之后就有3位为1，就如上面的分析，就可以将那3位都设置为1,&nbsp;其余位不变。这个就是标志可以组合起来用的原因。也可以用+组合起来，原因在于(下面的数字是2进制)0001&nbsp;+&nbsp;0010&nbsp;+&nbsp;0100&nbsp;=&nbsp;0111&nbsp;跟与运算结果一样。不过不提倡用+,&nbsp;考虑(app&nbsp;|&nbsp;ate&nbsp;|&nbsp;binary)要是我不小心写多了个标志值，(app&nbsp;|&nbsp;ate&nbsp;|&nbsp;ate&nbsp;|&nbsp;binary)结果还是正确的，如果用+的话，就会产生进位，结果就会错误。通常我们不知道原先已经组合了多少个标志值了，用或运算会安全。<br><br>现在将flags对应的位设置为0,&nbsp;可以这样做&nbsp;flags&nbsp;&amp;=&nbsp;~app。相当于&nbsp;flags&nbsp;=&nbsp;flags&nbsp;&amp;&nbsp;(~app).&nbsp;app取反之后，只有1位是0，其余是1，做与运算之后，1对应的位并不会改变，0对应的为不管原来是1是0，都肯定为0，这样就将对应的位设置了0。同样同时设置几个标志位可以这样做，flags&nbsp;&amp;=&nbsp;~(app&nbsp;|&nbsp;ate&nbsp;|&nbsp;binary)。<br><br>现在将flags对应的位，如果是1就变成0，如果是0就变成1，可以这样做&nbsp;flags&nbsp;^=&nbsp;app。同时设置几个标志位可以写成&nbsp;flags&nbsp;^=&nbsp;(app&nbsp;|&nbsp;ate&nbsp;|&nbsp;binary)。不再做分析了，不然就太罗嗦了。不过也给大家一个例子，你查查Ascii表，会发现对应的大小写字母是相差倒数第6位，可以用这样的函数统一的将大写变成小写，小写变成大写。<br>void&nbsp;xchgUppLow(string&amp;&nbsp;letters)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;unsigned&nbsp;int&nbsp;mask&nbsp;=&nbsp;(1&lt;&lt;5);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(size_t&nbsp;i=0;&nbsp;i&lt;letters.length();&nbsp;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;letters[i]&nbsp;^=&nbsp;mask;<br>}<br>前提是输入的string一定要全是字母,&nbsp;而要想是操作字母，可以在原来基础上加个判断。<br><br>好啦，上面已经可以设置flags的对应位值了，要是判断呢？可以这样写&nbsp;if&nbsp;(flags&nbsp;&amp;&nbsp;app)&nbsp;这样可以判断对应的位值是否为1,&nbsp;因为C\C++语言中非0就真。app只有一位是1，其余是0，如果,&nbsp;flags的对应位也是0，在与操作下就得到结果0，反之非0，这样就可以判断标志位了。<br><br>//&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;<br>上面关于标志值的操作就介绍完毕。其实在C++中已经有了个bitset了，没有必要去自己进行低阶的位运算，上面的四个操作在bitset中分别叫做set,&nbsp;reset,&nbsp;flip,&nbsp;test。不过在C中，这样的代码还很常见,&nbsp;反正知道多点也没有坏处。<br><br>用&nbsp;windows&nbsp;API&nbsp;编程，你也经常会碰到这样的标志值，要互相组合，可以用|,&nbsp;也可以用+(只是建议用|，理由上面说了).&nbsp;它的标志值也是这样定义的，不过用#define<br>#define&nbsp;WS_BORDER&nbsp;&nbsp;&nbsp;&nbsp;0x0001<br>#define&nbsp;WS_CAPTION&nbsp;&nbsp;&nbsp;&nbsp;0x0002<br>......<br>当初我就是想不明白为什么可以用|或者用+来组合，现在知道了。<br><br>(注：上面出现的数字是我自己作的，到底实际怎么定义其实没有关系，只要保证只有一位是1，其余是0就可以的了.&nbsp;因为编程的时候用的是常量值，没有人这样笨去直接用数值的)<br><br>//&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;<br>其实，位运算还有很多用处。比如移位相当于乘除2的幂数(不过通常编译器也将乘除2的幂数优化成汇编的移位指令，所以没有必要不要这样卖弄了。汇编的移位指令有两组，分别针对有符号和无符号的,&nbsp;我猜想在C\C++的同一移位运算针对有符号整数和无符号整数的不同，会根据情况编译成不同的汇编移位指令，不过没有去证实),&nbsp;其实移位更用得多的地方是去构造一个掩码,&nbsp;比如上面的mask&nbsp;=&nbsp;(1&lt;&lt;5);<br><br>还有&amp;运算，有时候可以用来求余数。比如&nbsp;value&nbsp;&amp;&nbsp;(1&lt;&lt;4&nbsp;-&nbsp;1)&nbsp;这相当于将value的高位全变成0了，效果等于&nbsp;value&nbsp;%&nbsp;8.&nbsp;<br><br>还有值得一提的是^运算，它有个很特殊的性质。比如&nbsp;A&nbsp;^=&nbsp;B,&nbsp;变成另一个数，跟着再执行A&nbsp;^=&nbsp;B，又变回原来的数了，不信你可以列真值表或者化简逻辑式看看。就因为这个性质，^有很多用途。比如加密，你将原文看成A,&nbsp;用同一个B异或一次，就相当于加密，跟着在用B异或一次，相当于解密。不过这样是很容易破解就是了。要是一个B不够，还可以加个C,&nbsp;比如A&nbsp;^=&nbsp;B,&nbsp;A&nbsp;^=&nbsp;C,&nbsp;A&nbsp;^=&nbsp;C,&nbsp;A&nbsp;^=&nbsp;B,&nbsp;恢复原状。<br><br>下面一个小程序，用异或交换两个数字。<br>int&nbsp;x&nbsp;=&nbsp;3;<br>int&nbsp;y&nbsp;=&nbsp;4;<br><br>x&nbsp;^=&nbsp;y;<br>y&nbsp;^=&nbsp;x;<br>x&nbsp;^=&nbsp;y;<br><br>其实何止交换数字，连交换对象也可以的<br>template&nbsp;&lt;typename&nbsp;T&gt;<br>void&nbsp;swap(T&amp;&nbsp;obj1,&nbsp;T&amp;&nbsp;obj2)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;int&nbsp;sizeOfObj&nbsp;=&nbsp;sizeof(T);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;pt1&nbsp;=&nbsp;(char*)&amp;obj1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;pt2&nbsp;=&nbsp;(char*)&amp;obj2;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(size_t&nbsp;i=0;&nbsp;i&lt;sizeOfObj;&nbsp;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pt1[i]&nbsp;^=&nbsp;pt2[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pt2[i]&nbsp;^=&nbsp;pt1[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pt1[i]&nbsp;^=&nbsp;pt2[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br><br>还有异或操作还可以用在图象的光栅操作。我们知道，颜色也是用二进制来表示的，对颜色进行不同的位运算，就可以得到不同的光栅。因为异或的特殊性质，我们用异或操作的光栅画了副图，跟着再在原来的地方画一次，那副图就刷除了。这样可以用来显示动画而不用保存原来的画像信息。以前我写过个双人的贪食蛇，就用了异或光栅。因为背景色是白色的，也就是全1，作A&nbsp;^&nbsp;1&nbsp;=&nbsp;A,&nbsp;所以用画刷画一次是画了设定的颜色，再画一次就恢复。最有趣的是两蛇相交的时候，颜色也会作异或叠加，产生一种新的颜色了，离开的时候也会自动恢复。<br>//&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;<br>好啦，够长了，就停止吧。在最后再给大家一段代码，是用来看看对象在内存中的位值的。可以看看。<br>string&nbsp;bitsOfUChar(unsigned&nbsp;char&nbsp;c)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;int&nbsp;numOfBitsInUChar&nbsp;=&nbsp;8;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;int&nbsp;mask&nbsp;=&nbsp;(1&lt;&lt;7);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;result(8,&nbsp;'0');<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(size_t&nbsp;i=0;&nbsp;i&lt;numOfBitsInUChar;&nbsp;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;mask&nbsp;&amp;&nbsp;c)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result[i]&nbsp;=&nbsp;'1';<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mask&nbsp;&gt;&gt;=&nbsp;1;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;<br>}<br><br>template&nbsp;&lt;typename&nbsp;T&gt;<br>string&nbsp;bitsInMemory(const&nbsp;T&amp;&nbsp;obj)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;sizeOfObj&nbsp;=&nbsp;sizeof(obj);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;char*&nbsp;pt&nbsp;=&nbsp;(unsigned&nbsp;char*)&amp;obj;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;result;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(size_t&nbsp;i=0;&nbsp;i&lt;sizeOfObj;&nbsp;i++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;+=&nbsp;bitsOfUChar(pt[i]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;+=&nbsp;'&nbsp;';<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;<br>}<br><br>比如bitsInMemory(12)，会输出00001100&nbsp;00000000&nbsp;00000000&nbsp;00000000,&nbsp;我就知道我自己的机器是小尾顺序的了。<br></p>
<img src ="http://www.cppblog.com/Walker/aggbug/80466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-19 20:44 <a href="http://www.cppblog.com/Walker/articles/80466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>算法链接</title><link>http://www.cppblog.com/Walker/articles/80380.html</link><dc:creator>漫步者×&amp;……%￥</dc:creator><author>漫步者×&amp;……%￥</author><pubDate>Sat, 18 Apr 2009 11:35:00 GMT</pubDate><guid>http://www.cppblog.com/Walker/articles/80380.html</guid><wfw:comment>http://www.cppblog.com/Walker/comments/80380.html</wfw:comment><comments>http://www.cppblog.com/Walker/articles/80380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Walker/comments/commentRss/80380.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Walker/services/trackbacks/80380.html</trackback:ping><description><![CDATA[<a href="http://wz.csdn.net/tag/%e7%ae%97%e6%b3%95/2/">http://wz.csdn.net/tag/%e7%ae%97%e6%b3%95/2/</a>
<img src ="http://www.cppblog.com/Walker/aggbug/80380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Walker/" target="_blank">漫步者×&……%￥</a> 2009-04-18 19:35 <a href="http://www.cppblog.com/Walker/articles/80380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>