﻿<?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++博客-goal00001111</title><link>http://www.cppblog.com/goal00001111/</link><description>理想，你是不是太遥远</description><language>zh-cn</language><lastBuildDate>Sat, 22 Nov 2008 10:13:19 GMT</lastBuildDate><pubDate>Sat, 22 Nov 2008 10:13:19 GMT</pubDate><ttl>60</ttl><item><title>二进制在数学中的妙用</title><link>http://www.cppblog.com/goal00001111/archive/2008/06/15/53344.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Sun, 15 Jun 2008 08:42:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2008/06/15/53344.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/53344.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2008/06/15/53344.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/53344.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/53344.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 二进制在数学中的妙用goal00001111搜集整理&nbsp;十八世纪初，莱布尼茨发明了二进制数，当时的他肯定没有预料到二进制在信息时代会有着如此广泛的应用。二进制数以其工作可靠，运算简单，逻辑严密，容易实现等特点，成为了计算机的专用语言。在计算机科学和大量应用数学领域中，二进制记数法是必不可少的。在趣味数学方面，同样也有广泛的应用。让我们先来看一个经典的数学趣题：一工人工作...&nbsp;&nbsp;<a href='http://www.cppblog.com/goal00001111/archive/2008/06/15/53344.html'>阅读全文</a><img src ="http://www.cppblog.com/goal00001111/aggbug/53344.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2008-06-15 16:42 <a href="http://www.cppblog.com/goal00001111/archive/2008/06/15/53344.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>爱因斯坦的思考题</title><link>http://www.cppblog.com/goal00001111/archive/2006/12/06/16070.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Wed, 06 Dec 2006 14:31:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/12/06/16070.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/16070.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/12/06/16070.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/16070.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/16070.html</trackback:ping><description><![CDATA[
		<p>/*爱因斯坦的思考题<br />在网上看到了个有趣的逻辑推理题，爱因斯坦声称世界上只有2%的人能解出：</p>
		<p>有五个具有五种不同颜色的房间排成一排；</p>
		<p>每个房间里分别住着一个不同国籍的人；</p>
		<p>每个人都在喝一种特定品牌的饮料，抽一特定品牌的烟，养一特定的宠物；</p>
		<p>没有任意两个人在抽相同品牌的香烟，或喝相同品牌的饮料，或养相同的宠物。</p>
		<p>　　问题：谁在养鱼作为宠物？ </p>
		<p>　　爱因斯坦给出如下线索：</p>
		<p>
				<br />英国人住在红色的房子里；</p>
		<p>瑞典人养狗作为宠物；</p>
		<p>丹麦人喝茶；</p>
		<p>绿房子紧挨着白房子，在白房子的左边；</p>
		<p>绿房子的主人喝咖啡；</p>
		<p>抽Pall Mall牌香烟的人养鸟；</p>
		<p>黄色房子里的人抽Dunhill牌香烟；</p>
		<p>住在中间那个房子里的人喝牛奶；</p>
		<p>挪威人住在第一个房子里面；</p>
		<p>抽Blends牌香烟的人和养猫的人相邻；</p>
		<p>养马的人和抽Dunhill牌香烟的人相邻；</p>
		<p>抽BlueMaster牌香烟的人喝啤酒；</p>
		<p>德国人抽Prince牌香烟；</p>
		<p>挪威人和住在蓝房子的人相邻；</p>
		<p>抽Blends牌香烟的人和喝矿泉水的人相邻。</p>
		<p>           <br />           国家           房子           宠物           饮料           香烟<br />           挪威           黄色             猫         矿泉水        Dunhill<br />           丹麦           蓝色             马             茶         Blends<br />           英国           红色             鸟           牛奶       PallMall<br />           德国           绿色             鱼           咖啡         Prince<br />           瑞典           白色             狗           啤酒     BlueMaster<br />*/<br />/*<br />算法思路：<br />以房子的位置为主序，把国籍，颜色，宠物，饮料，香烟都作为该房子的一个成员，每一个成员都有可能<br />处在任何位置，为所有成员穷举每一个位置，再根据已知条件进行适当剪枝，找到唯一的解 <br />*/</p>
		<p>#include &lt;iostream&gt;<br />#include &lt;string&gt;<br />#include &lt;fstream&gt;</p>
		<p>using namespace std;</p>
		<p>int main(void)<br />{<br /> string Title[5] = {"国籍","颜色","宠物","饮料","香烟"};<br /> struct {<br />  string nation;<br />  string color;<br />  string pet;<br />  string drink;<br />  string cigarette;<br /> } House[5];//房子从左到右编号 </p>
		<p> House[0].nation = "挪威";//挪威人住在第一个房子里面<br /> House[1].color = "蓝色";//挪威人和住在蓝房子的人相邻,即蓝房子是第2个房子 <br /> House[2].drink = "牛奶";// 住在中间那个房子里的人喝牛奶</p>
		<p> for (int e=1; e&lt;5; e++) //表示英国人的房子序号<br /> for (int r=1; r&lt;5; r++)//表示瑞典人的房子序号<br /> for (int d=1; d&lt;5; d++)//表示丹麦人的房子序号<br /> for (int g=0; g&lt;5; g++)//表示绿房子的序号<br /> for (int p=0; p&lt;5; p++)//表示抽Pall Mall牌香烟的人的房子序号<br /> for (int y=0; y&lt;5; y++)//表示黄色房子的序号<br /> for (int b=0; b&lt;5; b++)//表示喝啤酒人的房子序号<br /> for (int h=0; h&lt;5; h++)//表示养马的人的房子序号<br /> for (int cat=0; cat&lt;5; cat++)//表示养猫的人的房子序号<br /> {<br />  int Germany = 10 - 0 - e - r - d; //表示德国人的房子序号,德国人抽Prince牌香烟；<br />  int Blends = 10 - p - y - b - Germany;//表示抽Blends牌香烟的人的房子序号<br />  int white = 10 - 1 - e - g - y; //表示白房子的序号<br />  int water = 10 - 2 - d - g - b; //表示喝矿泉水的人的房子序号<br />  int fish = 10 - r - p - h - cat;//表示养鱼的人的房子序号<br />  <br />  bool A1 = (e!=1); //英国人住在红色的房子里；根据房子和国家判断 <br />  bool A2 = (r!=e); //瑞典人养狗作为宠物；根据国家和宠物判断 <br />  bool A3 = (d!=e &amp;&amp; d!=r &amp;&amp; d!=2);//丹麦人喝茶；根据国家和饮料判断<br />  bool A4 = (g!=1 &amp;&amp; g!=2 &amp;&amp; g!=e &amp;&amp; g!=d);//绿房子的主人喝咖啡；根据颜色和饮料判断<br />  bool A5 = (p!=r); //抽Pall Mall牌香烟的人养鸟；根据香烟和宠物判断<br />  bool A6 = (y!=e &amp;&amp; y!=1 &amp;&amp; y!=g &amp;&amp; y!=p);//黄色房子里的人抽Dunhill牌香烟；根据颜色和香烟判断 <br />  bool A7 = (b!=2 &amp;&amp; b!=d &amp;&amp; b!=g &amp;&amp; b!=p &amp;&amp; b!=y);//抽BlueMaster牌香烟的人喝啤酒；根据香烟和饮料判断<br />  bool A8 = (h!=r &amp;&amp; h!=p &amp;&amp; (h==y+1 || h==y-1));//养马的人和抽Dunhill牌香烟的人相邻,根据香烟和宠物判断<br />  bool A9 = (white == g + 1); //绿房子紧挨着白房子，在白房子的左边；<br />  bool A0 = (cat==Blends-1 || cat==Blends+1);//Blends牌香烟的人和养猫的人相邻；<br />  bool A11 = (water==Blends-1 || water==Blends+1);//抽Blends牌香烟的人和喝矿泉水的人相邻<br />  <br />  if (A1 &amp;&amp; A2 &amp;&amp; A3 &amp;&amp; A4 &amp;&amp; A5 &amp;&amp; A6 &amp;&amp; A7 &amp;&amp; A8 &amp;&amp; A9 &amp;&amp; A0 &amp;&amp; A11)<br />  {//把满足条件的序号填入结构数组 <br />   House[e].nation = "英国";<br />   House[e].color = "红色";<br />   House[r].nation = "瑞典";<br />   House[r].pet = "狗";<br />   House[d].nation = "丹麦";<br />   House[d].drink = "茶";<br />   House[g].color = "绿色";<br />   House[g].drink = "咖啡";<br />   House[p].cigarette = "Pall Mall";<br />   House[p].pet = "鸟";<br />   House[y].color = "黄色";<br />   House[y].cigarette = "Dunhill";<br />   House[b].cigarette = "BlueMaster";<br />   House[b].drink = "啤酒";<br />   House[h].pet = "马";<br />   House[Germany].nation = "德国";<br />   House[Germany].cigarette = "Prince";<br />   House[Blends].cigarette = "Blends";<br />   House[white].color = "白色";<br />   House[water].drink = "矿泉水";<br />   House[cat].pet = "猫";<br />   House[fish].pet = "鱼";  <br />   <br />   goto end;<br />  }<br /> }<br />end:<br /> for (int i=0; i&lt;5; i++)<br />  cout &lt;&lt; Title[i] &lt;&lt; "\t";<br /> cout &lt;&lt; endl &lt;&lt; endl;<br /> <br /> for (int i=0; i&lt;5; i++)<br /> {<br />  cout &lt;&lt; House[i].nation &lt;&lt; "\t"; <br />  cout &lt;&lt; House[i].color &lt;&lt; "\t"; <br />  cout &lt;&lt; House[i].pet &lt;&lt; "\t"; <br />  cout &lt;&lt; House[i].drink &lt;&lt; "\t"; <br />  cout &lt;&lt; House[i].cigarette &lt;&lt; "\t"; <br />  cout &lt;&lt; endl;<br /> }<br /> //输出到文件 <br /> ofstream out("爱因斯坦的思考题.txt");<br /> for (int i=0; i&lt;5; i++)<br />  out &lt;&lt; Title[i] &lt;&lt; "\t";<br /> out &lt;&lt; endl &lt;&lt; endl;<br /> <br /> for (int i=0; i&lt;5; i++)<br /> {<br />  out &lt;&lt; House[i].nation &lt;&lt; "\t"; <br />  out &lt;&lt; House[i].color &lt;&lt; "\t"; <br />  out &lt;&lt; House[i].pet &lt;&lt; "\t"; <br />  out &lt;&lt; House[i].drink &lt;&lt; "\t"; <br />  out &lt;&lt; House[i].cigarette &lt;&lt; "\t"; <br />  out &lt;&lt; endl;<br /> }<br /> out.close();<br /> <br />   system("pause"); <br />   return 0;<br />}</p>
<img src ="http://www.cppblog.com/goal00001111/aggbug/16070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-12-06 22:31 <a href="http://www.cppblog.com/goal00001111/archive/2006/12/06/16070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>手机的汉语拼音输入法</title><link>http://www.cppblog.com/goal00001111/archive/2006/10/21/13966.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Sat, 21 Oct 2006 11:56:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/10/21/13966.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/13966.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/10/21/13966.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/13966.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/13966.html</trackback:ping><description><![CDATA[
		<p>系统功能：<br /> 手机的汉语拼音输入法很'聪明'，只要用数字键组合，就能够自动找到能组成拼音的字母组合.从2开始分别代表2:abc,3:def,4:ghi,5:jkl,6:mno,7:pqrs,8:tuv,9:wxyz"<br />键盘布局如图示 +-------+-------+-------+<br />         |1 OK   |2 abc  |3 def  |<br />     +-------+-------+-------+<br />     |4 ghi  |5 jkl  |6 mno  |<br />     +-------+-------+-------+<br />     |7 pqrs |8 tuv  |9 wxyz |<br />     +-------+-------+-------+<br />     |#&lt;prep&gt;|0&lt;back&gt;|*&lt;next&gt;|<br />     +-------+-------+-------+<br />拼音规则：输入时手机有3个状态：<br />1. 拼音状态： 只接受2至9，和结束键1。按下1则进入状态2，如果候选拼音组合唯一则自动进入状态3（此时拼音不必拼完）；如果无匹配的拼音组合，则一直忽略直到遇到#取消当前拼音。若用户输入非法字符，则自动屏蔽非法字符，只读取合法字符。若只输入结束键1，表示用户选择离开。<br />2. 选择拼音状态 ： 根据用户输入的数字组合，在屏幕上列出满足条件的拼音组合，每页最多有10个组合，按字母顺序标号由0到9。接受0-9任何一个键则选择对应组合进入状态3。忽略选择不存在组合的位置的数字。接受*则下翻一页。如果已经到达最后一页则忽略*号。接受#则取消当前拼音，并回到状态1。<br />3. 汉字选择状态： 进入本状态，如果所选的拼音组合包含对应汉字。则可以选择汉字。否则回到状态1，并且此时不输出任何汉字。每页最多有10个汉字，按输入的数据顺序排列。接受0-9任何一个键则选择对应汉字并输出输出后回到拼音状态。忽略选择不存在组合的位置的数字。接受#则取消当前拼音，并回到状态1。<br />注意：提供一个文本文件，里面包含所有的汉语拼音及对应汉字。文件包含若干行，每行2个字符串，串之间有1个空格分开。行尾没有空格。第一个串只包含英文字母，表示一个有效的拼音发音组合。后一个串包含若干个汉字。每个汉字是2个字节组成的。第一个字节最高位为1，第二个字节在0x40到0xfe之间，且不为0x7f。</p>
		<p>
				<br />总体设计：<br />一。读取文件信息<br />    1。从文件中把所有汉语拼音及对应汉字读入内存。因为文件中的每个拼音及其所有同音字处在同一行中，故可用一个指针数组*storage[]存储文件内容，数组的每个元素指向文件中的一行。</p>
		<p>二。读取用户数据<br />    2。读取用户输入的字符串，并对其进行适当的转换，判断字符串是否合法，并屏蔽非法字符得到一个只包含合法数字字符的新字符串。</p>
		<p>三。处理用户数据，并请用户选择正确的拼音和汉字<br />    3。采用递归的方法，求出数字字符串对应的所有拼音组合，把所有满足条件的拼音组合添加到线性链表letterList。<br />    4。把匹配的拼音组合按顺序显示到屏幕，请用户选取一个组合。<br />    5。根据选中的拼音组合，到*storage[]中找到相应的汉字，并按顺序输出到屏幕，请用户选取一个汉字。<br />    6。输出用户选取的汉字，同时输出到文件。</p>
		<p>四。重复步骤2-6，直到用户选择退出。</p>
		<p>
				<br />详细设计：<br />一。读取文件信息<br />1。从文件中把所有汉语拼音及对应汉字读入内存。因为文件中的每个拼音及其所有同音字处在同一行中，故可用一个指针数组*storage[]存储文件内容，数组的每个元素指向文件中的一行。因为工程中很多函数都要用到指针数组*storage[]，因此把它设置成全局变量。 <br />实现函数：void ReadFile(const char fileName[]);<br />/*<br />函数声明：void ReadFile(const char fileName[]);<br />函数功能：从指定的文件中把所有汉语拼音及对应汉字读入一个指针数组*storage[]（全局变量），<br />  数组的每个元素指向文件中的一行。<br />输入变量： const char fileName[]，指定的文件名，其中存储了汉字库 <br />输出变量：*storage[]，全局变量，每个元素指向一个包含某拼音组合及其对应汉字的字符串<br />返回值： 无  <br />*/</p>
		<p>二。读取用户数据<br />2。读取用户输入的字符串buf，并对其进行适当的转换，判断字符串是否合法，并屏蔽非法字符得到一个只含合法数字字符的新字符串value。 <br />转换规则：先找到结束键'1'，删除结束键之后的字符。若无结束键'1'，value[i] = '\0';并结束程序; <br />然后在buf中逆序查找#号，直到找到#号或遇到buf的第一个元素为止。若找到#号，则把#号之后的合法字符（数字）复制到value；<br />若未找到#号，则把buf的所有合法字符（数字）复制到value；若只输入结束键'1'，表示用户选择离开。<br />实现函数：void ReadValue(char value[]); <br />/*<br />函数声明：void ReadValue(char value[]);<br />函数功能：读取用户输入的字符串buf，并对其进行适当的转换。 <br />    转换规则：先找到结束键'1'，删除结束键之后的字符。<br />    若无结束键'1'，value[i] = '\0';；并结束程序; <br />    然后在buf中逆序查找#号，直到找到#号或遇到buf的第一个元素为止。<br />    若找到#号，则把#号之后的合法字符（数字）复制到value；<br />    若未找到#号，则把buf的所有合法字符（数字）复制到value；<br />    若只输入结束键'1'，表示用户选择离开。 <br />输入变量： char value[]，用来存储用户输入的合法字符的字符串 <br />输出变量： char value[]，用来存储用户输入的合法字符的字符串 <br />返回值： 无   <br />*/</p>
		<p>三。处理用户数据，并请用户选择正确的拼音和汉字<br />    此部分可分成三个步骤：先分析并得到正确的拼音组合，再根据拼音组合得到正确的汉字，最后输出该汉字。<br />3。 获取正确的拼音组合：（若value[0] = '\0';，则跳到第6步）<br />实现函数：void OutPutSpell(char letters[]，const char value[]); <br />/*<br />函数声明：void OutPutSpell(char letters[]，const char value[]); <br />函数功能：根据整理后得到的字符串value，找出对应的所有拼音组合，创建一个线性链表letterList，<br />把所有满足条件的拼音组合添加到letterList。把存储在letterList中的拼音组合按顺序显示到屏幕，<br />请用户选取一个组合，并把用户选择的拼音存储到letters。 然后销毁线性链表。 <br />输入变量：char letters[]，用来存储用户选择的拼音组合 <br />  const char value[]，用来存储用户输入的合法字符的字符串  <br />输出变量：char letters[]，用来存储用户选择的拼音组合<br />返回值： 无<br />*/</p>
		<p>该函数包括四个主要功能函数：<br />LNode GetLetterList(const char value[]); <br />void ChooseSpell(LNode head, char letters[]); <br />void RecursionAnalyse(const char *keyboard[], const char value[], int pos, char buf[], LNode Head); <br />void DistroyList(LNode List); </p>
		<p>/*<br />函数声明：LNode GetLetterList(const char value[]);  <br />函数功能：首先创建一个指针数组用来存储键盘上的数字字母组合，以该数字为下标，即<br />const char *keyboard[10] = {NULL, NULL,"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; <br />创建一个空的线性链表LNode letterList。<br />然后调用函数RecursionAnalyse,采用递归的方法，求出数字字符串对应的所有拼音组合，并把它们添加到链表letterList。<br />输入变量： const char value[]，用来存储用户输入的合法字符的字符串 <br />输出变量： 无 <br />返回值： LNode letterList，由拼音组合所组成的链表，它的空间在程序执行过程中动态分配 <br />*/<br />/* <br />函数声明：void ChooseSpell(LNode head, char letters[]); <br />函数功能：把存储在链表letterList中的拼音组合按顺序显示到屏幕，请用户选取一个组合，<br />  若用户输入#号存储letters[0] = '\0'；<br />  若用户输入*号，则继续输出后面的拼音组合，直到全部输出'； <br />  若用户输入了有效的选择，存储所选择的拼音组合到letters。<br />  若用户输入非法字符或在末页输入*号，报错并要求重新输入。 <br />输入变量：LNode Head，线性链表letterList 的头结点<br />  char letters[]，用来存储用户选择的拼音组合  <br />输出变量：char letters[]，用来存储用户选择的拼音组合<br />返回值： 无<br />*/<br />/*<br />函数声明：void RecursionAnalyse(const char *keyboard[], const char value[], int pos, char buf[], LNode Head);     <br />函数功能：递归调用本函数，求出所有的拼音组合，每求出一个拼音组合便将其构造成一个字符串，<br />  把该字符串作为结点数据插入链表letterList。 <br />输入变量： const char *keyboard[]，用来存储手机键盘信息的指针数组，根据输入的数字可以得到相应的字母 <br />  const char value[]，用来存储用户输入的合法字符的字符串<br />  int pos， 当前所处理的value的元素的下标 <br />  LNode Head，线性链表letterList 的头结点  <br />输出变量： LNode Head，线性链表letterList 的头结点  <br />返回值： 无<br />*/<br />/*<br />函数声明：void DistroyList(LNode List); <br />函数功能：销毁链表letterList。 <br />输入变量：LNode *List，指向线性链表letterList的指针 <br />输出变量：无<br />返回值： 无<br />*/</p>
		<p>4。获取正确的汉字：（若letters[0] = '\0'，则跳到第6步）<br />实现函数：void OutPutCharacters(const char letters[], char characters[]); <br />/*<br />函数声明：void OutPutCharacters(const char letters[], char character[]); <br />函数功能：到*storage[]中找到与letters匹配的元素，将相应的汉字按顺序输出到屏幕，<br />  请用户选取一个汉字，<br />  若用户输入#号或非法字符，存储NULL到character； <br />  若用户输入*号，则继续输出后面的汉字，直到全部输出，然后存储NULL到character； <br />  若用户输入了有效的选择，存储所选择的汉字到character。 <br />输入变量：const char letters[]，用来存储用户选择的拼音组合 <br />  char character[]，用来存储用户选择的汉字  <br />输出变量：char character[]，用来存储用户选择的汉字  <br />返回值： 无<br />*/<br />该函数包括三个主要功能函数：<br />int MatchCharacters(const char letters[], int pos);<br />void SaveCharacters(char charactersStorage[][3], char source[]);<br />void ChooseCharacters(char character[], const char charactersStorage[][3]); </p>
		<p>/*<br />函数声明：int MatchCharacters(const char letters[], int pos);<br />函数功能：判断storage[pos]中的拼音组合是否与字符串letters相同<br />输入变量： const char letters[]，用来存储用户选择的拼音字符串 <br />     int pos， 当前所处理的storage的指针元素的下标 <br />输出变量：无<br />返回值： 相同则返回1，否则返回0 <br />*/<br />/*<br />函数声明：void SaveCharacters(char charactersStorage[][3], char source[]);<br />函数功能：把source中的汉字存储到charactersStorage中 <br />输入变量：char charactersStorage[][3]， 用来存储与拼音letters对应的所有汉字<br />    char source[], storage的一个指针元素，它的拼音部分与letters相同 <br />输出变量： char charactersStorage[][3]， 用来存储与拼音letters对应的所有汉字<br />返回值：无<br />*/<br />/*<br />函数声明：void ChooseCharacters(char character[], const char charactersStorage[][3]); <br />函数功能：把存储在charactersStorage中的汉字按顺序显示到屏幕，请用户选取一个组合， <br />  若用户输入#号存储character[0] = '\0'；<br />  若用户输入*号，则继续输出后面的汉字，直到全部输出'； <br />  若用户输入了有效的选择，存储所选择的汉字到character。<br />  若用户输入非法字符或在末页输入*号，报错并要求重新输入。 <br />输入变量：char character[]，用来存储用户选择的汉字 <br />  const char charactersStorage[][3]，用来存储所有同音字  <br />输出变量：char character[]，用来存储用户选择的汉字 <br />返回值： 无<br />*/</p>
		<p>5。显示用户选取的汉字到屏幕，同时按照追加的方式输出到指定文件 。<br />实现函数：void PrintCharacter(const char character[], const char fileName[]); <br />/*<br />函数声明：void PrintCharacter(const char character[], const char fileName[]); <br />函数功能：显示用户选取的汉字到屏幕，同时按照追加的方式输出到指定文件 。<br />输入变量：const char character[]，用来存储用户选择的汉字<br />  const char fileName[]，指定的文件名，用来追加存储用户选择的汉字 <br />输出变量：char character[]，用来存储用户选择的汉字  <br />返回值： 无<br />*/</p>
		<p>6。重复步骤2-5，直到用户选择退出。</p>
		<p>注意：这里只列出了一些主要函数，其他功能函数由程序员自行设计。要求每个函数均要做好单体测试后再加入工程中。</p>
<img src ="http://www.cppblog.com/goal00001111/aggbug/13966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-10-21 19:56 <a href="http://www.cppblog.com/goal00001111/archive/2006/10/21/13966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我所理解的插入排序算法</title><link>http://www.cppblog.com/goal00001111/archive/2006/06/20/8771.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Tue, 20 Jun 2006 15:22:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/06/20/8771.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/8771.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/06/20/8771.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/8771.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/8771.html</trackback:ping><description><![CDATA[插入排序是一种简单的排序方法，因为的实现比较简单，所以在数据量较少时应用很广泛。插入排序根据其插入的不同方式，可以分为直接插入排序，折半插入排序，2-路插入排序，表插入排序和希尔排序。在这里我将一一写出各种插入排序的算法代码。<br />直接插入排序<br />template &lt;class T&gt;<br />void InsertSort(T a[], int len)<br />{<br />      int i, j;<br />      T temp;<br />      for (i=1; i&lt;len; i++)<br />      {<br />            temp = a[i];<br />            for (j=i-1; j&gt;=0 &amp;&amp; a[j]&gt;temp; j--)//元素后移<br />                  a[j+1] = a[j];<br />            a[j+1] = temp;  //插入<br />      }<br />}<br />      有些算法把a[0]设置为临时数据存放处（即原数组中a[0]未存储元素），这样就可以少进行一些判断，在数据量较大时可以节省一些时间，算法如下：<br />template &lt;class T&gt;<br />void InsertSort(T a[], int len)<br />{<br />      int i, j;<br />      for (i=1; i&lt;len; i++)<br />      {<br />            a[0] = a[i];<br />            for (j=i-1; a[j]&gt;temp; j--)<br />                  a[j+1] = a[j];<br />            a[j+1] = temp;<br />      }<br />}<br />折半插入排序法<br />      由于插入排序的基本操作是在一个有序表中进行查找和插入，则这个查找操作可以利用折半查找来实现。但是折半插入排序仅减少了元素间的比较次数，而元素的移动次数不变，因此折半插入排序法的时间复杂度仍为O(n^2)。算法如下：<br />template &lt;class T&gt;<br />void HalfInsertSort(T a[], int len)<br />{<br />      int i, j;<br />      int low, high, mid;<br />      T temp;<br />      for (i=1; i&lt;len; i++)<br />      {<br />            temp = a[i];<br />            low = 0;<br />            high = i - 1;<br />            while (low &lt;= high) //在a[low。。。high]中折半查找有序插入的位置<br />            {<br />                  mid = (low + high) / 2;<br />                  if (a[mid] &gt; temp)<br />                        high = mid - 1;<br />                  else<br />                        low = mid + 1;<br />            } //while<br />            <br />            for (j=i-1; j&gt;high; j--)//元素后移<br />                  a[j+1] = a[j];<br />            a[high+1] = temp; //插入<br />      }//for<br />}<br /><br />希尔排序法<br />      希尔排序法又称缩小增量排序法，它也是插入排序类的方法，但在时间效率上较前面几种插入排序算法有较大的改进。<br />      希尔排序法通过比较相距一定间隔的元素来工作，各趟比较所用的距离随着算法的进行而减小，直到比较相邻元素的最后一趟排序为止。算法如下：<br />template &lt;class T&gt;<br />void ShellSort(T a[], int len)<br />{<br />      for (int increment=len/2; increment&gt;0; increment/=2)<br />      {<br />            for (int i=increment; i&lt;len; i++)<br />            {<br />                  T temp = a[i];<br />                  int j = i;<br />                  for (; j&gt;=increment; j-=increment)//元素后移<br />                  {<br />                        if (temp &lt; a[j-increment])<br />                              a[j] = a[j-increment];<br />                        else<br />                              break;<br />                  }<br />                  a[j] = temp; //插入<br />            }//for<br />      }//for<br />}<br />注：缺2-路插入排序和表插入排序，有意者请补上！谢谢！<br /><img src ="http://www.cppblog.com/goal00001111/aggbug/8771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-06-20 23:22 <a href="http://www.cppblog.com/goal00001111/archive/2006/06/20/8771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我所理解的归并排序算法</title><link>http://www.cppblog.com/goal00001111/archive/2006/06/15/8612.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Thu, 15 Jun 2006 15:24:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/06/15/8612.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/8612.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/06/15/8612.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/8612.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/8612.html</trackback:ping><description><![CDATA[归并排序算法以O（nlogn）最坏情形运行时间运行，而所使用的比较次数几乎是最优的。它可以用递归的形式实现，形式简洁易懂。但是需要注意的是当用递归形式时，如果数据较多，则开销很大，实用性很差，所以我们一般采用非递归的形式。我这里两种形式都给出。<br />      不管是递归还是非递归，归并排序算法中基本的操作是合并两个已经排序的数组。<br />递归形式：<br />template &lt;class T&gt;<br />void MSort(T a[], int left, int right)<br />{<br />      if (left &lt; right)<br />      {<br />            int center = (left + right) / 2;<br />            MSort(a, left, center);<br />            MSort(a, center+1, right);<br />            Merge(a, left, center, right, right-left+1);<br />      }<br />}<br /><br />template &lt;class T&gt;<br />void MergeSort(T a[], int n)<br />{<br />      MSort(a, 0, n-1);<br />}<br />///////////////////////////////////////////////////////////////////////<br />非递归形式：<br />算法介绍：先介绍三个变量beforeLen，afterLen和i的作用：<br />int beforeLen; //合并前序列的长度<br />int afterLen;//合并后序列的长度，合并后序列的长度是合并前的两倍<br />int i = 0;//开始合并时第一个序列的起始位置下标，每次都是从0开始<br />i，i+beforeLen-1，i+afterLen-1定义被合并的两个序列的边界。<br />算法的工作过程如下：<br />开始时，beforeLen被置为1，i被置为0。外部for循环的循环体每执行一次，都使beforeLen和afterLen加倍。内部的while循环执行序列的合并工作，他的循环体每执行一次，i都向前移动afterLen个位置。当n不是afterLen的倍数时，如果被合并序列的起始位置i，加上合并后序列的长度afterLen，超过输入数组的边界n，就结束内部循环；此时如果被合并序列的起始位置i，加上合并前序列的长度beforeLen，小于输入数组的边界n，还需要执行一次合并工作，把最后长度不足afterLen，但超过beforeLen的序列合并起来。这个工作由算法的语句Merge(a, i, i+beforeLen-1, n-1, n);完成。<br /><br />template &lt;class T&gt;<br />void MergeSort(T a[], int n)<br />{<br />      int beforeLen; //合并前序列的长度<br />      int afterLen = 1;//合并后序列的长度<br />      <br />      for (beforeLen=1; afterLen&lt;n; beforeLen=afterLen)<br />      {<br />            int i = 0;//开始合并时第一个序列的起始位置下标，每次都是从0开始<br />            afterLen = 2 * beforeLen; //合并后序列的长度是合并前的两倍<br />            <br />            while (i+afterLen &lt; n)<br />            {<br />                  Merge(a, i, i+beforeLen-1, i+afterLen-1, afterLen);<br />                  i += afterLen;<br />            }<br />            <br />            if (i+beforeLen &lt; n)<br />                  Merge(a, i, i+beforeLen-1, n-1, n);<br />      }<br />}<br />///////////////////////////////////////////////////////////<br />      上面两种算法都要用到下面的合并函数。<br />/*函数介绍：合并两个有序的子数组<br />输入：数组a[]，下标left，center，right，元素个数n，a[left]~a[center]及a[center+1]~a[right]已经按非递减顺序排序。<br />输出：按非递减顺序排序的子数组a[left]~a[right]。<br />*/<br />template &lt;class T&gt;<br />void Merge(T a[], int left, int center, int right, int n)<br />{<br />      T *t = new T[n];//存放被排序的元素<br />      int i = left;<br />      int j = center + 1;<br />      int k = 0;<br /><br />      while (i&lt;=center &amp;&amp; j&lt;=right)<br />      {<br />            if (a[i] &lt;= a[j])<br />                  t[k++] = a[i++];<br />            else<br />                  t[k++] = a[j++];<br />      }<br /><br />      if (i == center+1)<br />      {<br />            while (j &lt;= right)<br />                  t[k++] = a[j++];<br />      }<br />      else<br />      {<br />            while (i &lt;= center)<br />                  t[k++] = a[i++];<br />      }<br />      //把t[]的元素复制回a[]<br />      for (i=left,k=0; i&lt;=right; i++,k++)<br />            a[i] = t[k];<br /><br />      delete []t;<br />} <img src ="http://www.cppblog.com/goal00001111/aggbug/8612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-06-15 23:24 <a href="http://www.cppblog.com/goal00001111/archive/2006/06/15/8612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我所理解的快速排序算法</title><link>http://www.cppblog.com/goal00001111/archive/2006/06/14/8534.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Wed, 14 Jun 2006 02:19:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/06/14/8534.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/8534.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/06/14/8534.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/8534.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/8534.html</trackback:ping><description><![CDATA[
		<div id="td_content">
				<p>我所理解的快速排序算法<br />      快速排序是在实践中最快的已知排序算法，它的平均运行时间是O（NlogN）。该算法之所以特别快，主要是由于非常精练和高度优化的内部循环。在队列中寻找合适的枢点元素，并按枢点元素划分序列，是快速排序算法的关键。<br />      为简单起见，我这里数组的第一个元素作为枢点元素，重新排列数组，使得枢点元素之前的元素都小于枢点元素，而枢点元素之后的元素都大于或等于枢点元素。<br />      在这里我提供算法的两种实现：<br />第一种：<br />template &lt;class T&gt;<br />int Parttion(T a[], int low, int high)<br />{<br />      T x = a[low];</p>
				<p>      while (low &lt; high)<br />      {<br />            while (low &lt; high &amp;&amp; a[high] &gt;=  x)<br />                  high--;<br />            a[low] = a[high];</p>
				<p>            while (low &lt; high &amp;&amp; a[low] &lt;  x)<br />                  low++;<br />            a[high] = a[low];<br />      }</p>
				<p>      a[low] = x;<br />      return low;<br />}<br />第二种：<br />template &lt;class T&gt;<br />int Parttion(T a[], int low, int high)<br />{<br />      T x = a[low];<br />      int i = low;<br />      <br />      for (int j=low+1; j&lt;=high; j++)<br />      {<br />            if (a[j] &lt;= x)<br />            {<br />                  i++;<br />                  if (i != j)<br />                        Swap(a[i], a[j]);<br />            }<br />      }<br />      <br />      Swap(a[low], a[i]);<br />      return i;<br />}</p>
				<p>template &lt;class T&gt;<br />void Swap(T &amp; a, T &amp; b)<br />{<br />      T t = a;<br />      a = b;<br />      b = t;<br />}</p>
				<p>快速排序的驱动程序：<br />template &lt;class T&gt;<br />void QuickSort(T a[], int len)<br />{<br />      Qsort(a, 0, len-1);<br />}</p>
				<p>template &lt;class T&gt;<br />void Qsort(T a[], int low, int high)<br />{<br />      if (low &lt; high)<br />      {<br />            int k = Parttion(a, low, high);<br />            Qsort(a, low, k-1);<br />            Qsort(a, k+1, high);<br />      }<br />}<br /></p>
		</div>
<img src ="http://www.cppblog.com/goal00001111/aggbug/8534.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-06-14 10:19 <a href="http://www.cppblog.com/goal00001111/archive/2006/06/14/8534.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我所理解的堆排序算法</title><link>http://www.cppblog.com/goal00001111/archive/2006/06/14/8533.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Wed, 14 Jun 2006 02:18:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/06/14/8533.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/8533.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/06/14/8533.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/8533.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/8533.html</trackback:ping><description><![CDATA[
		<div id="td_content">
				<p>我所理解的堆排序算法<br />      堆排序在最坏的情况下，其时间复杂度也能达到O（nlogn）。相对于快速排序来说，这是它最大的优点，此外，堆排序仅需要一个记录大小供交换用的辅助存储空间。<br />      堆排序的数据结构是二叉堆，二叉堆的特点有两个，一个是它是一棵完全二叉树，另一个是它的根结点小于孩子结点，所以我们很容易找到它的最小结点----根结点；当然如果你想找到最大结点的话，那就要扫描所有的叶子结点，这是很费时间的，如果你想找的是最大结点的话，你最好把它弄成一个大顶堆，即一棵根结点大于孩子结点的完全二叉树。<br />      二叉堆通常用数组来实现，它舍弃下标0，从下标1开始置数，则很容易满足，对于数组中任意位置i上的元素，其左儿子的位置在2i上，右儿子的位置在2i+1上，双亲的位置则在i/2上。<br />      堆排序的算法之一是把数组构建成二叉堆----这只要增添一个长度为n+1的辅助空间，然后把原数组的元素依次插入到二叉堆即可。然后删除二叉堆的根，把它作为排序后的数组的第一个元素,然后使二叉堆的长度减1，并通过上移使得新得到的序列仍为二叉堆，再提取新二叉堆的第一个元素到新数组。依此类推，直到提取最后一个元素，新得到的数组就是排序后的数组。<br />算法如下：<br />template &lt;class T&gt;<br />void Insert(T a[], int len, T x)//把x插入到原长度为len的二叉堆，注意保证新二叉堆不越界<br />{<br />      int i;<br />      for (i=len; i/2&gt;0 &amp;&amp; a[i/2]&gt;x; i/=2)<br />            a[i] = a[i/2];<br />      a[i] = x;<br />}</p>
				<p>template &lt;class T&gt;<br />T DeleteMin(T a[], int len)//删除二叉堆的根，并通过上移使得新得到的序列仍为二叉堆<br />{<br />      if (len == 0)<br />            exit(1);<br />      T min = a[1];//二叉堆的根<br />      T last = a[len--];//二叉堆的最后一个元素</p>
				<p>      int c;<br />      int i;<br />      for (i=1; i*2&lt;=len; i=c)//把二叉堆的某些元素往前移，使得新得到的序列仍为二叉堆<br />      {<br />            c = i * 2;//i的左儿子<br />            if (c != len &amp;&amp; a[c+1] &lt; a[c])//若i有右儿子，且右儿子小于左儿子，c指向右儿子<br />                  c++;</p>
				<p>            if (last &gt; a[c])//若i的小儿子小于二叉堆的最后一个元素，把其移到i的位置<br />                  a[i] = a[c];<br />            else<br />                  break;<br />      }<br />      a[i] = last; //把二叉堆的最后一个元素放到适当的空位，此时得到的序列仍为二叉堆</p>
				<p>      return min;<br />}</p>
				<p>template &lt;class T&gt;<br />void HeapSort(T a[], int len)<br />{<br />      T *ca = new T[len+1]; //复制原数组到二叉堆<br />      ca[0] = 0;<br />      for (int i=0; i&lt;len; i++) //把元素依次插入到二叉堆<br />            Insert(ca, i+1, a[i]);</p>
				<p>      for (int i=0; i&lt;len; i++)//依次提取二叉堆的根作为排序后的数组的元素<br />      {<br />            a[i] = DeleteMin(ca, len-i);<br />      }</p>
				<p>      a[len-1] = ca[1]; //注意不能忘了最后一个元素</p>
				<p>      delete []ca;<br />}<br />      在《数据结构习题与解析》（李春葆 编著 清华大学出版社）中看到一个类似的算法，它是把原数组构建成一个大顶堆，然后把大顶堆的第一个元素与最后一个元素交换；再把前n-1个元素重新构造成一个大顶堆，把新大顶堆的第一个元素与最后一个元素交换；依此类推，直到新大顶堆只有一个元素，这样就得到了一个有序的二叉堆。<br />算法如下：<br />template &lt;class T&gt;<br />void HeapSort(T a[], int len)<br />{<br />      T *ca = new T[len+1];<br />      ca[0] = 0;<br />      for (int i=0; i&lt;len; i++)<br />            ca[i+1] = a[i];</p>
				<p>      for (int i=len/2; i&gt;0; i--) //建立初始堆<br />            HeapAdjust(ca, len, i);</p>
				<p>      for (int i=len; i&gt;1; i--)//进行len-1次循环，完成堆排序<br />      {<br />            Swap(ca[1], ca[i]); //新大顶堆的第一个元素与最后一个元素交换<br />            HeapAdjust(ca, i-1, 1);//筛a[1]元素，得到i-1个元素的堆<br />      }</p>
				<p>      for (int i=0; i&lt;len; i++)<br />            a[i] = ca[i+1];</p>
				<p>      delete []ca;<br />}</p>
				<p>template &lt;class T&gt;<br />void HeapAdjust(T a[], int len, int left) //将i与其小儿子交换位置<br />{<br />      if (len == 0)<br />            exit(1);</p>
				<p>      T x = a[left];<br />      int i = left;<br />      int c = 2 * i;<br />      while (c &lt;= len)<br />      {<br />            if (c &lt; len &amp;&amp; a[c+1] &gt; a[c])//若i有右儿子，且右儿子大于左儿子，c指向右儿子<br />                  c++;<br />            if (last &lt; a[c])//若i的大儿子大于二叉堆的最后一个元素，把其移到i的位置<br />            {<br />                  a[i] = a[c];<br />                  i = c;<br />                  c = 2 * i;<br />            }<br />            else<br />                  break;<br />      }<br />      a[i] = x; //把原二叉堆的第一个元素放到适当的空位<br />}</p>
				<p>template &lt;class T&gt;<br />void Swap(T &amp; a, T &amp; b)<br />{<br />      T t = a;<br />      a = b;<br />      b = t;<br />}</p>
				<p>      还有一种方法是每次都要重新调整大顶堆，使得父亲比儿子大，这样调整的函数较简单，<br />但因为每次都要遍历一半的元素，时间复杂度较大。<br />算法如下：<br />template &lt;class T&gt;<br />void HeapSort(T a[], int len)<br />{<br />      T *ca = new T[len+1];<br />      ca[0] = 0;<br />      for (int i=0; i&lt;len; i++)<br />            ca[i+1] = a[i];</p>
				<p>      for (int i=len/2; i&gt;0; i--) //把原数组构建成一个大顶堆<br />            HeapAdjust(ca, len, i);<br />      Swap(ca[1], ca[len]); //把大顶堆的第一个元素与最后一个元素交换<br />      <br />      for (int i=len-1; i&gt;0; i--)<br />      {<br />            for (int j=i/2; j&gt;0; j--)//遍历长度为i的堆，得到新的大顶堆<br />                  HeapAdjust(ca, i, j);<br />            Swap(ca[1], ca[i]);<br />      }<br />      <br />      for (int i=0; i&lt;len; i++)<br />            a[i] = ca[i+1];</p>
				<p>      delete []ca;<br />}</p>
				<p>template &lt;class T&gt;<br />void HeapAdjust(T a[], int len, int i) //将i与其小儿子交换位置<br />{<br />      int c = 2 * i;</p>
				<p>      if (c &lt; len)<br />      {<br />            T &amp; max = (a[c] &gt; a[c+1])? a[c] : a[c+1];<br />            if (a[i] &lt; max)<br />                  Swap(a[i], max);<br />      }<br />      else<br />      {<br />            if (a[i] &lt; a[c])<br />                  Swap(a[i], a[c]);<br />      }<br />}</p>
				<p>template &lt;class T&gt;<br />void Swap(T &amp; a, T &amp; b)<br />{<br />      T t = a;<br />      a = b;<br />      b = t;<br />}</p>
				<p>      模仿构造大顶堆的方法，我们可以调用HeapAdjust()构造一个二叉堆，并提取二叉堆的根到新数组，<br />然后把原二叉堆的最后一个元素放到根的位置，再调用HeapAdjust()构造一个新二叉堆，依此类推。<br />算法如下：<br />template &lt;class T&gt;<br />void HeapSort(T a[], int len)<br />{<br />      T *ca = new T[len+1];<br />      ca[0] = 0;<br />      for (int i=0; i&lt;len; i++)<br />            ca[i+1] = a[i];</p>
				<p>      for (int i=len/2; i&gt;0; i--) //把原数组构建成一个大顶堆<br />            HeapAdjust(ca, len, i);<br />      a[0] = ca[1];<br />      ca[1] = ca[len]; //把二叉堆的最后一个元素放到根的位置</p>
				<p>      for (int i=len-1; i&gt;0; i--)<br />      {<br />            for (int j=i/2; j&gt;0; j--)<br />                  HeapAdjust(ca, i, j);<br />            a[len-i] = ca[1];<br />            ca[1] = ca[i]; //把二叉堆的最后一个元素放到根的位置<br />      }</p>
				<p>      delete []ca;<br />}</p>
				<p>template &lt;class T&gt;<br />void HeapAdjust(T a[], int len, int i)<br />{<br />      int c = 2 * i;</p>
				<p>      if (c &lt; len)<br />      {<br />            T &amp; min = (a[c] &lt; a[c+1])? a[c] : a[c+1];<br />            if (a[i] &gt; min)<br />                  Swap(a[i], min);<br />      }<br />      else<br />      {<br />            if (a[i] &gt; a[c])<br />                  Swap(a[i], a[c]);<br />      }<br />}</p>
				<p>template &lt;class T&gt;<br />void Swap(T &amp; a, T &amp; b)<br />{<br />      T t = a;<br />      a = b;<br />      b = t;<br />}<br />      后面两种方法采用的是递归，容易理解，但时间复杂度较高，因为比前两种要慢上很多，所以不可能是O（nlogn），估计是O（n^2），但具体我也不会算，请高手指教。</p>
		</div>
<img src ="http://www.cppblog.com/goal00001111/aggbug/8533.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-06-14 10:18 <a href="http://www.cppblog.com/goal00001111/archive/2006/06/14/8533.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>汉诺塔非递归算法</title><link>http://www.cppblog.com/goal00001111/archive/2006/06/07/8252.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Wed, 07 Jun 2006 10:00:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/06/07/8252.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/8252.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/06/07/8252.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/8252.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/8252.html</trackback:ping><description><![CDATA[
		<p>/*<br />问题描述：有三个柱子A, B, C. A柱子上叠放有n个盘子，每个盘子都比它下面的盘子要小一点，<br />可以从上到下用1, 2, ..., n编号。要求借助柱子B，把柱子A上的所有的盘子移动到柱子C上。<br />移动条件为：1、一次只能移一个盘子；<br />2、移动过程中大盘子不能放在小盘子上，只能小盘子放在大盘子上。<br />*/<br />/*<br />递归的算法相信大多数人都知道，非递归算法也有出现过。<br />如：摘自<a href="http://www.programfan.com/club/old_showbbs.asp?id=96548">http://www.programfan.com/club/old_showbbs.asp?id=96548</a><br />作者：qq590240<br />#include &lt;iostream&gt;<br />#include &lt;stdlib.h&gt;</p>
		<p>#ifdef _WIN32<br />using namespace std;<br />#endif</p>
		<p>static void hanoi(int height)<br />{<br />    int fromPole, toPole, Disk;<br />    int *BitStr = new int[height],<br />        *Hold   = new int[height];<br />    char Place[]  = {'A', 'B', 'C'};<br />    int i, j, temp;</p>
		<p>    for (i=0; i &lt; height; i++)<br />    {<br />        BitStr[i] = 0;<br />        Hold[i] = 1;<br />    }<br />    temp = 3 - (height % 2);<br />    int TotalMoves = (1 &lt;&lt; height) - 1;<br />    for (i=1; i &lt;= TotalMoves; i++)<br />    {<br />        for (j=0 ; BitStr[j] != 0; j++)<br />        {<br />            BitStr[j] = 0;<br />        }<br />        BitStr[j] = 1;<br />        Disk = j+1;<br />        if (Disk == 1)<br />        {<br />            fromPole = Hold[0];<br />            toPole = 6 - fromPole - temp;<br />            temp = fromPole;<br />        }<br />        else<br />        {<br />            fromPole = Hold[Disk-1];<br />            toPole = 6 - Hold[0] - Hold[Disk-1];<br />        }<br />        cout &lt;&lt; "Move disk " &lt;&lt; Disk &lt;&lt; " from " &lt;&lt; Place[fromPole-1]<br />             &lt;&lt; " to " &lt;&lt; Place[toPole-1] &lt;&lt; endl;<br />        Hold[Disk-1] = toPole;<br />    }<br />}</p>
		<p> </p>
		<p>
				<br />int main(int argc, char *argv[])<br />{<br />    cout &lt;&lt; "Towers of Hanoi: " &lt;&lt; endl<br />         &lt;&lt; "moving a tower of n disks from pole A to pole B by using pole C" &lt;&lt; endl;<br />    cout &lt;&lt; "Input the height of the original tower: ";<br />    int height;<br />    cin &gt;&gt; height;<br />    hanoi(height);</p>
		<p>    system("PAUSE");<br />    return EXIT_SUCCESS;<br />}<br /> ////////////////////////////////////////////////////////////<br /> 我在这里根据《数学营养菜》（谈祥柏 著）提供的一种方法，编了一个程序来实现。<br />*/<br />/*<br />算法介绍：<br />首先容易证明，当盘子的个数为n时，移动的次数应等于2^n - 1。<br />一位美国学者发现一种出人意料的方法，只要轮流进行两步操作就可以了。<br />首先把三根柱子按顺序排成品字型，把所有的圆盘按从大到小的顺序放在柱子A上。<br />根据圆盘的数量确定柱子的排放顺序：若n为偶数，按顺时针方向依次摆放 A B C；<br />若n为奇数，按顺时针方向依次摆放 A C B。<br />（1）按顺时针方向把圆盘1从现在的柱子移动到下一根柱子，即当n为偶数时，若圆盘1在柱子A，则把它移动到B；<br />若圆盘1在柱子B，则把它移动到C；若圆盘1在柱子C，则把它移动到A。<br />（2）接着，把另外两根柱子上可以移动的圆盘移动到新的柱子上。<br />即把非空柱子上的圆盘移动到空柱子上，当两根柱子都非空时，移动较小的圆盘<br />这一步没有明确规定移动哪个圆盘，你可能以为会有多种可能性，其实不然，可实施的行动是唯一的。<br />（3）反复进行（1）（2）操作，最后就能按规定完成汉诺塔的移动。<br />*/<br />#include &lt;iostream&gt;<br />using namespace std;</p>
		<p>const int MAX = 64; //圆盘的个数最多为64</p>
		<p>struct st{  //用来表示每根柱子的信息<br />      int s[MAX]; //柱子上的圆盘存储情况<br />      int top; //栈顶，用来最上面的圆盘<br />      char name; //柱子的名字，可以是A，B，C中的一个<br />      <br />      int Top()//取栈顶元素<br />      {<br />            return s[top];<br />      }<br />      int Pop()//出栈<br />      {<br />            return s[top--];<br />      }<br />      void Push(int x)//入栈<br />      {<br />            s[++top] = x;<br />      }<br />} ;</p>
		<p>long Pow(int x, int y); //计算x^y<br />void Creat(st ta[], int n); //给结构数组设置初值<br />void Hannuota(st ta[], long max); //移动汉诺塔的主要函数</p>
		<p>int main(void)<br />{<br />      int n;<br />      cin &gt;&gt; n; //输入圆盘的个数<br />      <br />      st ta[3]; //三根柱子的信息用结构数组存储<br />      Creat(ta, n); //给结构数组设置初值</p>
		<p>      long max = Pow(2, n) - 1;//动的次数应等于2^n - 1<br />      Hannuota(ta, max);//移动汉诺塔的主要函数</p>
		<p>      system("pause");<br />      return 0;<br />}</p>
		<p>void Creat(st ta[], int n)<br />{<br />      ta[0].name = 'A';<br />      ta[0].top = n-1;<br />      for (int i=0; i&lt;n; i++) //把所有的圆盘按从大到小的顺序放在柱子A上<br />            ta[0].s[i] = n - i;<br />            <br />      ta[1].top = ta[2].top = 0;//柱子B，C上开始没有没有圆盘<br />      for (int i=0; i&lt;n; i++)<br />            ta[1].s[i] = ta[2].s[i] = 0;<br />            <br />      if (n%2 == 0) //若n为偶数，按顺时针方向依次摆放 A B C<br />      {<br />            ta[1].name = 'B';<br />            ta[2].name = 'C';<br />      }<br />      else  //若n为奇数，按顺时针方向依次摆放 A C B<br />      {<br />            ta[1].name = 'C';<br />            ta[2].name = 'B';<br />      }<br />}</p>
		<p>long Pow(int x, int y)<br />{<br />      long sum = 1;<br />      for (int i=0; i&lt;y; i++)<br />            sum *= x;</p>
		<p>      return sum;<br />}</p>
		<p>void Hannuota(st ta[], long max)<br />{<br />      int k = 0; //累计移动的次数<br />      int i = 0;<br />      int ch;<br />      while (k &lt; max)<br />      {<br />            //按顺时针方向把圆盘1从现在的柱子移动到下一根柱子<br />            ch = ta[i%3].Pop();<br />            ta[(i+1)%3].Push(ch);<br />            cout &lt;&lt; ++k &lt;&lt; ": " &lt;&lt; "Move disk " &lt;&lt; ch &lt;&lt; " from " &lt;&lt; ta[i%3].name &lt;&lt; " to " &lt;&lt; ta[(i+1)%3].name &lt;&lt; endl;<br />            i++;<br />            //把另外两根柱子上可以移动的圆盘移动到新的柱子上<br />            if (k &lt; max)<br />            {     //把非空柱子上的圆盘移动到空柱子上，当两根柱子都为空时，移动较小的圆盘<br />                  if (ta[(i+1)%3].Top() == 0 || ta[(i-1)%3].Top() &gt; 0 &amp;&amp; ta[(i+1)%3].Top() &gt; ta[(i-1)%3].Top())<br />                  {<br />                        ch =  ta[(i-1)%3].Pop();<br />                        ta[(i+1)%3].Push(ch);<br />                        cout &lt;&lt; ++k &lt;&lt; ": " &lt;&lt; "Move disk " &lt;&lt; ch &lt;&lt; " from " &lt;&lt; ta[(i-1)%3].name &lt;&lt; " to " &lt;&lt; ta[(i+1)%3].name &lt;&lt; endl;<br />                  }<br />                  else<br />                  {<br />                        ch =  ta[(i+1)%3].Pop();<br />                        ta[(i-1)%3].Push(ch);<br />                        cout &lt;&lt; ++k &lt;&lt; ": " &lt;&lt; "Move disk " &lt;&lt; ch &lt;&lt; " from " &lt;&lt; ta[(i+1)%3].name &lt;&lt; " to " &lt;&lt; ta[(i-1)%3].name &lt;&lt; endl;<br />                  }<br />            }<br />      }<br />}</p>
		<p> </p>
<img src ="http://www.cppblog.com/goal00001111/aggbug/8252.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-06-07 18:00 <a href="http://www.cppblog.com/goal00001111/archive/2006/06/07/8252.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>平衡有序树AVL树之两种思路</title><link>http://www.cppblog.com/goal00001111/archive/2006/06/04/8151.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Sun, 04 Jun 2006 08:53:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/06/04/8151.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/8151.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/06/04/8151.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/8151.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/8151.html</trackback:ping><description><![CDATA[也许二杈树是很好用的，在插入和查找的时候时间复杂度一般为O（logN），但如果左右子树失去平衡，也可能达到O（N）。为了防止这种现象发生，一种解决办法是是左右子树尽量保持平衡，即建立一种平衡有序树AVL树。     <br />    一棵AVL树是其每个结点的左子树和右子树的高度最多相差1的二杈有序树。空树的高度定义为-1。<br />    AVL树的结点声明；<br />typedef struct avlnode<br />{<br />    int height;//比普通二杈有序树多了一个高度信息 <br />    ElemType data;<br />    struct bnode *lchild, *rchild;<br />} *AvlTree, *Position;    <br />//----------AVL树基本操作------------ ------------------------------<br />AvlTree MakeEmpty(AvlTree T);<br />Position Find(ElemType x, AvlTree T);<br />Position FindMin(AvlTree T);<br />Position FindMax(AvlTree T);<br />static int Height(Position P);<br />AvlTree Insert(ElemType x, AvlTree T);<br />AvlTree Delete(ElemType x, AvlTree T);<br />ElemType Retrieve(Position P);<br /><br />//----------AVL树基本操作的算法实现--------------------<br />递归算法： <br />Position FindMin(AvlTree T)<br />{<br />    if(T==NULL)<br />        return NULL;<br />    else if(T-&gt;lchild == NULL)<br />        return T;<br />    else<br />        return FindMin(T-&gt;lchild);<br />}<br /><br />Position FindMax(AvlTree T)<br />{<br />    if(T==NULL)<br />        return NULL;<br />    else if(T-&gt;rchild == NULL)<br />        return T;<br />    else<br />        return FindMax(T-&gt;rchild);<br />}<br />非递归算法：<br />Position FindMin(AvlTree T)<br />{<br />    if(T!=NULL)<br />    {<br />        while(T-&gt;lchild != NULL)<br />            T = T-&gt;lchild;<br />    }<br />    <br />    return T;<br />}<br /><br />Position FindMax(AvlTree T)<br />{<br />    if(T!=NULL)<br />    {<br />        while(T-&gt;rchild != NULL)<br />            T = T-&gt;rchild;<br />    }<br />    <br />    return T;<br />}<br />//返回P点的高度 <br />static int Height(Position P)<br />{<br />    if(P==NULL)<br />        return -1;<br />    else<br />        return P-&gt;height;<br />}<br />//在对一棵AVL树进行插入操作后，可能会破坏它的平衡条件，因此必须对新的AVL树进行调整，<br />这里用到了“单旋转”或“双旋转”的算法，分别适用于：<br />单左旋转（SingleRotateWithLeft）；对结点p的左孩子的左子树进行一次插入 <br />单右旋转（SingleRotateWithRight）；对结点p的右孩子的右子树进行一次插入  <br />双左旋转（DoubleRotateWithLeft）；对结点p的左孩子的右子树进行一次插入 <br />双右旋转（DoubleRotateWithRight）；对结点p的右孩子的左子树进行一次插入  <br />static Position SingleRotateWithLeft(Position K2)<br />{<br />    Position K1;<br />    <br />    K1 = K2-&gt;lchild;  //在K2和K1之间进行一次单左旋转 <br />    K2-&gt;lchild = K1-&gt;rchild;<br />    K1-&gt;rchild = K2;<br />    <br />    K2-&gt;height = Max(Height(K2-&gt;lchild), Height(K2-&gt;rchild)) + 1;<br />    K1-&gt;height = Max(Height(K1-&gt;lchild), Height(K1-&gt;rchild)) + 1;<br />    <br />    return K1;<br />}<br /><br />static Position SingleRotateWithRight(Position K2)<br />{<br />    Position K1;<br />    <br />    K1 = K2-&gt;rchild;    //在K2和K1之间进行一次单右旋转 <br />    K2-&gt;rchild = K1-&gt;lchild;<br />    K1-&gt;lchild = K2;<br />    <br />    K2-&gt;height = Max(Height(K2-&gt;lchild), Height(K2-&gt;rchild)) + 1;<br />    K1-&gt;height = Max(Height(K1-&gt;lchild), Height(K1-&gt;rchild)) + 1;<br />    <br />    return K1;<br />}<br /><br />static Position DoubleRotateWithLeft(Position K3)<br />{<br />    K3-&gt;lchild = SingleRotateWithRight(K3-&gt;lchild); //在K2和K1之间进行一次单右旋转 <br />    <br />    return SingleRotateWithLeft(K3); //在K3和K2之间进行一次单左旋转 <br />}<br /><br />static Position DoubleRotateWithRight(Position K3)<br />{<br />    K3-&gt;rchild = SingleRotateWithLeft(K3-&gt;rchild); //在K2和K1之间进行一次单左旋转 <br />    <br />    return SingleRotateWithRight(K3);//在K3和K2之间进行一次单右旋转 <br />}<br /><br />//向AVL树插入结点的操作 <br />AvlTree Insert(float x, AvlTree T)<br />{<br />    if(T == NULL)<br />    {<br />        T = (Position)malloc(sizeof(struct avlnode));<br />        if(T == NULL)<br />        {<br />            puts("wrong"); <br />            exit(1);<br />        }<br />        T-&gt;data = x;  <br />        T-&gt;height = 0;<br />        T-&gt;lchild = T-&gt;rchild = NULL;<br />    }<br />    else if(T-&gt;data == x)//不做任何插入操作 <br />        ;<br />    else if(T-&gt;data &gt; x)//把s所指结点插入到左子树中<br />    {<br />          T-&gt;lchild = Insert(x, T-&gt;lchild);<br />          if(Height(T-&gt;lchild) - Height(T-&gt;rchild) == 2) //若平衡被破坏<br />          {<br />            if(x &lt; T-&gt;lchild-&gt;data)     //若x比T的左孩子小，对T单左旋转  <br />                T = SingleRotateWithLeft(T);<br />            else                         //否则，对T双左旋转   <br />                T = DoubleRotateWithLeft(T);<br />        }<br />    }<br />    else      //把s所指结点插入到右子树中<br />    {<br />          T-&gt;rchild = Insert(x, T-&gt;rchild);<br />          if(Height(T-&gt;rchild) - Height(T-&gt;lchild) == 2)<br />          {<br />            if(x &gt; T-&gt;rchild-&gt;data)    //若x比T的右孩子大，对T单右旋转  <br />                T = SingleRotateWithRight(T);<br />            else                        //否则，对T双右旋转   <br />                T = DoubleRotateWithRight(T);<br />        }<br />    }<br />    T-&gt;height = Max(Height(T-&gt;lchild), Height(T-&gt;rchild)) + 1;<br />    <br />    return T;   <br />}<br />int Max(int a, int b)<br />{<br />    if(a &gt; b)<br />        return a;<br />    else<br />        return b;<br />}<br />还有一种AVL树，它的结构中不包含高度特征，但包含一个平衡因子bf，用来判断结点的平衡性，若左孩子比右孩子高，则bf==1；否则，bf==-1；若左右相等则bf==0。<br />    AVL树的结点声明；<br />enum  BALANCE{LH = 1, EH = 0, RH = -1};<br />typedef struct avlnode<br />{<br />    BALANCE bf;//比普通二杈有序树多了一个平衡因子信息<br />    ElemType data;<br />    struct avlnode *lchild, *rchild;<br />} *AvlTree, *Position;<br />//----------AVL树基本操作------------ ------------------------------<br />AvlTree MakeEmpty(AvlTree T);<br />Position Find(ElemType x, AvlTree T);<br />Position FindMin(AvlTree T);<br />Position FindMax(AvlTree T);<br />AvlTree Insert(ElemType x, AvlTree T);<br />AvlTree Delete(ElemType x, AvlTree T);<br />ElemType Retrieve(Position P);<br /><br />//----------AVL树基本操作的算法实现--------------------<br /><br />//在对一棵AVL树进行插入操作后，可能会破坏它的平衡条件，因此必须对新的AVL树进行调整，<br />这里用到了“单旋转”或“双旋转”的算法，分别适用于：<br />单左旋转（SingleRotateWithLeft）；对结点p的左孩子的左子树进行一次插入<br />单右旋转（SingleRotateWithRight）；对结点p的右孩子的右子树进行一次插入<br />双左旋转（DoubleRotateWithLeft）；对结点p的左孩子的右子树进行一次插入<br />双右旋转（DoubleRotateWithRight）；对结点p的右孩子的左子树进行一次插入<br />Position SingleRotateWithLeft(Position K2)<br />{<br />    Position K1;<br /><br />    K1 = K2-&gt;lchild;  //在K2和K1之间进行一次单左旋转<br />    K2-&gt;lchild = K1-&gt;rchild;<br />    K1-&gt;rchild = K2;<br /><br />    return K1;<br />}<br /><br />Position SingleRotateWithRight(Position K2)<br />{<br />    Position K1;<br /><br />    K1 = K2-&gt;rchild;    //在K2和K1之间进行一次单右旋转<br />    K2-&gt;rchild = K1-&gt;lchild;<br />    K1-&gt;lchild = K2;<br /><br />    return K1;<br />}<br /><br />Position DoubleRotateWithLeft(Position K3)<br />{<br />    K3-&gt;lchild = SingleRotateWithRight(K3-&gt;lchild); //在K2和K1之间进行一次单右旋转<br /><br />    return SingleRotateWithLeft(K3); //在K3和K2之间进行一次单左旋转<br />}<br /><br />Position DoubleRotateWithRight(Position K3)<br />{<br />    K3-&gt;rchild = SingleRotateWithLeft(K3-&gt;rchild); //在K2和K1之间进行一次单左旋转<br /><br />    return SingleRotateWithRight(K3);//在K3和K2之间进行一次单右旋转<br />}<br /><br />AvlTree LeftBalance(AvlTree T) //左平衡处理<br />{<br />      AvlTree lT = T-&gt;lchild;<br />      switch (lT-&gt;bf) //检查左树的平衡度，并做相应处理<br />      {<br />            case LH :   T = SingleRotateWithLeft(T); //若新结点插入在T的左孩子的左子树上，对T单左旋转<br />                        T-&gt;bf = lT-&gt;bf = EH;   //重新设置平衡度<br />                        break;<br />            case RH :   AvlTree rT = lT-&gt;rchild;//若新结点插入在T的左孩子的右子树上，对T双左旋转，并重新设置平衡度<br />                        switch (rT-&gt;bf)<br />                        {<br />                              case LH :   T-&gt;bf = RH;<br />                                          lT-&gt;bf = EH;<br />                                          break;<br />                              case EH :   T-&gt;bf = lT-&gt;bf = EH; //我感觉这种情况应该不会出现<br />                                          break;<br />                              case RH :   T-&gt;bf = EH;<br />                                          lT-&gt;bf = LH;<br />                                          break<br />                        }<br />                        rT-&gt;bf = EH;<br />                        T = DoubleRotateWithLeft(T);<br />                        break;<br />      }<br />      return T;<br />}<br /><br />AvlTree RightBalance(AvlTree T) //右平衡处理<br />{<br />      AvlTree rT = T-&gt;rchild;<br />      switch (rT-&gt;bf) //检查右树的平衡度，并做相应处理<br />      {<br />            case LH :   T = SingleRotateWithRight(T); //若新结点插入在T的右孩子的右子树上，对T单右旋转<br />                        T-&gt;bf = rT-&gt;bf = EH;   //重新设置平衡度<br />                        break;<br />            case RH :   AvlTree lT = rT-&gt;lchild;//若新结点插入在T的右孩子的左子树上，对T双右旋转，并重新设置平衡度<br />                        switch (lT-&gt;bf)<br />                        {<br />                              case LH :   T-&gt;bf = EH;<br />                                          rT-&gt;bf = RH;<br />                                          break;<br />                              case EH :   T-&gt;bf = rT-&gt;bf = EH; //我感觉这种情况应该不会出现<br />                                          break;<br />                              case RH :   T-&gt;bf = LH;<br />                                          rT-&gt;bf = EH;<br />                                          break<br />                        }<br />                        lT-&gt;bf = EH;<br />                        T = DoubleRotateWithRight(T);<br />                        break;<br />      }<br />      return T;<br />}<br /><br />//向AVL树插入结点的操作<br />AvlTree Insert(ElemType x, AvlTree T, bool &amp; taller)<br />{<br />    if(T == NULL)<br />    {<br />        T = (Position)malloc(sizeof(struct avlnode));<br />        if(T == NULL)<br />        {<br />            puts("wrong");<br />            exit(1);<br />        }<br />        T-&gt;data = x;<br />        T-&gt;lchild = T-&gt;rchild = NULL;<br />        T-&gt;bf = EH;<br />        taller = true; //插入新结点，树“长高”，置taller为真值<br />    }<br />    else if(T-&gt;data == x)//不做任何插入操作<br />        taller = false; //树未长高，置taller为假值<br />    else if(T-&gt;data &gt; x)//把x插入到左子树中<br />    {<br />          T-&gt;lchild = Insert(x, T-&gt;lchild, taller);<br />          if (taller)//已经插入左子树，且树“长高”，需要检查平衡度，并做相应处理<br />          {<br />                  switch(T-&gt;bf)<br />                  {<br />                        case LH :   T = LeftBalance(T);//原本左树高于右树，需做左平衡处理，树高不变<br />                                    taller = false;<br />                                    break;<br />                        case EH :   T-&gt;bf = LH;//原本左右等高，现在左高于右，且树“长高”<br />                                    taller = true;<br />                                    break;<br />                        case RH :   T-&gt;bf = EH; //原本右树高于左树，现在左右等高，树高不变<br />                                    taller = false;<br />                                    break;<br />                  }<br />            }<br />    }<br />    else      //把x插入到右子树中，仿照处理左树的方法处理<br />    {<br />            T-&gt;rchild = Insert(x, T-&gt;rchild, taller);<br />          if (taller)<br />          {<br />                  switch(T-&gt;bf)<br />                  {<br />                        case LH :   T-&gt;bf = EH;<br />                                    taller = false;<br />                                    break;<br />                        case EH :   T-&gt;bf = RH;<br />                                    taller = true;<br />                                    break;<br />                        case RH :   T = RightBalance(T);<br />                                    taller = false;<br />                                    break;<br />                  }<br />            }<br />    }<br /><br />    return T;<br />}<br />AVL树应用示例:<br /> /*输入一组数,存储到AVL树中,并进行输出*/<br />#include &lt;iostream&gt;<br />using namespace std;<br /><br />#define MAX 100<br />enum  BALANCE{LH = 1, EH = 0, RH = -1};<br />typedef struct avlnode<br />{<br />    BALANCE bf;//比普通二杈有序树多了一个平衡因子信息<br />    int data;<br />    struct avlnode *lchild, *rchild;<br />} *AvlTree, *Position;<br /><br />int Input(int a[]);//输入数据到数组,未排序<br />void Print(const int a[], int len); //输入未排序的原始数据<br />AvlTree Sort(AvlTree A, const int a[], int len); //对数据进行排序<br />AvlTree Insert(int x, AvlTree T, bool &amp; taller); //把数据存储到AVL树中<br />Position SingleRotateWithLeft(Position K2); //单左旋转<br />Position SingleRotateWithRight(Position K2); //单右旋转<br />Position DoubleRotateWithLeft(Position K3);//双左旋转<br />Position DoubleRotateWithRight(Position K3);//双右旋转<br />AvlTree LeftBalance(AvlTree T);// 左平衡处理<br />AvlTree RightBalance(AvlTree T); //右平衡处理<br />void inorder(const AvlTree bt); //中序遍历AVL树<br />void PrintBT(AvlTree bt); //输出二杈树<br /><br />int main(void)<br />{<br />    int a[MAX]={0};<br />    int len;<br />    AvlTree A=NULL;<br /><br />    len = Input(a);<br />    Print(a, len);<br />    printf("\n");<br />    A = Sort(A, a, len);<br />    PrintBT(A);<br />    printf("\n");<br />    inorder(A);<br />    system("pause");<br />      return 0;<br />}<br />int Input(int a[])<br />{<br />    int i=0;<br /><br />    do{<br />        a[i++] = rand()%1000;//输入随机数<br />    } while(i&lt;MAX);<br />    return i;<br />}<br />void Print(const int a[], int len)<br />{<br />    int i;<br /><br />    for(i=0; i&lt;len; i++)<br />        printf("%d\t", a[i]);<br />}<br />AvlTree Sort(AvlTree A, const int a[], int len)<br />{<br />    int i;<br />    bool taller = false;<br /><br />    for(i=0; i&lt;len; i++)<br />         A = Insert(a[i], A, taller);<br />    return A;<br />}<br />void inorder(const AvlTree bt)<br />{<br />    AvlTree p=bt, stack[MAX];//p表示当前结点，栈stack[]用来存储结点<br />    int top=-1;<br /><br />    do<br />    {<br />        while(p != NULL)//先处理结点的左孩子结点，把所有左孩子依次入栈<br />        {<br />            stack[++top] = p;<br />            p = p-&gt;lchild;<br />        }<br />        if(top &gt;= 0) //所有左孩子处理完毕后<br />        {<br />            p = stack[top--];//栈顶元素出栈<br />            printf("%d\t", p-&gt;data); //输出该结点<br />            p = p-&gt;rchild; //处理其右孩子结点<br />        }<br />    } while((p != NULL)||(top &gt;= 0));<br />}<br /><br />//向AVL树插入结点的操作<br />AvlTree Insert(int x, AvlTree T, bool &amp; taller)<br />{<br />    if(T == NULL)<br />    {<br />        T = (Position)malloc(sizeof(struct avlnode));<br />        if(T == NULL)<br />        {<br />            puts("wrong");<br />            exit(1);<br />        }<br />        T-&gt;data = x;<br />        T-&gt;lchild = T-&gt;rchild = NULL;<br />        T-&gt;bf = EH;<br />        taller = true; //插入新结点，树“长高”，置taller为真值<br />    }<br />    else if(T-&gt;data == x)//不做任何插入操作<br />        taller = false; //树未长高，置taller为假值<br />    else if(T-&gt;data &gt; x)//把x插入到左子树中<br />    {<br />          T-&gt;lchild = Insert(x, T-&gt;lchild, taller);<br />          if (taller)//已经插入左子树，且树“长高”，需要检查平衡度，并做相应处理<br />          {<br />                  switch(T-&gt;bf)<br />                  {<br />                        case LH :   T = LeftBalance(T);//原本左树高于右树，需做左平衡处理，树高不变<br />                                    taller = false;<br />                                    break;<br />                        case EH :   T-&gt;bf = LH;//原本左右等高，现在左高于右，且树“长高”<br />                                    taller = true;<br />                                    break;<br />                        case RH :   T-&gt;bf = EH; //原本右树高于左树，现在左右等高，树高不变<br />                                    taller = false;<br />                                    break;<br />                  }<br />            }<br />    }<br />    else      //把x插入到右子树中，仿照处理左树的方法处理<br />    {<br />            T-&gt;rchild = Insert(x, T-&gt;rchild, taller);<br />          if (taller)<br />          {<br />                  switch(T-&gt;bf)<br />                  {<br />                        case LH :   T-&gt;bf = EH;<br />                                    taller = false;<br />                                    break;<br />                        case EH :   T-&gt;bf = RH;<br />                                    taller = true;<br />                                    break;<br />                        case RH :   T = RightBalance(T);<br />                                    taller = false;<br />                                    break;<br />                  }<br />            }<br />    }<br /><br />    return T;<br />}<br /><br />Position SingleRotateWithLeft(Position K2)<br />{<br />    Position K1;<br /><br />    K1 = K2-&gt;lchild;  //在K2和K1之间进行一次单左旋转<br />    K2-&gt;lchild = K1-&gt;rchild;<br />    K1-&gt;rchild = K2;<br /><br />    return K1;<br />}<br /><br />Position SingleRotateWithRight(Position K2)<br />{<br />    Position K1;<br /><br />    K1 = K2-&gt;rchild;    //在K2和K1之间进行一次单右旋转<br />    K2-&gt;rchild = K1-&gt;lchild;<br />    K1-&gt;lchild = K2;<br /><br />    return K1;<br />}<br /><br />Position DoubleRotateWithLeft(Position K3)<br />{<br />    K3-&gt;lchild = SingleRotateWithRight(K3-&gt;lchild); //在K2和K1之间进行一次单右旋转<br /><br />    return SingleRotateWithLeft(K3); //在K3和K2之间进行一次单左旋转<br />}<br /><br />Position DoubleRotateWithRight(Position K3)<br />{<br />    K3-&gt;rchild = SingleRotateWithLeft(K3-&gt;rchild); //在K2和K1之间进行一次单左旋转<br /><br />    return SingleRotateWithRight(K3);//在K3和K2之间进行一次单右旋转<br />}<br /><br />AvlTree LeftBalance(AvlTree T) //左平衡处理<br />{<br />      AvlTree lT = T-&gt;lchild;<br />      switch (lT-&gt;bf) //检查左树的平衡度，并做相应处理<br />      {<br />            case LH :   T = SingleRotateWithLeft(T); //若新结点插入在T的左孩子的左子树上，对T单左旋转<br />                        T-&gt;bf = lT-&gt;bf = EH;   //重新设置平衡度<br />                        break;<br />            case RH :   AvlTree rT = lT-&gt;rchild;//若新结点插入在T的左孩子的右子树上，对T双左旋转，并重新设置平衡度<br />                        switch (rT-&gt;bf)<br />                        {<br />                              case LH :   T-&gt;bf = RH;<br />                                          lT-&gt;bf = EH;<br />                                          break;<br />                              case EH :   T-&gt;bf = lT-&gt;bf = EH; //我感觉这种情况应该不会出现<br />                                          break;<br />                              case RH :   T-&gt;bf = EH;<br />                                          lT-&gt;bf = LH;<br />                                          break;<br />                        }<br />                        rT-&gt;bf = EH;<br />                        T = DoubleRotateWithLeft(T);<br />                        break;<br />      }<br />      return T;<br />}<br /><br />AvlTree RightBalance(AvlTree T) //右平衡处理<br />{<br />      AvlTree rT = T-&gt;rchild;<br />      switch (rT-&gt;bf) //检查右树的平衡度，并做相应处理<br />      {<br />            case RH :   T = SingleRotateWithRight(T); //若新结点插入在T的右孩子的右子树上，对T单右旋转<br />                        T-&gt;bf = rT-&gt;bf = EH;   //重新设置平衡度<br />                        break;<br />            case LH :   AvlTree lT = rT-&gt;lchild;//若新结点插入在T的右孩子的左子树上，对T双右旋转，并重新设置平衡度<br />                        switch (lT-&gt;bf)<br />                        {<br />                              case LH :   T-&gt;bf = EH;<br />                                          rT-&gt;bf = RH;<br />                                          break;<br />                              case EH :   T-&gt;bf = rT-&gt;bf = EH; //我感觉这种情况应该不会出现<br />                                          break;<br />                              case RH :   T-&gt;bf = LH;<br />                                          rT-&gt;bf = EH;<br />                                          break;<br />                        }<br />                        lT-&gt;bf = EH;<br />                        T = DoubleRotateWithRight(T);<br />                        break;<br />      }<br />      return T;<br />}<br /><br />void PrintBT(AvlTree bt)<br />{<br />    if(bt != NULL)<br />    {<br />        printf("%d", bt-&gt;data);<br />        if(bt-&gt;lchild!=NULL || bt-&gt;rchild!=NULL)<br />        {<br />            printf("(");<br />            PrintBT(bt-&gt;lchild);<br />            if(bt-&gt;rchild!=NULL)<br />                printf(",");<br />            PrintBT(bt-&gt;rchild);<br />            printf(")");<br />        }<br />    }<br />}<img src ="http://www.cppblog.com/goal00001111/aggbug/8151.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-06-04 16:53 <a href="http://www.cppblog.com/goal00001111/archive/2006/06/04/8151.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>二叉排序树的删除</title><link>http://www.cppblog.com/goal00001111/archive/2006/06/04/8150.html</link><dc:creator>梦想飞扬</dc:creator><author>梦想飞扬</author><pubDate>Sun, 04 Jun 2006 08:52:00 GMT</pubDate><guid>http://www.cppblog.com/goal00001111/archive/2006/06/04/8150.html</guid><wfw:comment>http://www.cppblog.com/goal00001111/comments/8150.html</wfw:comment><comments>http://www.cppblog.com/goal00001111/archive/2006/06/04/8150.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/goal00001111/comments/commentRss/8150.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/goal00001111/services/trackbacks/8150.html</trackback:ping><description><![CDATA[对于一般的二叉树来说，删去树中的一个结点是没有意义的，因为它将使以被删除的结点为根的子树变成森林，破坏了整棵树的结构<br />但是，对于二叉排序树，删去树上的一个结点相当于删去有序序列中的一个记录，只要在删除某个结点后不改变二叉排序树的特性即可。<br />      在二叉排序树上删除一个结点的算法如下：<br />btree * DeleteBST(btree *b, ElemType x)<br />{<br />      if (b)<br />      {<br />            if (b-&gt;data == x)<br />                  b = DelNode(b);<br />            else if (b-&gt;data &gt; x)<br />                  b-&gt;lchild = DeleteBST(b-&gt;lchild, x);<br />            else<br />                  b-&gt;rchild = DeleteBST(b-&gt;rchild, x);<br />      }<br />      return b;<br />}<br />其中删除过程有两种方法。<br />第一种过程如下：<br />1。若p有左子树，找到其左子树的最右边的叶子结点r，用该叶子结点r来替代p，把r的左孩子<br />作为r的父亲的右孩子。<br />2。若p没有左子树，直接用p的右孩子取代它。<br /><br />第二种过程如下：<br />1。若p有左子树，用p的左孩子取代它；找到其左子树的最右边的叶子结点r，把p的右子树作为r<br />的右子树。<br />2。若p没有左子树，直接用p的右孩子取代它。<br />    两种方法各有优劣，第一种操作简单一点点，但均衡性不如第二种，因为它将结点p的右子树<br />全部移到左边来了。下面将分别以两种种思路编写代码。<br /><br /><br />第一种：<br />btree * DelNode(btree *p)<br />{<br />      if (p-&gt;lchild)<br />      {<br />            btree *r = p-&gt;lchild;   //r指向其左子树;<br />        while(r-&gt;rchild != NULL)//搜索左子树的最右边的叶子结点r<br />        {<br />            r = r-&gt;rchild;<br />        }<br />            r-&gt;rchild = p-&gt;rchild;<br /><br />            btree *q = p-&gt;lchild;   //q指向其左子树;<br />            free(p);<br />            return q;<br />      }<br />      else<br />      {<br />            btree *q = p-&gt;rchild;   //q指向其右子树;<br />            free(p);<br />            return q;<br />      }<br />}<br /><br />第二种：<br />btree * DelNode(btree *p)<br />{<br />      if (p-&gt;lchild)<br />      {<br />            btree *r = p-&gt;lchild;   //r指向其左子树;<br />            btree *prer = p-&gt;lchild;   //prer指向其左子树;<br />        while(r-&gt;rchild != NULL)//搜索左子树的最右边的叶子结点r<br />        {<br />                  prer = r;<br />            r = r-&gt;rchild;<br />        }<br /><br />        if(prer != r)//若r不是p的左孩子，把r的左孩子作为r的父亲的右孩子<br />        {<br />                  prer-&gt;rchild = r-&gt;lchild;<br />                  r-&gt;lchild = p-&gt;lchild; //被删结点p的左子树作为r的左子树<br />            }<br />        r-&gt;rchild = p-&gt;rchild; //被删结点p的右子树作为r的右子树<br /><br />            free(p);<br />            return r;<br />      }<br />      else<br />      {<br />            btree *q = p-&gt;rchild;   //q指向其右子树;<br />            free(p);<br />            return q;<br />      }<br />}<br />    但是上面这种方法，把r移来移去，很容易出错，其实在这里我们删除的只是p的元素值，而不是它的地址，所以完全没有必要移动指针。仔细观察，发现我们删除的地址实际上是p的左子树的最右边的叶子结点r的地址，所以我们只要把r的数据填到p中，然后把r删除即可。<br />算法如下：<br />btree * DelNode(btree *p)<br />{<br />      if (p-&gt;lchild)<br />      {<br />            btree *r = p-&gt;lchild;   //r指向其左子树;<br />            btree *prer = p-&gt;lchild;   //prer指向其左子树;<br />        while(r-&gt;rchild != NULL)//搜索左子树的最右边的叶子结点r<br />        {<br />                  prer = r;<br />            r = r-&gt;rchild;<br />        }<br />            p-&gt;data = r-&gt;data;<br /><br />        if(prer != r)//若r不是p的左孩子，把r的左孩子作为r的父亲的右孩子<br />                  prer-&gt;rchild = r-&gt;lchild;<br />            else<br />            p-&gt;lchild = r-&gt;lchild; //否则结点p的左子树指向r的左子树<br /><br />            free(r);<br />            return p;<br />      }<br />      else<br />      {<br />            btree *q = p-&gt;rchild;   //q指向其右子树;<br />            free(p);<br />            return q;<br />      }<br />}<br /><img src ="http://www.cppblog.com/goal00001111/aggbug/8150.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/goal00001111/" target="_blank">梦想飞扬</a> 2006-06-04 16:52 <a href="http://www.cppblog.com/goal00001111/archive/2006/06/04/8150.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>