<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQYBI.com &#187; About Computer</title>
	<atom:link href="http://sqybi.com/blog/archives/category/about-computer/feed" rel="self" type="application/rss+xml" />
	<link>http://sqybi.com/blog</link>
	<description>Change is a part of life, and takes part in finding us who we are.</description>
	<lastBuildDate>Mon, 09 Jan 2012 13:33:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>sqybi和layla的算法课 系列文章筹备中……</title>
		<link>http://sqybi.com/blog/archives/366</link>
		<comments>http://sqybi.com/blog/archives/366#comments</comments>
		<pubDate>Sat, 05 Nov 2011 15:30:39 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[sqybi和layla的算法课]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/?p=366</guid>
		<description><![CDATA[不管什么事情，都是说起来容易，做起来难。这一点我最近是深有体会了……看着自己离100kg越来越远的体重，总觉得该做点什么了，可又总因为这样那样的原因最后什么都没做。真是失败啊。 闲话少谈。这个系列文章已经挖坑挖了好久了，一直没有能够找到机会动笔。随手翻翻blog，似乎已经有很长时间没有写有营养的文章了。上一篇大概还是PageRank那篇……或许还要更早吧，其实那篇营养也不多。 于是今天晚上下定了决心，要把这个坑填上。本来想今晚就写出第一篇的，现在看来还是有些困难。暂且列了个要讲的算法列表，当然非常概括了……可能还会有变动啥的。 这个列表基本是按照算法导论的目录来列的。仔细看了一下，列表中还是有一些算法已经快不会了，正好借这个机会重新温习一下，以后面试啥的说不定会用到。 先把提纲放出来吧。还有半小时断网，第一篇今晚是发不出来了。可以考虑明天早起赶完，嗯。 其实真的早就该填这个坑了，layla你估计都等急了吧…… ----- 数据结构 栈和队列，数组和链表 树和二叉树 二叉查找树 平衡二叉树 散列表 排序算法 选择排序、冒泡排序和快速排序（希尔排序？） 堆和堆排序 计数排序、基数排序和桶排序 搜索算法、贪心算法和动态规划 深度优先搜索和广度优先搜索 搜索时的剪枝 贪心算法和赫夫曼编码 动态规划（分成几次？） 图论 拓扑排序 强联通分量 最小生成树 单源最短路 二分图匹配 网络流 其它算法 数学算法（黑书31章） 字符串匹配和自动机 计算几何学（凸包和最近/最远点对） 后缀树和后缀数组]]></description>
			<content:encoded><![CDATA[<p>不管什么事情，都是说起来容易，做起来难。这一点我最近是深有体会了……看着自己离100kg越来越远的体重，总觉得该做点什么了，可又总因为这样那样的原因最后什么都没做。真是失败啊。</p>
<p>闲话少谈。这个系列文章已经挖坑挖了好久了，一直没有能够找到机会动笔。随手翻翻blog，似乎已经有很长时间没有写有营养的文章了。上一篇大概还是PageRank那篇……或许还要更早吧，其实那篇营养也不多。</p>
<p>于是今天晚上下定了决心，要把这个坑填上。本来想今晚就写出第一篇的，现在看来还是有些困难。暂且列了个要讲的算法列表，当然非常概括了……可能还会有变动啥的。<br />
这个列表基本是按照算法导论的目录来列的。仔细看了一下，列表中还是有一些算法已经快不会了，正好借这个机会重新温习一下，以后面试啥的说不定会用到。</p>
<p>先把提纲放出来吧。还有半小时断网，第一篇今晚是发不出来了。可以考虑明天早起赶完，嗯。</p>
<p>其实真的早就该填这个坑了，layla你估计都等急了吧……</p>
<p>-----</p>
<pre>数据结构
  栈和队列，数组和链表
  树和二叉树
  二叉查找树
  平衡二叉树
  散列表
排序算法
  选择排序、冒泡排序和快速排序（希尔排序？）
  堆和堆排序
  计数排序、基数排序和桶排序
搜索算法、贪心算法和动态规划
  深度优先搜索和广度优先搜索
  搜索时的剪枝
  贪心算法和赫夫曼编码
  动态规划（分成几次？）
图论
  拓扑排序
  强联通分量
  最小生成树
  单源最短路
  二分图匹配
  网络流
其它算法
  数学算法（黑书31章）
  字符串匹配和自动机
  计算几何学（凸包和最近/最远点对）
  后缀树和后缀数组</pre>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/366/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Help! My Archlinux (my Gnome 3) crashed!</title>
		<link>http://sqybi.com/blog/archives/365</link>
		<comments>http://sqybi.com/blog/archives/365#comments</comments>
		<pubDate>Sun, 16 Oct 2011 09:38:00 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[Technology]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/?p=365</guid>
		<description><![CDATA[今天Gnome 3崩了。。。不得已上来求救一下。。。 写一下崩的过程，希望写得还算清楚，不会乱七八糟。。。 崩的过程是，我用gnome-tweak-tool修改主题（是有某个选项卡，上面基本上所有的选项都是修改主题相关的，比如修改icon等等，那一页上的第一个选项）。 刚开始的主题是默认主题Adwaita，后来改成了某个主题（忘了是哪个了），Alt+F2，r，回车，一切正常。 再后来又改了，似乎是Atlanta，然后Alt+F2，r，回车，然后弹出提示告诉我gnome崩溃了，然后有一个选项（没有仔细看，记不清选项是什么了）和一个重启的按钮。 我没动那个选项，直接点了按钮重启。结果重启之后，gdm登陆的部分没有问题，但是进了gnome shell，显示出桌面壁纸就卡住了。状态栏什么的都没有显示，快捷键也都没有作用（至少我试过的都没有作用，比如Alt+F2，Win，以及自己设置的Alt+F3等），不过Ctrl+Alt+Fn切换控制台有效果。 然后尝试解决。最开始想通过修改配置文件把主题改回来，不过找了好久也没找到配置文件。Arch的wiki上有一段关于怎么修改配置文件换主题的介绍，但是可惜的是，我压根就找不到那个文件。 又找了找改主题的方法，所有介绍中基本都是图形界面的程序。有个gnomesettings神马的（名字肯定不是这个，记不清楚了），但是里面找不到theme相关的内容。 之后在/usr/share/themes/文件夹下看到了许多以主题名字命名的文件夹，尝试把Atlanta主题下的文件用Adwaita下的替换，还是不起作用。 再之后卸载gnome（pacman -Rc gnome），重启，重新安装gnome和gdm，问题依旧。 现在的问题就是这样，虽然我觉得最开始的时候大概只要把主题换回来就没有问题了，不过现在这个方法不一定还可行（毕竟已经重新装过gnome了）。这里需要求助的是： 1.如果有人经历过这个问题，求解决方案。 2.如果有人知道怎么在命令行下面改主题 ，求方法。 3.如果有人知道这个问题是解决不了的，也请告诉我，我直接重装。。。 多谢各位！ update: 问题已经解决，方法是备份后删除所有配置文件，然后再将有用的配置文件移回。感谢lx各位以及人人上各位的帮助！]]></description>
			<content:encoded><![CDATA[<p>今天Gnome 3崩了。。。不得已上来求救一下。。。<br />
写一下崩的过程，希望写得还算清楚，不会乱七八糟。。。</p>
<p>崩的过程是，我用gnome-tweak-tool修改主题（是有某个选项卡，上面基本上所有的选项都是修改主题相关的，比如修改icon等等，那一页上的第一个选项）。<br />
刚开始的主题是默认主题Adwaita，后来改成了某个主题（忘了是哪个了），Alt+F2，r，回车，一切正常。<br />
再后来又改了，似乎是Atlanta，然后Alt+F2，r，回车，然后弹出提示告诉我gnome崩溃了，然后有一个选项（没有仔细看，记不清选项是什么了）和一个重启的按钮。<br />
我没动那个选项，直接点了按钮重启。结果重启之后，gdm登陆的部分没有问题，但是进了gnome shell，显示出桌面壁纸就卡住了。状态栏什么的都没有显示，快捷键也都没有作用（至少我试过的都没有作用，比如Alt+F2，Win，以及自己设置的Alt+F3等），不过Ctrl+Alt+Fn切换控制台有效果。</p>
<p>然后尝试解决。最开始想通过修改配置文件把主题改回来，不过找了好久也没找到配置文件。Arch的wiki上有一段关于怎么修改配置文件换主题的介绍，但是可惜的是，我压根就找不到那个文件。<br />
又找了找改主题的方法，所有介绍中基本都是图形界面的程序。有个gnomesettings神马的（名字肯定不是这个，记不清楚了），但是里面找不到theme相关的内容。<br />
之后在/usr/share/themes/文件夹下看到了许多以主题名字命名的文件夹，尝试把Atlanta主题下的文件用Adwaita下的替换，还是不起作用。<br />
再之后卸载gnome（pacman -Rc gnome），重启，重新安装gnome和gdm，问题依旧。</p>
<p>现在的问题就是这样，虽然我觉得最开始的时候大概只要把主题换回来就没有问题了，不过现在这个方法不一定还可行（毕竟已经重新装过gnome了）。这里需要求助的是：<br />
1.如果有人经历过这个问题，求解决方案。<br />
2.如果有人知道怎么在命令行下面改主题 ，求方法。<br />
3.如果有人知道这个问题是解决不了的，也请告诉我，我直接重装。。。</p>
<p>多谢各位！</p>
<p><span style="color: #ff0000;">update: 问题已经解决，方法是备份后删除所有配置文件，然后再将有用的配置文件移回。感谢lx各位以及人人上各位的帮助！</span></p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/365/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>你的网站价值几何？让PageRank告诉你答案</title>
		<link>http://sqybi.com/blog/archives/359</link>
		<comments>http://sqybi.com/blog/archives/359#comments</comments>
		<pubDate>Tue, 27 Sep 2011 10:35:34 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[About Science]]></category>
		<category><![CDATA[[Technology]]]></category>
		<category><![CDATA[[果壳网约稿]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/archives/359</guid>
		<description><![CDATA[本文同时发表在果壳网死理性派栏目，传送门：http://www.guokr.com/article/65304/。因为字数原因，所以编辑对死理性派上发表的文章进行了一定的删减和修正。这里发出的是未删减的版本，表示“太理性了，看不懂”的童鞋们可以来围观此文。 如果你安装过Google工具栏，如果你建立过独立博客或个人网站，那么你肯定和PageRank打过照面。而即使是从未考虑建站的读者，也有很大一部分听说过PageRank，毕竟作为Google搜索结果排序的重要依据[1]，这个算法已经被广泛应用于网络的每一个角落。而PageRank值的大小，也早已与网站的SEO[2]成功与否紧密相连。 那么PageRank的名称从何而来？PageRank究竟如何准确表示网页重要度，它的算法又是如何高效准确运行的呢？在PageRank的背后，有什么数学理论的支持？且听笔者为您一一道来。 三个孩子和豌豆游戏 从前有一个死理性派老爸，他有三个孩子。老爸是个懒人，他在家里把三个孩子叫做老大、老二和老三。 一天，三个孩子正在玩游戏，老爸把他们叫到身边。“我这里有三十颗豌豆，”老爸说，“我们来用它们玩一个游戏，游戏结束之后按照游戏结果把豌豆分给你们，好不好啊？” “好！”三个孩子异口同声地答应了。 “你们先在这张纸上写下你们喜欢的人，如果你认为另外两个兄弟你都很喜欢，那就把两个人的名字都写下来。比如我知道老二很喜欢老大，那么老二就在纸上写老大的名字。” 三个孩子很快写好了，然后老爸把纸收了上来。老大的纸上写了老二和老三的名字，而老二写了老大，老三写了老二。三个人互相喜欢的结果如图： 老爸清了一下嗓子，继续向孩子们解释规则：“接下来，我会给你们每个人分十颗豌豆。桌上有三个盘子，分别代表你们三个人，豌豆都放在盘子里。在我喊‘预备’的时候，你们要把盘子里的豌豆全都拿到手里。在我喊‘开始’的时候，你们要把手里的豌豆全部平均分给自己喜欢的人。” 老二举手：“那就是说，我每次都要把自己盘子里的豌豆全部拿起来，然后放到老大的盘子里吗？” “没错，”老爸说，“老三和老大也类似。大家都明白规则了吗？” 三个孩子点头。“好，那游戏开始！” 一开始三个孩子盘子里豌豆的情况如图： “预备！”妈妈喊到，“开始！” 三个孩子开始分配自己手中的豌豆。老二把十颗豌豆都给了老大；老三把十颗豌豆都给了老二；老大则是给老二和老三一人分配了五颗豌豆，如图： 三个孩子很快就麻利地分配好了自己手中的豌豆。这时三个人的盘子变成了这种情况： 老大有点不高兴了：“为什么我的豌豆比老二的还少啊？这个游戏不公平！” 老爸说：“这个游戏还没有结束。接下来我还会继续吹哨，你们也还要继续这个游戏，直到你们盘子里的豌豆数不再变化为止。公平不公平，到时候就能看出来了。” 老大虽然有点疑惑，不过还是点头同意了。 就这样，游戏一直进行下去。在下一轮的交换豌豆后，老大的盘子里有了15颗豌豆，老二有10颗，而老三只有五颗。当然故事在这里还没有结束，不过我们的描述要结束了。因为这个游戏将会持续很长很长时间——这点大概是死理性派老爸没有想到的。当然如果继续分下去，豌豆的数量将不再是整数，这一点我们也不深究了，游戏怎么能进行下去，就留给老爸想办法吧。 那么这个游戏最终的结果是什么样的呢？我们可以用电脑模拟这个过程，得出的结果是：老大和老二的盘子里各有12颗豌豆，而老三的盘子里有6颗豌豆。这时候无论游戏怎么进行下去，盘子里的豌豆数量都不会再变化。 网页排名和PageRank 在互联网刚刚发展的时代，人们曾经为网页的排名问题伤透脑筋。网页排名，顾名思义，就是为互联网上成千上万（当然，现在互联网上的网页数量已经不只是成千上万的程度了）的网页按照重要度进行排序。能够得知哪个网页更重要，对搜索引擎的发展十分有帮助——很显然，搜索引擎应该把重要的网页放到搜索结果中比较靠前的地方。 这个问题看起来很容易，但是解决的方法却没有想象的那么简单。 最初，一些比较流行的网页排名算法都很类似，它们都使用了一个非常简单的思想：越是重要的网页，访问量就会越大。于是，许多大公司就通过统计网页的访问量来进行网页排名。但是这种排名算法有两个很显著的问题：一是因为只能够抽样统计，所以统计数据不一定准确，而且访问量的波动会比较大，想要得到准确的统计需要大量的时间和人力，还只能维持很短的有效时间；二是访问量并不一定能体现网页的“重要程度”——可能一些比较早接触互联网的网民还记得，那时有很多人推出了专门“刷访问量”的服务。 有没有更好的方法，不统计访问量就能够为网页的重要度排序呢？在1999年，一篇以拉里•佩奇（Larry Page）为第一作者的论文[3]发表了。论文中介绍了一种叫做PageRank的算法，这种算法的主要思想是：越“重要”的网页，页面上的链接质量也越高，同时越容易被其它“重要”的网页链接。于是，算法完全利用网页之间互相链接的关系来计算网页的重要程度，终于摆脱了访问量统计的框框。 不过，不知道我们的死理性派老爸是不是了解，实际上刚刚他和孩子玩的游戏，就是PageRank算法的运行过程。 PageRank会给每个网页一个数值，这个数值越高，就说明这个网页越“重要”。而刚刚的游戏中，如果把豌豆的数量看作这个数值（可以不是整数），把孩子们看作网页，那么游戏的过程就是PageRank的算法，而游戏结束时豌豆的分配，就是网页的PageRank值。[4] 随机行走模型和马尔可夫过程 PageRank算法的思想基于“随机行走模型”（Random Walk Model）[5]。实际上，PageRank求解了这样一个问题：一个人在网络上浏览网页，每看过一个网页之后就会随机点击网页上的链接访问新的网页。如果当前这个人浏览的网页x已经确定，那么网页x上每个链接被点击的概率也是确定的，可以用向量Nx表示。在这种条件下，这个人点击了无限多次链接后，恰好停留在每个网页上的概率分别是多少？ 在这个模型中，我们用向量Ri来表示点击了i次链接之后可能停留在每个网页上的概率（R0则为一开始就打开了每个网页的概率，后面可以看到R0的取值对最终结果没有影响）。很显然Ri的L1范式[4]为1，这也是PageRank算法本身的要求。 于是，整个浏览过程的一开始，我们有： 其中，A是一个表示每一次点击链接概率的矩阵。A的第i列第j行Ai, j的含义是，如果当前访问的网页是网页i，那么下一次点击链接跳转到网页j的概率为Ai, j。 这样设计矩阵A的好处是，通过矩阵A和向量Rn-1相乘，即可得出点击一次链接后每个网页可能的停留概率向量Rn。例如，令R1=AR0，可以得到点击一次链接后停留在每个网页的概率： &#8230; <a href="http://sqybi.com/blog/archives/359">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<blockquote><p>本文同时发表在果壳网死理性派栏目，传送门：<a href="http://www.guokr.com/article/65304/">http://www.guokr.com/article/65304/</a>。因为字数原因，所以编辑对死理性派上发表的文章进行了一定的删减和修正。这里发出的是未删减的版本，表示“太理性了，看不懂”的童鞋们可以来围观此文。</p>
</blockquote>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/11.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top: 0px; border-right: 0px; padding-top: 0px" title="1" border="0" alt="1" src="http://sqybi.com/blog/wp-content/uploads/2011/09/1_thumb1.png" width="240" height="173" /></a>如果你安装过Google工具栏，如果你建立过独立博客或个人网站，那么你肯定和PageRank打过照面。而即使是从未考虑建站的读者，也有很大一部分听说过PageRank，毕竟作为Google搜索结果排序的重要依据[1]，这个算法已经被广泛应用于网络的每一个角落。而PageRank值的大小，也早已与网站的SEO[2]成功与否紧密相连。     <br />那么PageRank的名称从何而来？PageRank究竟如何准确表示网页重要度，它的算法又是如何高效准确运行的呢？在PageRank的背后，有什么数学理论的支持？且听笔者为您一一道来。</p>
<p><strong>三个孩子和豌豆游戏</strong></p>
<p>从前有一个死理性派老爸，他有三个孩子。老爸是个懒人，他在家里把三个孩子叫做老大、老二和老三。    <br />一天，三个孩子正在玩游戏，老爸把他们叫到身边。“我这里有三十颗豌豆，”老爸说，“我们来用它们玩一个游戏，游戏结束之后按照游戏结果把豌豆分给你们，好不好啊？”     <br />“好！”三个孩子异口同声地答应了。     <br />“你们先在这张纸上写下你们喜欢的人，如果你认为另外两个兄弟你都很喜欢，那就把两个人的名字都写下来。比如我知道老二很喜欢老大，那么老二就在纸上写老大的名字。”     <br />三个孩子很快写好了，然后老爸把纸收了上来。老大的纸上写了老二和老三的名字，而老二写了老大，老三写了老二。三个人互相喜欢的结果如图：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="2" border="0" alt="2" src="http://sqybi.com/blog/wp-content/uploads/2011/09/2_thumb.png" width="364" height="364" /></a></p>
<p>老爸清了一下嗓子，继续向孩子们解释规则：“接下来，我会给你们每个人分十颗豌豆。桌上有三个盘子，分别代表你们三个人，豌豆都放在盘子里。在我喊‘预备’的时候，你们要把盘子里的豌豆全都拿到手里。在我喊‘开始’的时候，你们要把手里的豌豆全部平均分给自己喜欢的人。”    <br />老二举手：“那就是说，我每次都要把自己盘子里的豌豆全部拿起来，然后放到老大的盘子里吗？”     <br />“没错，”老爸说，“老三和老大也类似。大家都明白规则了吗？”     <br />三个孩子点头。“好，那游戏开始！”     <br />一开始三个孩子盘子里豌豆的情况如图：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/3.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="3" border="0" alt="3" src="http://sqybi.com/blog/wp-content/uploads/2011/09/3_thumb.png" width="364" height="351" /></a></p>
<p>“预备！”妈妈喊到，“开始！”    <br />三个孩子开始分配自己手中的豌豆。老二把十颗豌豆都给了老大；老三把十颗豌豆都给了老二；老大则是给老二和老三一人分配了五颗豌豆，如图：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/4.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="4" border="0" alt="4" src="http://sqybi.com/blog/wp-content/uploads/2011/09/4_thumb.png" width="364" height="364" /></a></p>
<p>三个孩子很快就麻利地分配好了自己手中的豌豆。这时三个人的盘子变成了这种情况：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/5.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="5" border="0" alt="5" src="http://sqybi.com/blog/wp-content/uploads/2011/09/5_thumb.png" width="364" height="351" /></a></p>
<p>老大有点不高兴了：“为什么我的豌豆比老二的还少啊？这个游戏不公平！”    <br />老爸说：“这个游戏还没有结束。接下来我还会继续吹哨，你们也还要继续这个游戏，直到你们盘子里的豌豆数不再变化为止。公平不公平，到时候就能看出来了。”     <br />老大虽然有点疑惑，不过还是点头同意了。     <br />就这样，游戏一直进行下去。在下一轮的交换豌豆后，老大的盘子里有了15颗豌豆，老二有10颗，而老三只有五颗。当然故事在这里还没有结束，不过我们的描述要结束了。因为这个游戏将会持续很长很长时间——这点大概是死理性派老爸没有想到的。当然如果继续分下去，豌豆的数量将不再是整数，这一点我们也不深究了，游戏怎么能进行下去，就留给老爸想办法吧。     <br />那么这个游戏最终的结果是什么样的呢？我们可以用电脑模拟这个过程，得出的结果是：老大和老二的盘子里各有12颗豌豆，而老三的盘子里有6颗豌豆。这时候无论游戏怎么进行下去，盘子里的豌豆数量都不会再变化。     </p>
<p><strong>网页排名和PageRank</strong></p>
<p>在互联网刚刚发展的时代，人们曾经为网页的排名问题伤透脑筋。网页排名，顾名思义，就是为互联网上成千上万（当然，现在互联网上的网页数量已经不只是成千上万的程度了）的网页按照重要度进行排序。能够得知哪个网页更重要，对搜索引擎的发展十分有帮助——很显然，搜索引擎应该把重要的网页放到搜索结果中比较靠前的地方。    <br />这个问题看起来很容易，但是解决的方法却没有想象的那么简单。     <br />最初，一些比较流行的网页排名算法都很类似，它们都使用了一个非常简单的思想：越是重要的网页，访问量就会越大。于是，许多大公司就通过统计网页的访问量来进行网页排名。但是这种排名算法有两个很显著的问题：一是因为只能够抽样统计，所以统计数据不一定准确，而且访问量的波动会比较大，想要得到准确的统计需要大量的时间和人力，还只能维持很短的有效时间；二是访问量并不一定能体现网页的“重要程度”——可能一些比较早接触互联网的网民还记得，那时有很多人推出了专门“刷访问量”的服务。     <br />有没有更好的方法，不统计访问量就能够为网页的重要度排序呢？在1999年，一篇以拉里•佩奇（Larry Page）为第一作者的论文[3]发表了。论文中介绍了一种叫做PageRank的算法，这种算法的主要思想是：越“重要”的网页，页面上的链接质量也越高，同时越容易被其它“重要”的网页链接。于是，算法完全利用网页之间互相链接的关系来计算网页的重要程度，终于摆脱了访问量统计的框框。     <br />不过，不知道我们的死理性派老爸是不是了解，实际上刚刚他和孩子玩的游戏，就是PageRank算法的运行过程。     <br />PageRank会给每个网页一个数值，这个数值越高，就说明这个网页越“重要”。而刚刚的游戏中，如果把豌豆的数量看作这个数值（可以不是整数），把孩子们看作网页，那么游戏的过程就是PageRank的算法，而游戏结束时豌豆的分配，就是网页的PageRank值。[4]</p>
<p><strong>随机行走模型和马尔可夫过程</strong></p>
<p>PageRank算法的思想基于“随机行走模型”（Random Walk Model）[5]。实际上，PageRank求解了这样一个问题：一个人在网络上浏览网页，每看过一个网页之后就会随机点击网页上的链接访问新的网页。如果当前这个人浏览的网页x已经确定，那么网页x上每个链接被点击的概率也是确定的，可以用向量N<sub>x</sub>表示。在这种条件下，这个人点击了无限多次链接后，恰好停留在每个网页上的概率分别是多少？     <br />在这个模型中，我们用向量R<sub>i</sub>来表示点击了i次链接之后可能停留在每个网页上的概率（R<sub>0</sub>则为一开始就打开了每个网页的概率，后面可以看到R<sub>0</sub>的取值对最终结果没有影响）。很显然R<sub>i</sub>的L1范式[4]为1，这也是PageRank算法本身的要求。     <br />于是，整个浏览过程的一开始，我们有：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/eq1.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="eq1" border="0" alt="eq1" src="http://sqybi.com/blog/wp-content/uploads/2011/09/eq1_thumb.png" width="253" height="207" /></a></p>
<p>其中，A是一个表示每一次点击链接概率的矩阵。A的第i列第j行A<sub>i, j</sub>的含义是，如果当前访问的网页是网页i，那么下一次点击链接跳转到网页j的概率为A<sub>i, j</sub>。     <br />这样设计矩阵A的好处是，通过矩阵A和向量R<sub>n-1</sub>相乘，即可得出点击一次链接后每个网页可能的停留概率向量R<sub>n</sub>。例如，令R<sub>1</sub>=AR<sub>0</sub>，可以得到点击一次链接后停留在每个网页的概率：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/eq2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="eq2" border="0" alt="eq2" src="http://sqybi.com/blog/wp-content/uploads/2011/09/eq2_thumb.png" width="206" height="112" /></a></p>
<p>之后一直迭代下去，有：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/eq3.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="eq3" border="0" alt="eq3" src="http://sqybi.com/blog/wp-content/uploads/2011/09/eq3_thumb.png" width="166" height="41" /></a></p>
<p>对于以上例子，迭代结果如下图：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/9.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="9" border="0" alt="9" src="http://sqybi.com/blog/wp-content/uploads/2011/09/9_thumb.png" width="364" height="234" /></a></p>
<p>可以看到，每个网页停留的概率在振荡之后趋于稳定。    <br />在这种稳定状态下，我们可以知道，无论如何迭代，都有R<sub>n</sub>=R<sub>n-1</sub>。这样我们就获得了一个方程：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/eq4.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="eq4" border="0" alt="eq4" src="http://sqybi.com/blog/wp-content/uploads/2011/09/eq4_thumb.png" width="384" height="45" /></a></p>
<p>而整个迭代的过程，就是在寻求方程R=AR的解。这也是为什么R<sub>0</sub>的取值对结果没有影响：无论R<sub>0</sub>是多少，迭代无限多次之后，一定会取得令R=AR成立的R值。整个求解R的过程，就如同一个人在一张地图上的不同位置之间随机地行走一样，所以被称为“随机行走模型”。     <br />随机行走模型有一个显著的特点，那就是每一次迭代的结果只与前一次有关，与更早的结果完全无关。这种过程又被称为马尔可夫过程（Markov Process）或马尔可夫链（Markov Chain）[7]。     <br />马尔可夫过程的数学定义是：如果对于一个随机变量序列X<sub>0</sub>、X<sub>1</sub>、X<sub>2</sub>、…，其中X<sub>n</sub>表示时间n的状态及转移概率（transition possibility）P，有：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/eq5.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="eq5" border="0" alt="eq5" src="http://sqybi.com/blog/wp-content/uploads/2011/09/eq5_thumb.png" width="617" height="44" /></a></p>
<p>即X<sub>n</sub>只受X<sub>n-1</sub>的影响，则此过程成为马尔可夫过程。其中P(X<sub>n+1</sub>|X<sub>n</sub>)称作“一步转移概率”，而两步、三步转移概率则可以通过一步转移概率的积分求得。     <br />当状态空间有限时，转移概率可以用用一个矩阵A来表示，称作转移矩阵（transition matrix）。此时转移概率的积分即为矩阵的幂，k步转移概率可以用A<sup>k</sup>表示，这也是随机行走模型中的情况。而对于一个正的（每个元素都为正的）转移矩阵A，可以证明一定有：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/eq6.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="eq6" border="0" alt="eq6" src="http://sqybi.com/blog/wp-content/uploads/2011/09/eq6_thumb.png" width="240" height="63" /></a></p>
<p>这也解释了为什么在这段开始笔者提到，R<sub>0</sub>的取值对最终结果没有影响。     <br />上述有限状态空间的马尔可夫过程只是马尔可夫过程的一个小分支。马尔可夫过程作为一种有效的随机过程模型，已经在更广泛的领域中得以应用。除了PageRank算法外，LZMA压缩算法[8]也使用了马尔可夫过程作为信号模型；此外，生物学和机器写作的领域都有马尔可夫过程的身影。</p>
<p><strong>悬挂网页和个性化PageRank</strong></p>
<p>不知道细心的读者发现没有，以上叙述的算法有时并不能解决问题——在某些情况下，算法的结果中有很多网页的PageRank都是0，甚至结果就是一个零向量。    <br />这是为什么呢？其实，当一个网页只有链入链接没有链出链接的时候，这个网页就会像一个“黑洞”一样，将同一个连通子图中其它网页流向它的PageRank慢慢“吞掉”，这种网页我们称之为“悬挂网页”（Dangling Link）。此时的转移矩阵A，对于任意自然数n，A<sup>n</sup>都不会是一个正的转移矩阵——A中对应着悬挂网页的位置永远是0。     <br />为了解决这个问题，PageRank算法加入了一个新的向量E。它的作用是，按照其中所描述的比例来向全部网页分配悬挂网页每一次“吞掉”的PageRank。这样，相当于为悬挂网页添加了链向网络上全部网页的链接，避免了悬挂链接的出现。     <br />E的取值如何确定呢？论文中提到，一般可以直接使用平均分配的方式把悬挂网页的PageRank分配给所有网页。但是，因为抓取的数据库通常是不完全的，所以悬挂网页的数量一般来说非常巨大，E的改变也会对PageRank的结果造成影响。于是，通过设定不同的E，我们就可以人为干预PageRank的结果。这样得到的PageRank，称作“个性化PageRank”（Personalized PageRank）。     <br />事实上，这样的干预是很重要的。在PageRank算法的真正实现中，会增加一个常系数c，即：</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/09/eq7.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="eq7" border="0" alt="eq7" src="http://sqybi.com/blog/wp-content/uploads/2011/09/eq7_thumb.png" width="265" height="40" /></a></p>
<p>以此来人为“制造”悬挂网页。</p>
<p><strong>佩奇和“佩奇的排名”</strong></p>
<p>之前提到过，PageRank算法的论文中，第一作者的名字叫做拉里•佩奇，即Larry Page。    <br />佩奇是Google的创始人之一，现任Google的CEO。这里有一件很有意思的事情出现了：“佩奇”的英文是“Page”，恰好与“PageRank”的“Page”相吻合。这是巧合还是有意为之呢？     <br />在网络上笔者可以找到的许多资料中，均提到PageRank是以拉里•佩奇的姓命名。但是所有这些资料都没有提到这条信息的来源，所以其真实性无从得证。     <br />不过，既然佩奇本人没有出来解释，那我们也没有必要纠结于Page的含义了。或许这个词本身就是佩奇利用双关语向我们开的一个小玩笑呢！</p>
<p><strong>脚注与参考资料</strong></p>
<p>[1] 虽然PageRank是Google搜索结果排序的重要依据，不过它并不是全部依据——实际上，Google用了数百种不同的算法来确定最终显示给用户的搜索结果顺序。    <br />[2] SEO，即Search Engine Optimization，意为搜索引擎优化，主要是将网站的内容、布局等针对搜索引擎进行优化，使得页面更容易在搜索结果上被显示。     <br />[3] L. Page, S. Brin, R. Motwani and T. Winograd. The PageRank Citation Ranking: Bring Order to the Web. Jan, 1998.     <br />[4] 这里的描述不是非常准确：首先，在PageRank的算法中，要求结果向量的L2范式为1，所以需要将每个孩子的豌豆数量减少到例子中的1/30；另外，我们看到的网页PageRank值，实际上是通过对算法的结果求对数得到的。但算法的本质没有大的不同，所以这里不再赘述。     <br />[5] 随机行走模型，来自Wikipedia：<a href="http://en.wikipedia.org/wiki/Random_walk">http://en.wikipedia.org/wiki/Random_walk</a>     <br />[6] 向量的L1范式，即向量中每一项的绝对值之和。     <br />[7] 马尔可夫过程，来自Wikipedia：<a href="http://en.wikipedia.org/wiki/Markov_chain">http://en.wikipedia.org/wiki/Markov_chain</a>     <br />[8] LZMA算法，来自Wikipedia：<a href="http://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm">http://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/359/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Codeforces Beta Round #80 Div. 2 总结</title>
		<link>http://sqybi.com/blog/archives/332</link>
		<comments>http://sqybi.com/blog/archives/332#comments</comments>
		<pubDate>Tue, 09 Aug 2011 09:52:56 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[OI, ACM, etc]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/?p=332</guid>
		<description><![CDATA[这次比赛是晚上7点开始的，所以状态大概比上次好一些。不过还是有题错得蛋疼，算是熟悉Python过程中的一个教训吧。 A题可以算是水之又水，模拟也可以做，写几个if或者case语句也可以做，甚至直接打表也可以。不过还真有人做错，随手hack掉了。 B题大概就是推一个公式然后计算就可以。写的时候有个小地方写错了，resubmit了一次，貌似扣了一些分。 C题是说判断一个图是不是如下形状：有一个至少三个结点的环，环上每个结点下面都可以挂一棵树。我直接DFS了一下，不过判断连通的时候出了一个很恶心的问题：我的判断连通方法是，DFS之后看是不是访问了所有结点。结果Python的++i是0+0+i的意思，于是我写的一句++n直接没有作用而且还不报错……然后pretest又没有这种情况出现，于是这道题system test的时候挂掉了。写C++写习惯了，++、--操作符总是顺手用。这个习惯得改了…… D题看起来是概率题，实际上仔细想一想就知道，整体的概率大小和X无关，只和每个.和它后面第一个X的距离是奇数还是偶数有关。尽量保证结果是.X.X……的形式，然后在不影响总概率的情况下安排字典序（如：..X.X可以改为...XX），实际上这就成了一道构造题。代码写起来可能稍微乱一点，别的没难度。 E题貌似这次是Div 1的D题，比较难。有n*sqrt(n)的算法，但是最后也没写完，不知道能不能奏效。 最后挂了C题，E题没做。因为大部分人E都没做所以成绩还好，压线变紫。下次就要做Div 1了，Ganbatte！]]></description>
			<content:encoded><![CDATA[<p>这次比赛是晚上7点开始的，所以状态大概比上次好一些。不过还是有题错得蛋疼，算是熟悉Python过程中的一个教训吧。</p>
<p>A题可以算是水之又水，模拟也可以做，写几个if或者case语句也可以做，甚至直接打表也可以。不过还真有人做错，随手hack掉了。</p>
<p>B题大概就是推一个公式然后计算就可以。写的时候有个小地方写错了，resubmit了一次，貌似扣了一些分。</p>
<p>C题是说判断一个图是不是如下形状：有一个至少三个结点的环，环上每个结点下面都可以挂一棵树。我直接DFS了一下，不过判断连通的时候出了一个很恶心的问题：我的判断连通方法是，DFS之后看是不是访问了所有结点。结果Python的++i是0+0+i的意思，于是我写的一句++n直接没有作用而且还不报错……然后pretest又没有这种情况出现，于是这道题system test的时候挂掉了。写C++写习惯了，++、--操作符总是顺手用。这个习惯得改了……</p>
<p>D题看起来是概率题，实际上仔细想一想就知道，整体的概率大小和X无关，只和每个.和它后面第一个X的距离是奇数还是偶数有关。尽量保证结果是.X.X……的形式，然后在不影响总概率的情况下安排字典序（如：..X.X可以改为...XX），实际上这就成了一道构造题。代码写起来可能稍微乱一点，别的没难度。</p>
<p>E题貌似这次是Div 1的D题，比较难。有n*sqrt(n)的算法，但是最后也没写完，不知道能不能奏效。</p>
<p>最后挂了C题，E题没做。因为大部分人E都没做所以成绩还好，压线变紫。下次就要做Div 1了，Ganbatte！</p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/332/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Codeforces Beta Round #79 Div. 2 总结</title>
		<link>http://sqybi.com/blog/archives/329</link>
		<comments>http://sqybi.com/blog/archives/329#comments</comments>
		<pubDate>Wed, 03 Aug 2011 19:41:36 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[OI, ACM, etc]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/?p=329</guid>
		<description><![CDATA[最近突然来的兴致，于是又开始刷题了。现在在做的比赛有SRM和这个Codeforces的比赛。SRM还是用C++（因为不给开Python），这个就用来练Python了。 比赛刚刚结束，结果略坑爹。虽然速度搞出五道题然后hack了两个人暂时占领ranklist第二的位置，不过System Test直接挂了三道题。 A题是一道非常水的枚举，结果被我写挂了。原因是我偷懒没开二维数组存邻接矩阵（python开二维矩阵要写好长一段啊，用过的应该都知道吧……），然后直接存了边表。更坑爹的是边表里边的查找我随手写了个in，要知道Python的in可是线性复杂度啊，不过当时没看出来。这算是C++留下的后遗症呢还是Python不够熟练呢，总之光注意循环的复杂度没问题就没管这道题了。结果悲剧地TLE了。要是把边表存成一个set其实就OK了，不过可惜比赛时没注意到这一点。 B题也是水题，纯模拟，跳过。 C题是字符串处理，对于Python来说没有任何难度。只要注意最开始别直接转成int就行了，不然会爆掉（Python不会爆不过会TLE。。。大概）。 D题大概是线段树（树状数组？）+DP，可惜我已经好久没写代码了所以没敢下手，只写了一个离散化+DP。果断TLE掉。代码能力啊代码能力，这些算法怎么写都得补啊。。。以后应该还是有用的吧。。。其实这题算时间复杂度也出现了问题，(n/2) * (n/2)我竟然当成了n的复杂度，真不知道脑子在想什么。锁了题之后才发现这一点，不过已经晚了。测了极限数据过不了（顺便用这组极限数据hack了一个人），当时还心存侥幸，其实想想也知道这种比赛的数据肯定足够强。。。 update: D题其实只要把车站进入和离开的时间点排序就可以了，我想复杂了。。。坑爹啊。 E题是简单数学题（跟D题比真的简单不少），不过写的时候手贱了多打了点东西。。。于是就挂了。自作自受啊自作自受。不过就算是在当初状态最好的时候，能不能保证不出这个失误呢？还真不好说。 最后排名惨不忍睹了（就出了两道题还不是高分题），估计下次还要做Div 2了吧。SRM那边开的小号第一场倒运气不错，直接黄了，比大号的第一场分数都高——明明排名比大号的第一次比赛低不少。SRM的分数通货膨胀了么。 唉唉，这个总结就这样吧，恢复状态任重而道远啊。。。]]></description>
			<content:encoded><![CDATA[<p>最近突然来的兴致，于是又开始刷题了。现在在做的比赛有SRM和这个Codeforces的比赛。SRM还是用C++（因为不给开Python），这个就用来练Python了。</p>
<p>比赛刚刚结束，结果略坑爹。虽然速度搞出五道题然后hack了两个人暂时占领ranklist第二的位置，不过System Test直接挂了三道题。</p>
<p>A题是一道非常水的枚举，结果被我写挂了。原因是我偷懒没开二维数组存邻接矩阵（python开二维矩阵要写好长一段啊，用过的应该都知道吧……），然后直接存了边表。更坑爹的是边表里边的查找我随手写了个in，要知道Python的in可是线性复杂度啊，不过当时没看出来。这算是C++留下的后遗症呢还是Python不够熟练呢，总之光注意循环的复杂度没问题就没管这道题了。结果悲剧地TLE了。要是把边表存成一个set其实就OK了，不过可惜比赛时没注意到这一点。</p>
<p>B题也是水题，纯模拟，跳过。</p>
<p>C题是字符串处理，对于Python来说没有任何难度。只要注意最开始别直接转成int就行了，不然会爆掉（Python不会爆不过会TLE。。。大概）。</p>
<p>D题大概是线段树（树状数组？）+DP，可惜我已经好久没写代码了所以没敢下手，只写了一个离散化+DP。果断TLE掉。代码能力啊代码能力，这些算法怎么写都得补啊。。。以后应该还是有用的吧。。。其实这题算时间复杂度也出现了问题，(n/2) * (n/2)我竟然当成了n的复杂度，真不知道脑子在想什么。锁了题之后才发现这一点，不过已经晚了。测了极限数据过不了（顺便用这组极限数据hack了一个人），当时还心存侥幸，其实想想也知道这种比赛的数据肯定足够强。。。</p>
<p><span style="color: #ff0000;">update: D题其实只要把车站进入和离开的时间点排序就可以了，我想复杂了。。。坑爹啊。</span></p>
<p>E题是简单数学题（跟D题比真的简单不少），不过写的时候手贱了多打了点东西。。。于是就挂了。自作自受啊自作自受。不过就算是在当初状态最好的时候，能不能保证不出这个失误呢？还真不好说。</p>
<p>最后排名惨不忍睹了（就出了两道题还不是高分题），估计下次还要做Div 2了吧。SRM那边开的小号第一场倒运气不错，直接黄了，比大号的第一场分数都高——明明排名比大号的第一次比赛低不少。SRM的分数通货膨胀了么。</p>
<p>唉唉，这个总结就这样吧，恢复状态任重而道远啊。。。</p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/329/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>编译器和它的故事&#8212;&#8212;自展与交叉编译</title>
		<link>http://sqybi.com/blog/archives/322</link>
		<comments>http://sqybi.com/blog/archives/322#comments</comments>
		<pubDate>Sun, 08 May 2011 02:25:21 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[Technology]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/archives/322</guid>
		<description><![CDATA[其实好久以前就想开始动手写这么一篇文章了，不过一直没有时间。现在正好刚考完最后一门期中考试，还是编译原理，就把这篇文章写出来。 要阅读本文，不需要太高深的编译原理知识，甚至不需要编译相关的知识。但是本文也不是面向对电脑一无所知的读者的，你至少要知道： 1. 不管是exe可执行文件还是Linux下的程序，都是一些二进制代码，我们称之为机器语言。这些代码的执行和系统以及CPU都有关。 2. 大部分情况下，编译器是一种将高级语言翻译成机器语言的程序。而任何程序本身也是一些机器语言的代码。 3. 无论是高级语言、汇编语言还是机器语言，实际上都是等价的，唯一有区别的是，越高级的语言写起来越容易（所以我们倾向于尽量多书写高级语言代码）；同时，机器语言是可以直接运行的。 如果你觉得上面三条可以理解或者可以理解一部分，那么请继续阅读。 另外，本文中提到的无论是编译的过程还是语言的分类甚至是一些例子，都可以看做是一个简化的模型。实际上，很少有一个exe程序就可以运行的编译器，现代的编译器都是十分复杂的。不过，考虑这些简化模型对我们没有任何坏处，它们和实际情况相差并不很大。 首先我来详细解释一下高级语言和机器语言。 语言的所谓“高级”，实际上界定不是那么明确。不过我们可以确定的是：C++、Java、Python之流比汇编语言更高级，而汇编语言比机器语言更高级。 这里提到一个汇编语言和机器语言的区分。可能有些读者不明白这两个概念的区别，实际上很简单，汇编语言是我们会看到的那些MOV、JMP等命令组成的语言，而机器语言则纯粹是是各种01串。我想没有人会愿意写一个机器语言的程序——实际上，我们学校的计算机组成实验都是用Verilog HDL这种高级语言来完成的，而嵌入式原理实验也是用一种汇编语言完成的；即使是做处理器和单片机，也不会有人愿意去写机器语言，毕竟一大堆01串太坑爹了。 试想，让你用C++写一个从1输出到100的程序，几行代码就可以搞定；而汇编语言则可能需要几十行；机器语言呢，Oh my god，一大堆01000101110110101011111001……，看都看不懂，还写啥啊。 但是上面也提到了，机器语言和高级语言的区别是，它可以直接运行。比如exe程序，实际上它内部存储的就是一些机器语言的代码，机器可以直接阅读这些代码并在处理器中运行它们（这里说的不是完全准确，比如.NET编译出的exe程序实际上是一段中间代码，由CLR解释成机器代码才能运行——不过这可以暂且忽略，就当作我说的是一个简化的模型）。当然程序的运行是依赖机器架构和系统的，不然Wine什么的也就没有用了（什么是Wine？WINE = WINE Is Not an Emulator！有趣的名称递归定义还有很多，不过与本文无关，请自行Google）。 而实际上，是机器架构不同还是系统不同，并不是我们考虑的问题。我们考虑的问题只是，一段代码在A机器和X系统下能否运行，换到B机器和Y系统下又能否运行。就算在A机器和X系统下能运行，如果换成了A机器和Y系统之后不能运行了，那对于我们这也可以看做两台不同的机器（也就是说，A机器和Y系统实际上就可以看做一个新的机器B）。所以之后的描述中，我们不考虑操作系统的情况，而是只考虑机器，我们编号为a、b等，而它们上面可以运行的机器语言我们编号为A、B等。 以上几段的关键点是： 无论是机器语言还是高级语言，实际上都是代码。在之后的讨论中，我们不应该将它们区别对待。 虽然机器语言代码和高级语言略有不同，它可以直接在机器上运行，但是对于编译过程，它们没有任何区别。 上面的问题了解了之后，我再来简单说一下编译器。那编译器是什么？这要从两个方面来解释。 首先，编译器本身的功能是，将一种语言S的代码转化为一种语言T的代码。这里稍微了解编译器的读者可能有疑问了：我用的gcc之类的编译器，明明是把C语言代码编译成了一个exe程序，并不是把S语言的代码编译成了T语言的代码啊？如果你也有这个疑问，请重新阅读以上几段——我在前面已经提过了，“任何程序本身也是一些机器语言的代码”。也就是说，我们这里把机器语言也看作一种语言，只不过是很低级的语言；而编译器就可以将C语言这种高级语言S转化为机器语言这种低级语言T，恰好这种低级语言还是可以在机器t上直接运行的。 其次，大部分情况下，编译器自己也是一段程序，那么它也可以看做是一段代码。而编译器也会有它的源代码，这个源代码就是一种高级语言的代码，我们这时仍然叫它编译器。随便举个例子，对于gcc.exe，这个程序是一种机器语言A的代码，它可以直接在a机器上运行。而它的功能则是，将C语言的代码转化为机器语言A的代码（一个C语言的编译器），使得本身无法直接运行的C语言程序变得可以在a机器上运行。而在得到gcc.exe之前，我们一定也有一段代码，它是用来生成gcc.exe这个程序的，这段代码可能是一个高级语言的代码，比如汇编语言。那这时候，这段汇编语言的代码即使不能直接在电脑上运行，我们依然说这是一个C语言的编译器。 有了这两点，我们就可以总结出一个编译器的特征： 1. 本身是一段代码，假设是A语言的代码，A可以是机器语言，也可以不是； 2. 可以接收一段代码，假设是S语言的代码，S一般来说是高级语言，但理论上也可以不是； 3. 可以将接收到的S语言代码在内部转换后输出一段代码，假设是T语言的代码，T有可能是机器语言，但也有可能是一种高级语言。 这样，一个编译器就可以被表示为A(S –&#62; &#8230; <a href="http://sqybi.com/blog/archives/322">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>其实好久以前就想开始动手写这么一篇文章了，不过一直没有时间。现在正好刚考完最后一门期中考试，还是编译原理，就把这篇文章写出来。</p>
<blockquote><p>要阅读本文，不需要太高深的编译原理知识，甚至不需要编译相关的知识。但是本文也不是面向对电脑一无所知的读者的，你至少要知道：<br />
1. 不管是exe可执行文件还是Linux下的程序，都是一些<strong>二进制代码</strong>，我们称之为<strong>机器语言</strong>。这些代码的执行和系统以及CPU都有关。<br />
2. 大部分情况下，编译器是一种将<strong>高级语言翻译成机器语言</strong>的程序。而<strong>任何程序本身</strong>也是一些<strong>机器语言的代码</strong>。<br />
3. 无论是高级语言、汇编语言还是机器语言，实际上都是等价的，唯一有区别的是，越高级的语言写起来越容易（所以我们倾向于<strong>尽量多书写高级语言代码</strong>）；同时，<strong>机器语言是可以直接运行的</strong>。<br />
如果你觉得上面三条可以理解或者可以理解一部分，那么请继续阅读。</p>
<p>另外，本文中提到的无论是编译的过程还是语言的分类甚至是一些例子，都可以看做是一个简化的模型。实际上，很少有一个exe程序就可以运行的编译器，现代的编译器都是十分复杂的。不过，考虑这些简化模型对我们没有任何坏处，它们和实际情况相差并不很大。</p></blockquote>
<p>首先我来详细解释一下高级语言和机器语言。</p>
<p>语言的所谓“高级”，实际上界定不是那么明确。不过我们可以确定的是：C++、Java、Python之流比汇编语言更高级，而汇编语言比机器语言更高级。<br />
这里提到一个汇编语言和机器语言的区分。可能有些读者不明白这两个概念的区别，实际上很简单，汇编语言是我们会看到的那些MOV、JMP等命令组成的语言，而机器语言则纯粹是是各种01串。我想没有人会愿意写一个机器语言的程序——实际上，我们学校的计算机组成实验都是用Verilog HDL这种高级语言来完成的，而嵌入式原理实验也是用一种汇编语言完成的；即使是做处理器和单片机，也不会有人愿意去写机器语言，毕竟一大堆01串太坑爹了。<br />
试想，让你用C++写一个从1输出到100的程序，几行代码就可以搞定；而汇编语言则可能需要几十行；机器语言呢，Oh my god，一大堆01000101110110101011111001……，看都看不懂，还写啥啊。</p>
<p>但是上面也提到了，机器语言和高级语言的区别是，它可以直接运行。比如exe程序，实际上它内部存储的就是一些机器语言的代码，机器可以直接阅读这些代码并在处理器中运行它们（这里说的不是完全准确，比如.NET编译出的exe程序实际上是一段中间代码，由CLR解释成机器代码才能运行——不过这可以暂且忽略，就当作我说的是一个简化的模型）。当然程序的运行是依赖机器架构和系统的，不然Wine什么的也就没有用了（什么是Wine？WINE = WINE Is Not an Emulator！有趣的名称递归定义还有很多，不过与本文无关，请自行Google）。<br />
而实际上，是机器架构不同还是系统不同，并不是我们考虑的问题。我们考虑的问题只是，一段代码在A机器和X系统下能否运行，换到B机器和Y系统下又能否运行。就算在A机器和X系统下能运行，如果换成了A机器和Y系统之后不能运行了，那对于我们这也可以看做两台不同的机器（也就是说，A机器和Y系统实际上就可以看做一个新的机器B）。所以之后的描述中，我们不考虑操作系统的情况，而是只考虑机器，我们编号为a、b等，而它们上面可以运行的机器语言我们编号为A、B等。</p>
<blockquote><p>以上几段的关键点是：<br />
无论是机器语言还是高级语言，实际上都是代码。在之后的讨论中，我们不应该将它们区别对待。<br />
虽然机器语言代码和高级语言略有不同，它可以直接在机器上运行，但是对于编译过程，它们没有任何区别。</p></blockquote>
<p>上面的问题了解了之后，我再来简单说一下编译器。那编译器是什么？这要从两个方面来解释。</p>
<p>首先，编译器本身的功能是，将一种语言S的代码转化为一种语言T的代码。这里稍微了解编译器的读者可能有疑问了：我用的gcc之类的编译器，明明是把C语言代码编译成了一个exe程序，并不是把S语言的代码编译成了T语言的代码啊？如果你也有这个疑问，请重新阅读以上几段——我在前面已经提过了，“任何程序本身也是一些机器语言的代码”。也就是说，我们这里把机器语言也看作一种语言，只不过是很低级的语言；而编译器就可以将C语言这种高级语言S转化为机器语言这种低级语言T，恰好这种低级语言还是可以在机器t上直接运行的。<br />
其次，大部分情况下，编译器自己也是一段程序，那么它也可以看做是一段代码。而编译器也会有它的源代码，这个源代码就是一种高级语言的代码，我们这时仍然叫它编译器。随便举个例子，对于gcc.exe，这个程序是一种机器语言A的代码，它可以直接在a机器上运行。而它的功能则是，将C语言的代码转化为机器语言A的代码（一个C语言的编译器），使得本身无法直接运行的C语言程序变得可以在a机器上运行。而在得到gcc.exe之前，我们一定也有一段代码，它是用来生成gcc.exe这个程序的，这段代码可能是一个高级语言的代码，比如汇编语言。那这时候，这段汇编语言的代码即使不能直接在电脑上运行，我们依然说这是一个C语言的编译器。</p>
<p>有了这两点，我们就可以总结出一个编译器的特征：<br />
1. 本身是一段代码，假设是A语言的代码，A可以是机器语言，也可以不是；<br />
2. 可以接收一段代码，假设是S语言的代码，S一般来说是高级语言，但理论上也可以不是；<br />
3. 可以将接收到的S语言代码在内部转换后输出一段代码，假设是T语言的代码，T有可能是机器语言，但也有可能是一种高级语言。<br />
这样，一个编译器就可以被表示为A(S –&gt; T)，表示编译器本身的代码是A语言，可以接受一个S语言代码作为输入，同时产生相同功能的T语言代码作为输出。之后我们的编译器都会这么表示，请务必牢记。</p>
<blockquote><p>以上几段的关键点是：<br />
编译器是什么？从本质上看是一段代码，而从功能上看可以将一段代码等价地转化为另一段代码。<br />
所以，我们用A(S –&gt; T)表示一个编译器，这个编译器本身是由A语言写成的，它的功能是将S语言代码等价地转换为T语言代码。当A语言是机器语言的时候，这个编译器就是可以使用的。</p></blockquote>
<p>有了之前的知识基础，终于可以开始讲自展了。</p>
<p>不知道读了之前的内容，你有没有这样一个疑问：既然编译器本身是一段代码，那么如果想编译一个编译器，就需要更早的编译器来进行编译操作。而编译这个更早的编译器还需要更更早的编译器——长此以往，第一个编译器是怎么产生的呢？难道是直接用机器语言书写的？<br />
如果能这么想，那么你就猜对了。第一个编译器一定是用机器语言写出的。实际上，很久以前的程序员还在纸带上打孔编程呢，他们也照样乐在其中。机器语言只是很难书写，并不是不能书写。<br />
但是，毕竟用这么难书写的语言写一个C++编译器，谁都不会愿意去干。所以，第一个编译器的功能一定是很简单的。而人们会用这很简单的编译器的语言，去写一个稍微复杂一些的编译器；然后再用这个新的编译器，去写一个更复杂的编译器；最终得到一个很复杂的编译器，比如C++编译器——好了，如果能够理解这个过程，那么你实际上几乎就理解了自展。</p>
<p>所谓自展，实际上就是用一个功能不太完善的编译器支持的语言写代码，然后放到这个编译器上去编译，产生一个比自己更完善的编译器的过程。用一个不太恰当的例子来描述，就是我们已经有了一个C语言的编译器，然后我们用C语言写一个C++的编译器代码，并用C语言编译器编译这个代码生成可以运行的C++编译器（之所以不太恰当，是因为C语言不是C++语言的严格子集）。<br />
也就是说，我们有一个编译器A(C –&gt; A)，现在写一个编译器C(C++ –&gt; A)，将后者放入前者中进行编译，即A(C(C++ –&gt; A) –&gt; A)，得到一个可以执行的编译器A(C++ –&gt; A)。</p>
<blockquote><p>以上几段的关键点是：<br />
自展过程，实际上就是用低级语言先实现一个简单的编译器，然后用这个编译器的语言再去编写一个更高级的编译器——这个新编译器是旧编译器的扩展——的过程。</p></blockquote>
<p>自展很简单？那下面就是本文的重头戏——交叉编译了。</p>
<p>交叉编译这个概念，没有自展这个概念那么准确。所以先看一个问题：如果你想写一个手机系统上的程序，你会怎么做呢？我们可能会想到，开发一个手机上的编译器，然后把程序放到上面编译成手机可以运行的机器代码。但是这样就有一个很大的问题了，那就是手机的运行速度和电脑相比十分缓慢（虽然现在手机的CPU已经很强悍了，但是手机的内存一向很小，不太足以运行编译器）。<br />
实际上，在现实中我们的做法是，在电脑上完成编译过程，然后直接把在手机上可以运行的机器代码拷贝到手机内。这样就不受限于编译时手机的内存和CPU限制了。这样一个过程，就叫做交叉编译。<br />
当然交叉编译也有其它的应用，比如有时候我们也需要在一台电脑a上生成另外一台电脑b上同一个语言的编译器，比如在Windows下编译一个Linux的编译器。这个问题比前面的问题还要多一步编译操作，我们不妨在后面的讨论中将这两个问题称作问题1（前者）和问题2（后者）。</p>
<p>为了方便起见，我们把这两个问题用之前的表示方法来书写一下。<br />
首先，将电脑看做是机器a，手机看作是机器b。我们现在手里拥有的是某语言S在a机器上的编译器A(S –&gt; A)。对于问题1，我们需要最终生成一个在a机器上编译b机器代码的编译器，即A(S –&gt; B)。而对于问题2，我们则是需要一个在b机器上生成b机器代码的编译器，B(S –&gt; B)。<br />
而我们可以做到的是，用高级语言S写一个自身的编译器（可以是a机器的也可以是b机器的，不过这个问题中只有后者会被用到），即S(S –&gt; B)。<br />
好，现在我们就有了两个代码，A(S –&gt; A)和S(S –&gt; B)，其中只有第一个代码是可以在a机器上运行的。我们要从这两个代码中得到两个新的代码，那就是A(S –&gt; B)和B(S –&gt; B)。</p>
<p>首先先考虑如何得到一个A(S –&gt; B)，即一个在a机器上运行的可以将S语言代码编译为b机器代码的编译器。<br />
其实写成现在的形式，这一点如何做到已经很简单了。那就是将S(S –&gt; B)放入A(S –&gt; A)中编译，即A(S(S –&gt; B) –&gt; A)，这样就可以得到A(S –&gt; B)。这一步因为使用的编译器是A(S –&gt; A)，所以只需要在A机器上执行。<br />
这时，可以发现第一个问题已经解决了。我们这时就可以利用得到的A(S –&gt; B)在a机器（电脑）上编译b机器（手机）的代码了。</p>
<p>然后在考虑如何得到一个B(S –&gt; B)。<br />
可以看到，我们之前一步的时候有了一个A(S –&gt; B)，而最开始还拥有一个S(S –&gt; B)。这样，我们只需要将S(S –&gt; B)放入A(S –&gt; B)中编译，即A(S(S –&gt; B) –&gt; B)，这样就可以得到一个B(S –&gt; B)了。<br />
这样，我们用前一步得到的编译器A(S –&gt; B)，在a机器（Windows）上运行，又得到了一个新的编译器B(S –&gt; B)，它可以在b机器（Linux）下编译b机器（Linux）的代码。</p>
<p>可以看到，我们从最开始的编译器A(S –&gt; A)和代码S(S –&gt; B)得到最终代码B(S –&gt; B)的过程中，所有的步骤都是在A机器上运行的，完全没有用到B机器。这就是交叉编译的有趣之处！使用交叉编译，可以在很多情况下省去不少的麻烦。</p>
<p>另外解释一个问题，为什么不直接编写一个A(S –&gt; B)？因为A是机器代码，而之前也提到过了，“我们倾向于尽量多书写高级语言代码”，因为机器语言十分难以理解和书写。所以，我们写了一个高级语言代码S(S –&gt; B)，将它放到已有的A(S –&gt; A)上去编译（为什么是已有的？这个问题实际上不需要回答，因为这里假设a机器是一台很常用的机器（比如安装了Windows系统的PC机），所以A(S –&gt; A)是一个很普通的编译器，它的存在性无需证明；A(S –&gt; A)的书写可以利用之前提到的自展完成），最终得到了一个需要的B(S –&gt; B)。</p>
<blockquote><p>以上几段的关键点是：<br />
关键点太多了有木有！！！这个怎么总结呢……<br />
如果看不太懂交叉编译的过程的话，可以暂且把a机器当作一个安装了Windows的PC机，把b机器当作一台手机或者一个装了Linux的PC机，然后再带着这个理解重新阅读整个过程。<br />
实际上，交叉编译解决的两个问题分别都只需要一步操作，所以交叉编译没有听起来那么复杂！不要自己吓到自己就好了~</p></blockquote>
<p>拍了快两个小时，这篇文章终于完成了。文章是否容易理解？有没有出现什么技术性错误？欢迎各位留言讨论！<br />
神犇们就不要来bs内容太简单了……</p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/322/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>高效率写作利器 &#8212;&#8212; 几款写作软件对比</title>
		<link>http://sqybi.com/blog/archives/319</link>
		<comments>http://sqybi.com/blog/archives/319#comments</comments>
		<pubDate>Mon, 18 Apr 2011 05:27:34 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[Software]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/archives/319</guid>
		<description><![CDATA[几点说明 欢迎转载，转载请注明出自SQYBI.com，并附上原文链接（最好Trackback 一下）。 本文所提及的软件，并非那种“自动生成作文”的所谓“写作软件”——自己尽心尽力写出的文字才是最好的文字。所谓“写作软件”，自然是文字处理软件的意思。 为什么不用Word？Word的确是很多职业作家的选择，但是它的界面过于臃肿，有很多在写作中根本用不到的功能——或者说，它的大部分功能都是在写作过程中根本用不到的。 为什么不用TeX/LaTeX？TeX的确是用于科技论文写作的好软件，不过在文学写作上，用它实在是太屈才了。而且对于文学写作这种感性的创作，WYSIWYG（What You See Is What You Get，所见即所得）的编辑器往往比一长串像代码一样的东西更容易激发人们的写作灵感和写作热情。我想没有人愿意对着一大串代码想象两个人的恋爱的故事该如何继续进行。 为什么不用记事本/VIM/Emacs/etc.？本文的标题是“高效率写作利器”——而文中介绍的几个软件都有这样一个特点，那就是排除一切干扰，让作者专心于写作。具体的实现方法是，程序全屏、没有多余的菜单和按钮、有纯色背景或风景图片背景、有背景音乐等等（这里插一句题外话，记得上次查字典，“等”的意思是“只有以上这些”，“等等”的意思是“除了以上这些还有别的”，希望没记错……）。因为我是个VIM党，所以我对Emacs并不熟悉，不能妄加评论，不过我想VIM应该是不能简单地实现这些功能的。毕竟要想着各种命令就很烦人了…… 因为作者的测试环境是Windows，所以只评测有Windows版本的软件。似乎Mac上有一些非跨平台的软件，有兴趣的读者可以自行搜索。 本文中得出的任何结论都是作者个人的推荐，如果想知道哪一个软件更适合你，最好还是亲自试用一下。 测试环境 计算机：Dell Studio 1450，Core2 Duo P8700，4G，ATI Raedon HD 4530 系统：Windows 7 Ultimate 64-bit 显示器：双屏；外接Philips显示器作为主屏，分辨率1920*1080；笔记本显示器作为副屏，分辨率1366*768。 写在前面 前几天偶然在GR上看到小众软件发表了一篇关于OmmWriter的介绍文章。正好我之前苦寻此类软件未果，就试用了一下，但是个人感觉体验并不是很好。 之后又在这篇文章的评论下面看到有很多人推荐各种各样的写作软件，于是依次试用了一下。后来一想，既然已经尝试了这么多款软件，为什么不写一个评测，让更多的人知道这类软件的存在呢。 于是就有了这篇文章。 这些软件的一个共同特点是，可以让写作者集中精神于自己的工作。利用简单的界面，或者清爽的音乐，营造一种轻松专注的氛围，这是我在这里介绍它们的原因。如果不需要这个特性，那么Word或者记事本（甚至VIM？）会更适合你。 因为之前发预告文章的时候很多人都在说VIM之类的更好，所以这里特别说明一下。此外，我个人认为VIM十分不适合文学写作。 如果你是从人人网上看到这篇文章的，推荐来看原文，人人网上RSS的图片显示可能会有问题。 单独评测 OmmWriter 官方网站：http://www.ommwriter.com/ 安装包：51.2M（zip），单exe安装文件 &#8230; <a href="http://sqybi.com/blog/archives/319">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong><span style="font-size: medium;">几点说明</span></strong></p>
<ul>
<li>欢迎转载，转载请注明出自SQYBI.com，并附上原文链接（最好Trackback 一下）。</li>
<li>本文所提及的软件，并非那种“自动生成作文”的所谓“写作软件”——自己尽心尽力写出的文字才是最好的文字。所谓“写作软件”，自然是文字处理软件的意思。</li>
<li>为什么不用Word？Word的确是很多职业作家的选择，但是它的界面过于臃肿，有很多在写作中根本用不到的功能——或者说，它的大部分功能都是在写作过程中根本用不到的。</li>
<li>为什么不用TeX/LaTeX？TeX的确是用于科技论文写作的好软件，不过在文学写作上，用它实在是太屈才了。而且对于文学写作这种感性的创作，WYSIWYG（What You See Is What You Get，所见即所得）的编辑器往往比一长串像代码一样的东西更容易激发人们的写作灵感和写作热情。我想没有人愿意对着一大串代码想象两个人的恋爱的故事该如何继续进行。</li>
<li>为什么不用记事本/VIM/Emacs/etc.？本文的标题是“高效率写作利器”——而文中介绍的几个软件都有这样一个特点，那就是排除一切干扰，让作者专心于写作。具体的实现方法是，程序全屏、没有多余的菜单和按钮、有纯色背景或风景图片背景、有背景音乐等等（这里插一句题外话，记得上次查字典，“等”的意思是“只有以上这些”，“等等”的意思是“除了以上这些还有别的”，希望没记错……）。因为我是个VIM党，所以我对Emacs并不熟悉，不能妄加评论，不过我想VIM应该是不能简单地实现这些功能的。毕竟要想着各种命令就很烦人了……</li>
<li>因为作者的测试环境是Windows，所以只评测有Windows版本的软件。似乎Mac上有一些非跨平台的软件，有兴趣的读者可以自行搜索。</li>
<li>本文中得出的任何结论都是作者个人的推荐，如果想知道哪一个软件更适合你，最好还是亲自试用一下。</li>
</ul>
<p><strong><span style="font-size: medium;">测试环境</span></strong></p>
<ul>
<li>计算机：Dell Studio 1450，Core2 Duo P8700，4G，ATI Raedon HD 4530</li>
<li>系统：Windows 7 Ultimate 64-bit</li>
<li>显示器：双屏；外接Philips显示器作为主屏，分辨率1920*1080；笔记本显示器作为副屏，分辨率1366*768。</li>
</ul>
<p><strong><span style="font-size: medium;">写在前面</span></strong></p>
<p>前几天偶然在GR上看到<a href="http://www.appinn.com/">小众软件</a>发表了一篇<a href="http://www.appinn.com/ommwriter/">关于OmmWriter的介绍文章</a>。正好我之前苦寻此类软件未果，就试用了一下，但是个人感觉体验并不是很好。<br />
之后又在这篇文章的评论下面看到有很多人推荐各种各样的写作软件，于是依次试用了一下。后来一想，既然已经尝试了这么多款软件，为什么不写一个评测，让更多的人知道这类软件的存在呢。<br />
于是就有了这篇文章。</p>
<p>这些软件的一个共同特点是，可以让写作者集中精神于自己的工作。利用简单的界面，或者清爽的音乐，营造一种轻松专注的氛围，这是我在这里介绍它们的原因。如果不需要这个特性，那么Word或者记事本（甚至VIM？）会更适合你。<br />
因为之前发预告文章的时候很多人都在说VIM之类的更好，所以这里特别说明一下。此外，我个人认为VIM十分不适合文学写作。</p>
<p>如果你是从人人网上看到这篇文章的，推荐来看原文，人人网上RSS的图片显示可能会有问题。</p>
<p><span id="more-319"></span><strong><span style="font-size: medium;">单独评测</span></strong></p>
<p><strong>OmmWriter</strong></p>
<p>官方网站：<a title="http://www.ommwriter.com/" href="http://www.ommwriter.com/">http://www.ommwriter.com/</a><br />
安装包：51.2M（zip），单exe安装文件<br />
版本：0.1.0.15  Dana</p>
<p>OmmWriter，也就是<a href="http://www.appinn.com/">小众软件</a>介绍的那款写作软件。官网做的很漂亮。<br />
似乎以前只能在Mac下面用，最近才推出了Windows平台下的跨平台。<br />
软件分Dana I和Dana II两版，其中Dana I是免费的（也是评测的版本），而Dana II是要收费的，似乎提供了更多的背景图片和音乐（小众说的……）。</p>
<p>安装包看似很大，但是实际上里面有40多M都是背景音乐。<br />
安装过程十分简洁，但是有点简洁过头了，连选择安装路径的余地都没有——其实没有任何选项可供选择。在本机安装在了C:\Program Files (x86)\HerraizSoto\OmmWriter的目录下，可以看到是32位程序。</p>
<p>软件自动在主屏打开。在打开的时候，副屏变黑，不能进行任何操作，需要在另外一个屏幕查看资料的话略有不便。<br />
界面很简洁，第一感觉很不错。<br />
背景默认是一张颜色很淡的图片，可以更换为乳白色或暗灰色的纯色背景。<br />
背景音乐也有几首可以更换，都是类似钟声的很舒适的音乐。按键音也有几个不同的设置，但是按键音略小，很难听清，所以没感觉到设置与不设置有何不同。</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/04/OmmWriter1.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="OmmWriter1" src="http://sqybi.com/blog/wp-content/uploads/2011/04/OmmWriter1_thumb.jpg" border="0" alt="OmmWriter1" width="644" height="364" /></a></p>
<p>字体可以选择四种内置的，但是无论选择何种字体，中文字体没有变化（只有大小的变化）。也可以设置四种不同的字体大小。<br />
默认的中文字体看起来不是那么舒服，可惜不能更改。</p>
<p>文本编辑框可以拉动和改变大小，不过滚动条却在界面的最右边。对于大屏用户，拉动滚动条时鼠标需要移动不少距离。<br />
编辑框下方有文章的字数统计，但是对于中文的统计不正确。</p>
<p>将鼠标移动到最顶端，会出现熟悉的菜单栏。File菜单中有一个Export to PDF的命令，可以直接导出当前编辑的文字为PDF。不过导出的中文是乱码，十分遗憾。</p>
<p>可以选择保存文档为omm或txt格式，omm格式与txt格式实际上完全相同，只是扩展名改了一下——不知道有什么意义。</p>
<p><strong>语思</strong></p>
<p>官方网站：<a title="http://www.cryrivers.com/exoterica/zh-CN/" href="http://www.cryrivers.com/exoterica/zh-CN/">http://www.cryrivers.com/exoterica/zh-CN/</a><br />
安装包：25.3M（zip），多安装文件<br />
版本：N/A（抢先版）</p>
<p>有人说语思是OmmWriter的中国山寨版，不过实际上用起来感觉并不是这样。界面风格和感觉都很有自己的特点，作为国产软件，还是值得赞扬的。<br />
不过可能因为是“抢先版”，bug多多。软件的稳定性还十分值得提升。</p>
<p>安装包是Windows Installer制作的，说实话我对这种安装包实在没什么好感。软件需要提前安装.NET Framework 4.0才可以使用。<br />
安装的过程中，同样没有任何设置选项。测试机器上，默认安装在C:\Program Files (x86)\littleBigDream\语思，无法更改。</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/04/ys1.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="ys1" src="http://sqybi.com/blog/wp-content/uploads/2011/04/ys1_thumb.jpg" border="0" alt="ys1" width="644" height="364" /></a></p>
<p>双屏的情况下，软件在主屏打开，副屏也可以继续使用。两个屏幕之间操作十分方便，完全可以一边写作一边查资料，做到无缝切换。<br />
软件默认是一个木质感的背景。下面有一个按钮可以切换日间、夜间模式，但是不知道为什么，切换之后就只能使用纯白和纯黑的背景了，再也调不回木质背景。<br />
软件没有任何声音。</p>
<p>设置选项很少，或者说几乎没有。只有界面最下方的几个按钮。但就算是这几个按钮，也是bug多多。<br />
唯一没有bug的，是最右边的那个按钮。把鼠标放在上面，滚动滚轮，就可以调整文字大小。不过考虑到可能有用户没有滚轮，这个设计并不是什么好设计。<br />
一个bug是刚才提到的，切换日间、夜间模式之后，木质界面会消失。另外左下角的垃圾箱图标，不知道是做什么用了，只要点了程序就会直接崩溃。<br />
另外，保存文件的图标，点击之后界面也会出现混乱。实际上如果什么都不动的话，可以直接用界面右边的几个选项保存。除了保存为txt，还可以存为doc格式或直接复制到剪切板。<br />
最后一个图标，就是显示“00:00:00”的那个图标。点击一下，会发现这个图标上面的文字变成了“250字”，猜测是一个定时休息的功能。不过似乎没有完成，因为我至今没找到如何设置时间和字数。</p>
<p>软件的编辑区，字体是微软雅黑无法更改，但是似乎没有开启ClearType（整个界面都是这样），所以效果不是很好。<br />
编辑区右侧有一个滚动条，但是颜色太浅太细，以至于我刚开始找了好久都没找到。</p>
<p>一个亮点是，软件的左上角会显示当前系统时间，对于这种全屏的软件来说，这是十分必要的。<br />
另外一个亮点是，切换输入法的时候，软件会提示当前在使用什么输入法。这点是相当有中国特色的。</p>
<p>软件每次退出之后都会提示错误，十分烦人。</p>
<p><strong>CreaWriter</strong></p>
<p>官方网站：<a title="http://www.creawriter.com/" href="http://www.creawriter.com/">http://www.creawriter.com/</a><br />
安装包：5.6M，单exe安装文件<br />
版本：1.0.1.10</p>
<p>软件的官网很简洁，但是单栏式设计似乎不太方便查找内容。<br />
软件有两个版本，Free edition和Donor version（为啥一个是edition一个是version？搞不懂……），后者是要捐助之后才可以使用的，多了一些功能，其实说白了就是收费版。<br />
本文测试的是Free edition。<br />
需要提前安装.NET Framework 3.5，Win7已经自带了。</p>
<p>安装包很小，安装的时候可以选择路径。这应该是正常的软件安装包都有的功能吧，前面两个软件全都不支持这个功能，搞得我现在看到这个功能倒觉得眼前一亮……<br />
安装之后也几乎只有一个主程序和两个背景音乐的文件而已，十分简洁。</p>
<p>软件打开之后，会看到一张海边日落的背景图。而默认的背景音乐则是烧干柴的声音，真是有特点。想想某天深夜，在野外露营的你拿出随身带的笔记本电脑，伴着篝火写作，感觉的确不错。<br />
按键音在Donor版本里才可以用，不过没什么太大影响。至少我的机械键盘声音完全可以盖过按键音了……<br />
双屏的时候，主屏打开软件，副屏可以继续使用。</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/04/crea1.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="crea1" src="http://sqybi.com/blog/wp-content/uploads/2011/04/crea1_thumb.jpg" border="0" alt="crea1" width="644" height="364" /></a></p>
<p>将鼠标移到屏幕两侧，就可以看到很多设置选项。左侧的选项是设置字体的，而右侧的选项是功能选项。</p>
<p>默认的字体是宋体，显示效果不错。<br />
左侧设置字体的选项可以针对某一段文字单独设置！这一点还是有一些必要的，很多作家习惯用粗体来标出某些文字。<br />
但是可惜的是，粗体、斜体和下划线功能只能在Donor Version中使用，免费版只能针对某一段文字调整字号和字体（实际上只会改变英文字体，中文字体永远是宋体）。</p>
<p>右边的按钮上面都是一些英文缩写，基本能够看懂。鼠标移上去会有完整的功能说明。<br />
其中有新建、保存这种必备功能，也有开关背景音乐、背景图片的功能（背景图片关闭后会变成纯色）。而Trc则是可以设置整个软件的透明度，不过为了专注，其实还是不要设置的好。<br />
而Cfg则是整个软件的设置窗口，里面有不少设置。</p>
<p>软件可以设置背景图片和背景音乐为自己的图片或音乐，这个功能很不错。<br />
另外，可以单独为文本区设置颜色和透明度。</p>
<p>在设置窗口中还可以看到两个功能，一个是Break Timer，另一个是自动保存。<br />
前者就是语思里面没有实现的定时休息功能，只可以设置每隔一定时间休息一定时间，不能按照写作字数休息。<br />
而自动保存则比较简单，只能设置自动保存的文件路径。</p>
<p>软件没有任何统计功能，十分遗憾。不过官网上说有“Status bar with: word count (donor version), line &amp; column position, date and time, file name”，可是找了好久也没找到在哪儿。<br />
此外，编辑区没有滚动条，鼠标滚轮也不能滚动，实在是不应该。</p>
<p>可以把编辑的文字保存为rtf或txt格式，其中rtf可以将编辑的字体大小、粗体、斜体等内容保存下来。</p>
<p><strong>Dark Room</strong></p>
<p>官方网站：<a title="http://they.misled.us/dark-room" href="http://they.misled.us/dark-room">http://they.misled.us/dark-room</a><br />
安装包：46.1K（zip），绿色单文件<br />
版本：0.8b</p>
<p>官方说这个软件来源于一个Mac下的软件，WriteRoom。</p>
<p>这个软件是绿色的！而且体积相当小，很赞。<br />
不过相对应的，软件的功能简洁到了一定程度。几乎只有一些基本功能，而且大部分都要用快捷键实现，比如打开、保存等。<br />
在编辑区点右键，会弹出一个菜单，选择最下面的“Preferences”就可以打开设置窗口。</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/04/br.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="br" src="http://sqybi.com/blog/wp-content/uploads/2011/04/br_thumb.jpg" border="0" alt="br" width="644" height="364" /></a></p>
<p>可以设置软件的字体和字体颜色，还有编辑区域大小。<br />
此外，这款软件是可以设置多屏支持的，能够自由选择副屏是显示黑屏还是能够正常使用。这是此次评测唯一一款可以设置多屏支持的软件。</p>
<p>软件支持自动保存，不过只是有一个打开自动保存与否的选项，没有任何其它的设置选项。</p>
<p>另外两个特殊的设置是，自动将Tab转换为空格，以及在系统右键菜单中加入“用Dark Room打开”的选项。我甚至有点怀疑，这个软件的定位是不是一个文本编辑器……</p>
<p>可以用滚轮上下翻页，也可以使用右侧的四个按钮。另外，这四个按钮是可以在设置菜单中去掉的。</p>
<p>关于快捷键的说明，官网上已经给详细地给出了。</p>
<p><strong>Q10</strong></p>
<p>官方网站：<a title="http://www.baara.com/q10/" href="http://www.baara.com/q10/">http://www.baara.com/q10/</a><br />
安装包：400K，单exe安装文件<br />
版本：1.2.21</p>
<p>软件安装包很小，让人怀疑这款软件是不是和Dark Room一样过于简洁了。不过测试中发现，这款软件的功能还是很齐全的，不像Dark Room那样简洁得过头。<br />
安装的时候可以选择路径。</p>
<p>和DR类似，软件十分依赖快捷键。不过一个很好的设计是，F1键就可以呼出快捷键列表，方便快速查询快捷键。</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/04/q10.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="q10" src="http://sqybi.com/blog/wp-content/uploads/2011/04/q10_thumb.jpg" border="0" alt="q10" width="644" height="364" /></a></p>
<p>而软件可以说常用功能应有尽有。<br />
下面的状态栏可以显示字数统计、行数统计、字符数统计等信息，还有系统时间。只可惜中文的字数统计并不正确——这是这类软件的通病，毕竟都是老外写的嘛，唯一一个国产软件还没有这个功能。<br />
此外，可以设置一个Alarm，虽然不是强制休息，不过依然可以做到连续写作一定时间之后提示的功能。<br />
软件还有一个Global Target的功能，你可以选择文章的目标字数，然后状态栏中就会显示你完成了目标的百分之多少。对征文时控制字数十分有效。</p>
<p>Ctrl-P可以打开设置窗口。这个软件的设置也是十分详细的。<br />
除了字体和字号设置，软件还可以设置行间距和段间距，这是别的软件没有的功能。<br />
编辑区域的大小也可以在其中设置。</p>
<p>自动更正和Quick Text两个功能，算是这个软件比较独特的功能。前者不用多说，用过Word的人都知道。而后者则是将某一段文字（可能是文章里经常出现的人名地名等）用一段更简单的文字代替，加快写作速度。</p>
<p>软件可以开启按键音，似乎是打字机的声音。但是输入中文的时候因为输入法的原因没有声音。</p>
<p>此外，软件还有一个叫Notes的功能。刚开始我以为是可以做一些Note，后来发现并不是这样。官方网站上的解释是：<br />
“Any paragraph starting with ".." is considered a note. You can get a list of all notes in the current document and jump instantly to any of them.”<br />
也就是说，只要在某一段前面加上两个句点，就可以用这个功能快速跳转到这一段。测试了一下，快捷键是Ctrl-H。</p>
<p><strong>WriteMonkey</strong></p>
<p>官方网站：<a title="http://writemonkey.com/" href="http://writemonkey.com/">http://writemonkey.com/</a><br />
安装包：2.3M（zip），绿色多文件<br />
版本：2.0.1</p>
<p>这个软件是今天才看到的，官方网站十分有Geek风范。<br />
但是因为软件不支持中文输入法，所以没有详细评测，只有一个截图。进行英文写作的读者可以进一步尝试。</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2011/04/wm.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="wm" src="http://sqybi.com/blog/wp-content/uploads/2011/04/wm_thumb.jpg" border="0" alt="wm" width="644" height="364" /></a></p>
<p><strong><span style="font-size: small;">总结</span></strong></p>
<p>以上总共有六款软件。本来想列个表来总结一下每个软件都有哪些功能的，但是后来发现这六款软件的功能实在是太五花八门，这个总结有些困难。实际上，每个软件的介绍中已经提到了软件的大部分功能，所以这个总结就不做了。</p>
<p>以作者本人来看，Q10和CreaWriter是比较好的选择。<br />
WriteMonkey不支持中文输入法令人惋惜；而OmmWriter则是字体比较不爽；语思的bug太多，以后的版本或许会越来越好。<br />
Dark Room算是比较特殊的一款，过于简洁以及功能的定位，让我有些怀疑要不要把它列入这次的名单之中。它更像是一个普通的文本编辑器。</p>
<p>而Q10和CreaWriter中，CreaWriter的界面比较华丽，而Q10的界面比较简洁，可以算是两个方向的定位。作者选择的是Q10，读者可以根据喜好进行选择（甚至更简洁的Dark Room？）。</p>
<p>当然，如果读者发现有什么其它的优秀写作软件，也可以在文章下面留言说明。</p>
<p>---------- 人肉分隔线 ----------</p>
<p>题外话，你有没有发现每个截图上的文字都不一样呢？<br />
它们分别来自：<br />
《学生会的一己之见》《狼与香辛料》《文学少女》《笨蛋·测验·召唤兽》《凉宫春日》《虫之歌》<br />
各自的第一卷第一章。</p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/319/feed</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Gmail的哪些功能吸引了我？[updated]</title>
		<link>http://sqybi.com/blog/archives/306</link>
		<comments>http://sqybi.com/blog/archives/306#comments</comments>
		<pubDate>Thu, 14 Apr 2011 03:53:42 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[Technology]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/archives/306</guid>
		<description><![CDATA[昨天在人人上发了个关于Gmail的状态，引发了热烈讨论。某同学表示不知道为什么有那么多人在用Gmail，然后瞬间蹦出N个回复提出了Gmail的种种优点。 仔细想想，为什么Gmail这么吸引我呢？ 很早以前，我的第一个邮箱是sohu邮箱，用户名我还记得，是jk041。真的是很早以前的事情了。之后几乎尝试过国内每一个著名邮箱（正如当初几乎尝试过国内每一个著名BSP），然后换到了新浪。再后来，126邮箱似乎率先推出了什么功能（好像是无限容量，我也记不太清了），于是转到了126邮箱，而且那个邮箱也持续用到今天。 但是，实际上，现在的126邮箱对于我只是一个收垃圾邮件用的邮箱——所有网站的注册都用126的邮箱，然后私人的邮件都用Gmail。我已经忘了自己是什么时候开始用Gmail的，不过的确最开始的时候我也不觉得Gmail有什么好的功能，甚至觉得很难“上手”。不过某一次连续用了一个礼拜Gmail之后，我才发现原来这个邮箱真的这么优秀，国内没有任何一个邮箱能够与其比肩，甚至赶不上它的十分之一（国外估计也不会有吧？）。 这时我才发现，所谓很难“上手”，实际上只是迁移成本罢了，当初国内邮箱“上手”的时候，没有一个比Gmail更容易多少。Gmail已经在易用性和用户体验中间找到了一个十分良好的平衡点，国内邮箱互相的迁移成本低，是因为中国的网络产品“抄”的现象太严重，结果每个邮箱界面都一样，用起来感觉都一样，不一样的只剩下了域名。 扯淡扯太多了。那么回归正题，Gmail到底有哪些功能吸引了我呢？ ---------- 以下是Gmail默认开启的功能 ---------- 界面布局 之所以把这个放在第一个，是因为国内邮箱千篇一律的页面布局实在让人头疼。Gmail将Mail、Contacts和Tasks整合在了一起，对功能进行了分块。上面的搜索框也很有Google特色，用起来相当方便。通过Labs的功能，还可以对界面进行进一步改造（比如把Inbox分成多个，把Gtalk放到右边之类）。其实这个也不算太亮的亮点，但是用起来的确很舒服。 标签管理 这个是Gmail一个很核心的功能，可以说，如果不用这个功能，Gmail就浪费了一半。 虽然标签管理本身并不能带给我们什么体验上质的飞跃，但是它可以和很多功能相互配合使用，比如代收取邮件、过滤器和Archive等。可以发现，这时标签功能才真正展现出它的实力，把一切都统一成标签，简洁明了，完全不是国内邮箱那样，一个文件夹列表，一个代收取的邮箱列表，大大限制了灵活性。 Archive 这个功能可以说完全依赖标签才得以实现。有的邮件可能已经没有什么用处了，或许是谈论某个project然后project已经完成，或许是向教授套磁然后失败了……不管怎样，这种邮件会有一种删也不是不删也不是的感觉。这时怎么办？Archive功能告诉你，你可以把它从inbox中完全隐藏掉，但是这个邮件不会被删除，想要读的时候，搜索功能可以帮你忙。 这个功能的实现是，Inbox里的邮件都会被自动加上“Inbox”这样一个标签，只要把这个标签去掉，邮件就不会再在Inbox中出现了——这就是Archive功能。 代收取邮件 这个功能很多国内邮箱也已经开发了，不过至少我用126邮箱的时候，从来没收取成功过。Gmail的收取功能是十分稳定的，从来没有出错（除了126十分傻X地把POP端口只开放给本地客户端导致收取失败）。 配合Label，可以给每个邮箱收取的邮件标上不同的标签不同的颜色，一目了然。Labs里的Multiple Inbox功能，还可以在Inbox页同时显示多个Inbox，完全让Gmail替代、超越本地客户端。 可以说，这个功能是邮箱迁移的利器，也是多邮箱用户必用的功能。 Prioirty Inbox 这个功能也是Google最近才推出的，效果相当不错。 它可以通过邮件的内容，自动判断这封邮件是不是“重要”邮件。如果是“重要”邮件，就会在Priority Inbox的最前面集中显示出来。 上学期当助教的时候，我的邮箱受到了各种邮件轰炸，这个功能帮了我大忙。准确率令人发指啊，和垃圾邮件过滤的准确率有的一拼。 垃圾邮件过滤 既然提到了，就来说说垃圾邮件过滤。 我这个Gmail邮箱也和其它邮箱一样，每天收到十来封甚至几十封垃圾邮件。但是，Gmail的垃圾邮件过滤系统真的强大到了一定程度。至今为止，我似乎还没有任何有用邮件被识别为垃圾邮件的记忆；而垃圾邮件的漏网率，大概也不到百分之一——其实一个月也没有一封漏网的。 这么强大的垃圾邮件过滤器，大概是我选用Gmail的根本原因吧。 联系人管理 这个没什么亮点，不过给人感觉不差就是了。和国内的邮箱比起来，这个联系人管理可谓简单得多，怎么看上手也不会比国内那些乱七八糟的联系人管理难吧。 内嵌Google Talk和Google Tasks Google服务之间的整合做的相当不错。这个不多说了，内嵌的Gtalk估计每个Gmail邮箱用户都用过吧。Tasks虽然我没有用，但是放在邮箱里绝对没有错，想想那么多人热衷的Outlook就知道。 和Android手机的同步 安卓手机会和Google服务有紧密结合度是理所当然的事情。我现在的Milestone，通讯录是和Google &#8230; <a href="http://sqybi.com/blog/archives/306">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>昨天在人人上发了个关于Gmail的状态，引发了热烈讨论。某同学表示不知道为什么有那么多人在用Gmail，然后瞬间蹦出N个回复提出了Gmail的种种优点。<br />
仔细想想，为什么Gmail这么吸引我呢？</p>
<p>很早以前，我的第一个邮箱是sohu邮箱，用户名我还记得，是jk041。真的是很早以前的事情了。之后几乎尝试过国内每一个著名邮箱（正如当初几乎尝试过国内每一个著名BSP），然后换到了新浪。再后来，126邮箱似乎率先推出了什么功能（好像是无限容量，我也记不太清了），于是转到了126邮箱，而且那个邮箱也持续用到今天。<br />
但是，实际上，现在的126邮箱对于我只是一个收垃圾邮件用的邮箱——所有网站的注册都用126的邮箱，然后私人的邮件都用Gmail。我已经忘了自己是什么时候开始用Gmail的，不过的确最开始的时候我也不觉得Gmail有什么好的功能，甚至觉得很难“上手”。不过某一次连续用了一个礼拜Gmail之后，我才发现原来这个邮箱真的这么优秀，国内没有任何一个邮箱能够与其比肩，甚至赶不上它的十分之一（国外估计也不会有吧？）。</p>
<p>这时我才发现，所谓很难“上手”，实际上只是迁移成本罢了，当初国内邮箱“上手”的时候，没有一个比Gmail更容易多少。Gmail已经在易用性和用户体验中间找到了一个十分良好的平衡点，国内邮箱互相的迁移成本低，是因为中国的网络产品“抄”的现象太严重，结果每个邮箱界面都一样，用起来感觉都一样，不一样的只剩下了域名。</p>
<p>扯淡扯太多了。那么回归正题，Gmail到底有哪些功能吸引了我呢？</p>
<p>---------- 以下是Gmail默认开启的功能 ----------</p>
<p><strong>界面布局</strong></p>
<p>之所以把这个放在第一个，是因为国内邮箱千篇一律的页面布局实在让人头疼。Gmail将Mail、Contacts和Tasks整合在了一起，对功能进行了分块。上面的搜索框也很有Google特色，用起来相当方便。通过Labs的功能，还可以对界面进行进一步改造（比如把Inbox分成多个，把Gtalk放到右边之类）。其实这个也不算太亮的亮点，但是用起来的确很舒服。</p>
<p><strong>标签管理</strong></p>
<p>这个是Gmail一个很核心的功能，可以说，如果不用这个功能，Gmail就浪费了一半。<br />
虽然标签管理本身并不能带给我们什么体验上质的飞跃，但是它可以和很多功能相互配合使用，比如代收取邮件、过滤器和Archive等。可以发现，这时标签功能才真正展现出它的实力，把一切都统一成标签，简洁明了，完全不是国内邮箱那样，一个文件夹列表，一个代收取的邮箱列表，大大限制了灵活性。</p>
<p><strong>Archive</strong></p>
<p>这个功能可以说完全依赖标签才得以实现。有的邮件可能已经没有什么用处了，或许是谈论某个project然后project已经完成，或许是向教授套磁然后失败了……不管怎样，这种邮件会有一种删也不是不删也不是的感觉。这时怎么办？Archive功能告诉你，你可以把它从inbox中完全隐藏掉，但是这个邮件不会被删除，想要读的时候，搜索功能可以帮你忙。<br />
这个功能的实现是，Inbox里的邮件都会被自动加上“Inbox”这样一个标签，只要把这个标签去掉，邮件就不会再在Inbox中出现了——这就是Archive功能。</p>
<p><strong>代收取邮件</strong></p>
<p>这个功能很多国内邮箱也已经开发了，不过至少我用126邮箱的时候，从来没收取成功过。Gmail的收取功能是十分稳定的，从来没有出错（除了126十分傻X地把POP端口只开放给本地客户端导致收取失败）。<br />
配合Label，可以给每个邮箱收取的邮件标上不同的标签不同的颜色，一目了然。Labs里的Multiple Inbox功能，还可以在Inbox页同时显示多个Inbox，完全让Gmail替代、超越本地客户端。<br />
可以说，这个功能是邮箱迁移的利器，也是多邮箱用户必用的功能。</p>
<p><strong>Prioirty Inbox</strong></p>
<p>这个功能也是Google最近才推出的，效果相当不错。<br />
它可以通过邮件的内容，自动判断这封邮件是不是“重要”邮件。如果是“重要”邮件，就会在Priority Inbox的最前面集中显示出来。<br />
上学期当助教的时候，我的邮箱受到了各种邮件轰炸，这个功能帮了我大忙。准确率令人发指啊，和垃圾邮件过滤的准确率有的一拼。</p>
<p><strong>垃圾邮件过滤</strong></p>
<p>既然提到了，就来说说垃圾邮件过滤。<br />
我这个Gmail邮箱也和其它邮箱一样，每天收到十来封甚至几十封垃圾邮件。但是，Gmail的垃圾邮件过滤系统真的强大到了一定程度。至今为止，我似乎还没有任何有用邮件被识别为垃圾邮件的记忆；而垃圾邮件的漏网率，大概也不到百分之一——其实一个月也没有一封漏网的。<br />
这么强大的垃圾邮件过滤器，大概是我选用Gmail的根本原因吧。</p>
<p><strong>联系人管理</strong></p>
<p>这个没什么亮点，不过给人感觉不差就是了。和国内的邮箱比起来，这个联系人管理可谓简单得多，怎么看上手也不会比国内那些乱七八糟的联系人管理难吧。</p>
<p><strong>内嵌Google Talk和Google Tasks</strong></p>
<p>Google服务之间的整合做的相当不错。这个不多说了，内嵌的Gtalk估计每个Gmail邮箱用户都用过吧。Tasks虽然我没有用，但是放在邮箱里绝对没有错，想想那么多人热衷的Outlook就知道。</p>
<p><strong>和Android手机的同步</strong></p>
<p>安卓手机会和Google服务有紧密结合度是理所当然的事情。我现在的Milestone，通讯录是和Google Contact同步的，然后会自动收取Gmail，可以把Gtalk当短信用，Google Calendar上记录了课程表……总之都是完美协作，感觉那叫一个爽。</p>
<p><span style="color: #ff0000;"><strong>会话式邮件</strong></span></p>
<p>最重要的功能差点忘掉了，感谢winsty提醒！Gmail的Conversation Mail是最重要的一个功能，也是最实用的功能。抛弃以前乱七八糟的各种Re，用会话的形式把re的邮件组合到一起，用户体验绝对一流！这也是我抛弃本地客户端转投网页版Gmail最重要的原因。</p>
<p>---------- 以下是Labs中的功能 ----------</p>
<p><strong>Message Sneak</strong></p>
<p>右键点击邮件可以预览。算是补充了一个Gmail缺少的功能吧。</p>
<p><strong>Undo Send</strong></p>
<p>很多邮箱都缺少的一个功能。邮件会延迟几秒发送，在此期间可以取消邮件的发送。万一点错了或者发现忘了加附件，可以直接Undo，不用重新发邮件解释。</p>
<p><strong>Google Calendar Gadget</strong></p>
<p>把Google日历嵌入到Gmail，Google Task都有了，日历怎么能没有！</p>
<p><strong>Google Docs Preview</strong></p>
<p>有这个功能可谓情理之中。对于各种文档，Gmail中可以直接调用Google Doc进行预览。<br />
只不过，因为某些众所周知的原因，Google Doc经常打不开就是了……</p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/306/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>[zz from Nxun.com] Windows7中的扫雷</title>
		<link>http://sqybi.com/blog/archives/263</link>
		<comments>http://sqybi.com/blog/archives/263#comments</comments>
		<pubDate>Sun, 21 Nov 2010 01:45:48 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[Technology]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/archives/263</guid>
		<description><![CDATA[以下内容转载自Nxun的blog：http://blog.nxun.com/archives/35#comment-215。 ------------------------------------人肉分隔线------------------------------------ 扫雷游戏(Minesweeper)，自从1981年 Windows 3.1 出现以来，此款游戏的流行程度从未减退。在此不对游戏的规则及策略作介绍，如果您真的不清楚这是什么，请自行询问身边的朋友。 本人最近就迷上了 Windows 7 中自带的扫雷游戏，很OUT是吧，冒着被喷的危险，与大家分享点有趣的见闻。 Windows 7 / Vista 中的扫雷游戏，与 Windows XP / 2000 / 98- 中的比起来，游戏体验终于有了质的提升，从清新醒目的配色到简洁明快的动画效果，可见微软在此还是倾注了一定的心血。 新版本的改动并不仅限于画面效果，一个重要的变化是地雷的布局算法。有经验的扫雷玩家可能都知道，在一局扫雷游戏中，第一个点开的方块一定不是地雷。这一点不用怀疑，因为这不是概率问题，一个设计良好的扫雷游戏不会让你直接点到雷上，它们或者在点开第一个方块后再布局地雷，或者把第一下点到的地雷换到其他地方去。在Win7新版本扫雷中，做出了更加人性化的改动，第一个点开的方块连同周围8个方块（如果有的话）保证都不是地雷，使用9*9雷数最多的自定义游戏也可以证实这一点。 在XP扫雷（高级）中点开的第一个方块 在Win7扫雷（高级）中点开的第一个方块 9*9雷数67的自定义游戏 这样做给玩家带来的好处是显而易见的，因为开局点开一个孤立的方块几乎没有任何价值。事实上微软考虑的可能更多，我随便在高级游戏中测试了几次，几乎每次第一下都会点开一大片区域（超过20块），稍微计算一下便可知道这种概率并不高，唯一合适的解释就是游戏“智能”的为玩家提供了一个舒适的开局。 这里还有一个有趣的小程序，如果您对本文第一张截图感觉好奇，可以试一下。在这里下载。 实现原理见作者的这篇文章。 ------------------------------------人肉分隔线------------------------------------ 上面提供的程序下载经我测试在我这里无法运行，inject后找不到某个模块，所以懒得再传到我blog上了。可能和我是64位有关，想要自己试一下的请去原文照下载链接。 其实这几天在和Nxun玩扫雷，既然他开始研究扫雷的布局算法了，那我看来要多看看解扫雷的算法了……总感觉可以转化为一个完整的数学模型来解……]]></description>
			<content:encoded><![CDATA[<ul>
<li>以下内容转载自Nxun的blog：<a href="http://blog.nxun.com/archives/35#comment-215">http://blog.nxun.com/archives/35#comment-215</a>。</li>
</ul>
<p>------------------------------------人肉分隔线------------------------------------</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2010/11/mine.png"><img style="display: inline" title="mine" alt="mine" src="http://sqybi.com/blog/wp-content/uploads/2010/11/mine_thumb.png" width="616" height="409" /></a></p>
<p>扫雷游戏(Minesweeper)，自从1981年 Windows 3.1 出现以来，此款游戏的流行程度从未减退。在此不对游戏的规则及策略作介绍，如果您真的不清楚这是什么，请自行询问身边的朋友。</p>
<p>本人最近就迷上了 Windows 7 中自带的扫雷游戏，很OUT是吧，冒着被喷的危险，与大家分享点有趣的见闻。</p>
<p>Windows 7 / Vista 中的扫雷游戏，与 Windows XP / 2000 / 98- 中的比起来，游戏体验终于有了质的提升，从清新醒目的配色到简洁明快的动画效果，可见微软在此还是倾注了一定的心血。</p>
<p>新版本的改动并不仅限于画面效果，<strong>一个重要的变化是地雷的布局算法</strong>。有经验的扫雷玩家可能都知道，在一局扫雷游戏中，第一个点开的方块一定不是地雷。这一点不用怀疑，因为这不是概率问题，一个设计良好的扫雷游戏不会让你直接点到雷上，它们或者在点开第一个方块后再布局地雷，或者把第一下点到的地雷换到其他地方去。在Win7新版本扫雷中，做出了更加人性化的改动，第一个点开的方块连同周围8个方块（如果有的话）保证都不是地雷，使用9*9雷数最多的自定义游戏也可以证实这一点。</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2010/11/mine_in_xp.png"><img style="display: inline" title="mine_in_xp" alt="mine_in_xp" src="http://sqybi.com/blog/wp-content/uploads/2010/11/mine_in_xp_thumb.png" width="506" height="371" /></a>    <br />在XP扫雷（高级）中点开的第一个方块</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2010/11/mine_in_win7_a.png"><img style="display: inline" title="mine_in_win7_a" alt="mine_in_win7_a" src="http://sqybi.com/blog/wp-content/uploads/2010/11/mine_in_win7_a_thumb.png" width="616" height="409" /></a>    <br />在Win7扫雷（高级）中点开的第一个方块</p>
<p><a href="http://sqybi.com/blog/wp-content/uploads/2010/11/mine_in_win7_b.png"><img style="display: inline" title="mine_in_win7_b" alt="mine_in_win7_b" src="http://sqybi.com/blog/wp-content/uploads/2010/11/mine_in_win7_b_thumb.png" width="238" height="283" /></a>    <br />9*9雷数67的自定义游戏</p>
<p>这样做给玩家带来的好处是显而易见的，因为开局点开一个孤立的方块几乎没有任何价值。事实上微软考虑的可能更多，我随便在高级游戏中测试了几次，几乎每次第一下都会点开一大片区域（超过20块），稍微计算一下便可知道这种概率并不高，唯一合适的解释就是游戏“智能”的为玩家提供了一个舒适的开局。</p>
<p>这里还有一个有趣的小程序，如果您对本文第一张截图感觉好奇，可以试一下。<strike>在这里下载。     <br /></strike>实现原理见作者的<a href="http://cnbeta2004.blog.163.com/blog/static/602313402010820101425385/">这篇文章</a>。</p>
<p>------------------------------------人肉分隔线------------------------------------</p>
<p>上面提供的程序下载经我测试在我这里无法运行，inject后找不到某个模块，所以懒得再传到我blog上了。可能和我是64位有关，想要自己试一下的请去原文照下载链接。</p>
<p>其实这几天在和Nxun玩扫雷，既然他开始研究扫雷的布局算法了，那我看来要多看看解扫雷的算法了……总感觉可以转化为一个完整的数学模型来解……</p>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/263/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DS大作业的两段代码</title>
		<link>http://sqybi.com/blog/archives/246</link>
		<comments>http://sqybi.com/blog/archives/246#comments</comments>
		<pubDate>Sat, 25 Sep 2010 15:33:15 +0000</pubDate>
		<dc:creator>sqybi</dc:creator>
				<category><![CDATA[About Computer]]></category>
		<category><![CDATA[[OI, ACM, etc]]]></category>

		<guid isPermaLink="false">http://sqybi.com/blog/?p=246</guid>
		<description><![CDATA[  #include &#60;iostream&#62; using namespace std; class OutOfBound {}; class IllegalSize {}; template &#60;class elemType&#62; class list { public: virtual void clear() = 0; virtual int length() const = 0; virtual void insert(int i, const elemType &#38;x) = 0; virtual &#8230; <a href="http://sqybi.com/blog/archives/246">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p> </p>
<pre class="brush:cpp">#include &lt;iostream&gt;

using namespace std;

class OutOfBound {};
class IllegalSize {};

template &lt;class elemType&gt;
class list
{
public:
    virtual void clear() = 0;
    virtual int length() const = 0;
    virtual void insert(int i, const elemType &amp;x) = 0;
    virtual void remove(int i) = 0;
    virtual int search(const elemType &amp;x) const = 0;
    virtual elemType visit(int i) const = 0;
    virtual void traverse() const = 0;
    virtual ~list() {};
};

template &lt;class elemType&gt;
class seqList: public list&lt;elemType&gt;
{
private:
    elemType *data;
    int currentLength;
    int maxSize;

    void doubleSpace();

public:
    seqList(int initSize = 10);
    ~seqList() { delete [] data; }

    void clear() { currentLength = 0; }
    int length() const { return currentLength; }
    void insert(int i, const elemType &amp;x);
    void remove(int i);
    int search(const elemType &amp;x) const;
    elemType visit(int i) const;
    void traverse() const;

    //new part
    seqList operator + (const seqList&lt;elemType&gt; &amp;x);
    seqList operator = (const seqList&lt;elemType&gt; &amp;x);
};

template &lt;class elemType&gt;
seqList&lt;elemType&gt;::seqList(int initSize)
{
    if (initSize &lt;= 0) throw IllegalSize();
    data = new elemType[initSize];
    maxSize = initSize;
    currentLength = 0;
}

template &lt;class elemType&gt;
void seqList&lt;elemType&gt;::doubleSpace()
{

    elemType *tmp = data;
    if (maxSize == 0)
        maxSize *= 2;
    else
        maxSize = 1;
    data = new elemType[maxSize];
    for (int i = 0; i &lt; currentLength; ++i)
        data[i] = tmp[i];
    delete [] tmp;
}

template &lt;class elemType&gt;
void seqList&lt;elemType&gt;::insert(int i, const elemType &amp;x)
{
    if (i &lt; 0 || i &gt; currentLength) throw OutOfBound();
    if (currentLength == maxSize) doubleSpace();
    for (int j = currentLength; j &gt; i; j--)
        data[j] = data[j - 1];
    data[i] = x;
    ++currentLength;
}

template &lt;class elemType&gt;
void seqList&lt;elemType&gt;::remove(int i)
{
    if (i &lt; 0 || i &gt; currentLength - 1) throw OutOfBound();
    for (int j = i; j &lt; currentLength - 1; j++)
        data[j] = data[j + 1];
    --currentLength;
}

template &lt;class elemType&gt;
int seqList&lt;elemType&gt;::search(const elemType &amp;x) const
{
    int i;
    for (i = 0; i &lt; currentLength &amp;&amp; data[i] != x; ++i);
    if (i == currentLength)
        return -1;
    else
        return 1;
}

template &lt;class elemType&gt;
elemType seqList&lt;elemType&gt;::visit(int i) const
{
    if (i &lt; 0 || i &gt; currentLength - 1) throw OutOfBound();
    return data[i];
}

template &lt;class elemType&gt;
void seqList&lt;elemType&gt;::traverse() const
{
    for (int i = 0; i &lt; currentLength; ++i)
        cout &lt;&lt; data[i] &lt;&lt; " ";
    cout &lt;&lt; endl;
}

template &lt;class elemType&gt;
seqList&lt;elemType&gt; seqList&lt;elemType&gt;::operator + (const seqList&lt;elemType&gt; &amp;x)
{
    seqList&lt;elemType&gt; temp(currentLength + x.currentLength);
    for (int i = 0; i &lt; currentLength; ++i)
        temp.data[i] = data[i];
    for (int i = 0; i &lt; x.currentLength; ++i)
        temp.data[i + currentLength] = x.data[i];
    temp.currentLength = currentLength + x.currentLength;
    return temp;
}

template &lt;class elemType&gt;
seqList&lt;elemType&gt; seqList&lt;elemType&gt;::operator = (const seqList&lt;elemType&gt; &amp;x)
{
    while (maxSize &lt; x.currentLength) doubleSpace();
    for (int i = 0; i &lt; x.currentLength; ++i) data[i] = x.data[i];
    currentLength = x.currentLength;
    return *this;
}

int main()
{
    seqList&lt;int&gt; a, b, c;
    a.insert(0, 1);
    a.insert(1, 2);
    b.insert(0, 3);
    b.insert(1, 4);
    b.insert(2, 5);
    a.traverse();
    b.traverse();
    c = a + b;
    c.traverse();

    return 0;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://sqybi.com/blog/archives/246/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

