[藏]关于B树的一篇文章

很多人对B树的理解有很多错误,我看的最多的就是有人混淆二叉树(Binary Tree)和B树(B-Tree),二叉树是不用简称,也就是BT的,而特殊一点的二叉搜索树才会用BST(Binary Search Tree),至于B-树和B树,这两个其实一样的,英文都是(B-Tree),注意看中间的-号,这个是国内翻译的问题.所以大家不要被误导. Rudolf Bayer 和 Ed McCreight 于1972年,在Boeing Research Labs 工作时发明了B 树,但是他们没有解释B 代表什么意义(如果有的话).Douglas Comer 解释说: 两位作者从来都没解释过B树的原始意义。我个人觉得很有可能是他的名字,程序员对其作品的一种情结吧. 这篇文章来自国外,是某大学的CS课程在线的,由于有时候无法访问,我直接提供PDF版,对其构造过程非常清晰.非常非常好的B树教程,图示很多,就不翻译了,强烈推荐阅读! 下载:B树讲解

2013-04-01 · 1 min · bystander

简单扩展方法增强代码可读性

本文技术含量不高,但是思路可以借鉴。。 介绍 当你处理计时器,时间间隔,或是其他关于日期的计算的时候。你必然会使用TimeSpan类。 我觉得写出下面的代码可读性并不好。。 // 1个表示5小时的时间间隔 var theTimespan = new TimeSpan(0, 5, 0, 0, 0); 而下面的代码就要好一些 //一个表示5小时的时间间隔 var theTimespan = 5.Hours(); ** 扩展方法** 使用这些扩展了int类的方法。可以使得创建TimeSpan可读性更好 public static TimeSpan Days(this int value) { return new TimeSpan(value, 0, 0, 0, 0); } public static TimeSpan Years(this int value) { var dt = DateTime.Now.AddYears(value); return (dt - DateTime.Now).Duration(); } public static TimeSpan Hours(this int value) { return new TimeSpan(0, value, 0, 0, 0); } public static TimeSpan Minutes(this int value) { return new TimeSpan(0, 0, value, 0, 0); } public static TimeSpan Seconds(this int value) { return new TimeSpan(0, 0, 0, value, 0); } public static TimeSpan Milliseconds(this int value) { return new TimeSpan(0, 0, 0, 0, value); } 许可 本文所有源代码包括文件在CPOL下授权。。 原文地址:Simple-extension-methods-for-code-readability 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

2012-10-04 · 1 min · bystander

11个高效的VS调试技巧

介绍 调试是软件开发周期中的一个很重要的部分,有时很有挑战性,有时候则让程序员迷惑,有时候让程序员发疯,但是。可以肯定的是,对于任何不是太那个微不足道的程序来说,调试是不可避免的。近年来,调试工具的发展已经使得很多调试任务简单省时了。 本文总结了十个调试技巧,当你使用VS的时候可以节省你很多时间。 1. 悬停鼠标查看表达式 调试有时候很有挑战性,当你步入一个函数想看看哪块出错的时候,查看调用栈来想想值是从哪来的。另一些情况下,则需要添加一些监视表达式,或者查看局部变量列表,这通常还是花费一些时间的,但是。如果你把你鼠标指向你感兴趣的一个变量。你会发现事情简单多了。而且,类和结构体可以通过单击展开。这样。你就可以方便快捷的找到你想查看的变量了。 2. 实时改变值 调试器不仅仅是一个分析程序崩溃或是异常结果的工具了,许多bug都可以通过步入新写的函数,检查函数是否如期望的那样运行来预防。有时候你可能会好奇“如果条件为真函数会正确运行吗”大多数情况下,根本不需要改变代码重启挑起,仅仅把鼠标悬停到一个变量上,双击值然后输入一个新值就可以了。。 3.设置下一条语句 一个典型的调试情况就是通过单步跟踪分析为什么一个函数调用失败了。当你发现一个函数调用的另一个函数返回错误的时候你会怎么做?重启调试?有更好的方法。拖动这个黄色的语句标识到你想下一步执行的语句前就可以了。比如你刚才失败的那块,然后步入。简单,不是吗? 4.编辑然后继续 调试一个复杂的程序,或是一个插件的时候,在一个被调用很多次的函数处发现一个错误。但是不想浪费时间停下来,重新编译然后重新调试。没问题,仅仅在该处改正代码然后继续单步就可以。VS会修正程序然后继续调试不需要重启 注意,编辑然后继续有大量的已知限制,首先,64位代码是不行的。如果他如果为你的C#程序工作。就去工程设置的生成选项,然后目标平台为x86.不要担心。发布版的目标平台和调试的时候是分开的。可以被设置为任何平台。。 第二.编辑然后继续改变在一个方法里应该是局部的。。如果你改变了方法签名,添加一些新方法或是类。你就不得不重启程序了。或者撤销改变来继续。改变方法也包含lambda表达式隐式修改的自动生成的代理类,因此也不能继续。 5.方便的监视窗口 大概现代的调试器都有一个监视窗口,无论如何。VS允许你简单的添加或移除变量。单击空行,输入你的表达式按下回车,或者是在不需要的表达式上按下Delete键就可以删除了。 而且。从监视窗口你不仅仅可以看到“正常”的变量。你可以输入$handles 来追踪你的程序打开了多少句柄(可以方便的修复内存泄漏) ,输入$err 可以看到上一个函数的错误码,然后使用工具-错误信息可以看到更详细的描述,或者输入@eax(64位是@rax)来查看包含函数返回值的寄存器。 6.带注释的反汇编 使用交互式的反汇编模式可以使得优化程序的关键部分变得很容易,VS给出对应你代码每一行的汇编指令,并且运行单步运行。同时,可以在任何位置设置断点。而且,表达式的查看和修改也像在C++代码里一样 7.带有栈的线程窗口 调试多线程的程序是痛苦的。。或者也可以是很有趣的。取决于你的调试器。VS2010真正优美的特性是线程窗口的栈视图,通过窗口的调用栈你可以方便的总览线程。 8.条件断点 如果你尝试通过断点再现一个罕见的事件,该情况引发了一些严重的错误。你可以添加条件断点。定义一个断点的条件,然后如果条件不成立,VS会忽略该断点 9.内存窗口 有些bug由不正确的结构体定义引起,忽略的对齐属性等等。查看内存中的内容可以定位然后修复bug。VS提供了一个放百年的内存窗口,可以把值以8/16/32/64位的形式展示。还有浮点值。也允许实时改变他们。就像在文本编辑器里一样。 10.转到定义 这个特性不是直接关于调试的,而是关于浏览大项目的。如果你尝试找到一些不是你自己写的代码中的错误,快速知道“这个类型是什么”或者“这个函数是干嘛的”,可以节省很多时间,VS通过一个转到定义命令方便了你。 11.命令窗口 第十一的技巧chaau已经建议过了。确实可以节省很多时间,VS支持命令窗口,可以通过,视图-其他窗口-命令窗口来启动。一旦激活,你可以输入不同的命令来自动化调试。举个例子。你可以通过如下命令 简单的模拟MFC COleDateTime 变量。 ? dt.Format("%Y-%m-%d %H:%M:%S") 许可 本文包括源代码和文件在CPOL下授权。 原文地址:10plus-powerful-debugging-tricks-with-Visual-Studi 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

2012-10-03 · 1 min · bystander

VS2010 编译安装boost库

实践是最好的办法。。学习C++,想试试线程,然后打算用boost库,结果boost库编译差点吓到我。。没看到比较完整的安装教程。。一直耽搁。今天动手。完成了。方法记录如下: 1.下载boost 从boost官网( http://www.boost.org )上下载最新的boost版本,现在最新是1.49版本,解压到自定义目录(我解压到了D:/program files,最终的目录结构是D:\Program Files\boost_1_49_0) 2.编译安装 在D:\Program Files\boost_1_49_0的目录下,有一个bootstrap.bat文件,直接双击运行。就会在同目录生成b2.exe;bjam.exe两个文件。 3.设定编译环境 修改user-config.jam (D:\Program Files\boost_1_49_0\tools\build\v2\user-config.jam) 的MSVC configuration MSVC configuration Configure msvc (default version, searched for in standard locations and PATH). using msvc ; 在上面这段的下面直接添加如下的文字。 using msvc : 10.0 : :/wd4819/D_CRT_SECURE_NO_DEPRECATE/D_SCL_SECURE_NO_DEPRECATE/D_SECURE_SCL=0 ; 保存关闭。 4.开始编译 点击开始->所有程序->“Microsoft Visual Studio 2010”,指向“Visual Studio tools(工具)”,然后单击“Visual Studio 2010 command prompt(命令提示)” 使用cd切换到D:\Program Files\boost_1_49_0目录。这个就不说了 然后输入如下的代码: b2 toolset=msvc-10.0 architecture=x86 instruction-set=i686 address-model=32 link=static variant=debug,release threading=multi runtime-link=shared --without-python --without-mpi --without-wave --without-graph --without-math --without-serialization stage 解释一下命令的意思: 1.toolset:表示编译器工具,我安装的是VS2010,所以是msvc-10(如果你是VS2005,可以使用msvc-8.0 VS2008是msvc-9.0) 2.architecture:表示架构,也就是你的CPU架构,x86,x64,因为我安装的是win7 32位,所以使用了x86的架构 3.instruction-set:表示指令集,依然是8086指令集 4.address-model:表示地址长度为32位 5.link:表示生成动态/静态链接库,动态链接库是shared,静态链接库是static,一般都会编译成静态库,因为给出程序的时候打包boost的库会非常庞大 6.variant:表示生成的Debug或者release版本,一般情况下会两种版本都会编译出来的 7.threading:表示单/多线程编译,一般我们的程序都会用到多线程,所以选择了multi 8.runtime-link:表示动态/静态链接C/C++运行时库(C/C++ Runtime),我们选择了动态链接 9.without/with:表示不需要编译/需要编译哪些库,一些自己不用的库可以无需编译 10.stage/install:stage表示只生成库文件(DLL和Lib),install还会生成包含头文件的include目录,推荐使用stage,因为boost_1_49\boost中就是boost库完整的头文件,所以无需再拷贝一份出来。编译出来的库会放在stage文件夹中 这样一份完整的boost库就生成了,剩下就是直接使用到项目中了。 其实编译的具体命令都是可以自己写的。如果你需要编译所有。只需要使用下面的这行代码 b2 –toolset=msvc-10.0 –build-type=complete 就可以了。 不出问题的话。就开始编译了。。登个半个多小时吧。就会完成了。 5.设置vs 打开vs,新建一个工程。然后工程属性。配置属性->C/C++ ,附加包含目录 填上 D:\Program Files\boost_1_49_0;%(AdditionalIncludeDirectories) 这个是最终的结果,你也可以手动添加 在左侧选择链接器->附加库目录,填上 D:\Program Files\boost_1_49_0\stage\lib;%(AdditionalLibraryDirectories) 就可以了。 6.测试 在你新建的工程里输入如下的代码。运行成功就说明可以了 #include <boost/thread/thread.hpp> #include <iostream> void hello() { std::cout << "Hello world, I'm a thread!" << std::endl; } int main(int argc, char* argv[]) { boost::thread thrd(&hello); thrd.join(); return 0; } 参考: http://www.cppfans.org/1317.html http://www.cnblogs.com/ComputerG/archive/2011/03/10/1979730.html http://www.cppblog.com/shaker/archive/2011/11/30/33583.html

2012-05-24 · 1 min · bystander

快速排序算法

#include using namespace std; //化分区间,找到最后元素的排序位置。并返回分隔的点(即最后一数据排序的位置)。 //划分的区间是[nBegin, nEnd). pData是保存数据的指针 int Partition(int* pData, int nBeging, int nEnd) { int i = nBeging - 1; //分隔符号,最后nD保存在这里 --nEnd; int nD = pData[nEnd]; //比较的数据。 int nTemp; // 交换用的临时数据 //遍历数据比较,找到nD的位置,这里注意,比较结果是, //i的左边是小于等于nD的,i的右边是大于nD的 for (int j = nBeging; j < nEnd; ++j) { if (pData[j] <= nD) //如果数据比要比较的小,则在该数据的左边,与i+1交换 { ++i; //小于nD的数据多一个,所以要加1,i的左边数据都比nD小 nTemp = pData[i]; //交换数据 pData[i] = pData[j]; pData[j] = nTemp; } } //最后不要忘了吧nD和i+1交换,因为这里就是nD的位置咯。 ++i; pData[nEnd] = pData[i]; pData[i] = nD; return i; //返回nD的位置,就是分割的位置。 } //排序的递归调用。 int QuickSortRecursion(int* pData, int nBeging, int nEnd) { if (nBeging >= nEnd -1) //如果区域不存在或只有一个数据则不递归排序 { return 1; } //这里因为分割的时候,分割点处的数据就是排序中他的位置。 //也就是说他的左边的数据都小于等于他,他右边的数据都大于他。 //所以他不在递归调用的数据中。 int i = Partition(pData, nBeging, nEnd); //找到分割点 QuickSortRecursion(pData, nBeging, i); //递归左边的排序 QuickSortRecursion(pData, i + 1, nEnd); //递归右边的排序 return 1; } //快速排序 int QuickSort(int* pData, int nLen) { //递归调用,快速排序。 QuickSortRecursion(pData, 0, nLen); return 1; } int main() { int nData[10] = {5,9,3,2,1,6,20,45,88,75}; //测试数据 QuickSort(nData, 10); //调用快速排序 for (int i = 0; i < 10; ++i) //输出结果 { cout<

2012-05-19 · 1 min · bystander

C++回调函数

 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。 也就是说,回调函数它首先是一个函数,然后有一个指针指向它(该指针称为函数指针),在别的代码块中,通过这个函数指针调用了这个函数,仅此而已。 下面给出一个例子,我写出了比较详细的注释。希望足够清晰。这个例子说明了,回调函数可以把调用者和被调用者分开,对于调用者来说,只需要知道自己要调用一个函数,该函数有一个string类型的参数,至于具体调用哪个,被调用的函数到底怎么执行,怎么解释该参数,是完全不用关心的。 #include #include using namespace std; typedef void (*PF)(string s); //定义一个名为PF的函数指针,该指针指向一类函数,该类函数有一个string类型的参数,返回值为void。 void funcOne(string s) //回调函数1 { cout << s+" One"<< endl; } void funcTwo(string s) //回调函数2 { cout << s+" Two"<< endl; } void caller( PF pf, string s) //调用函数 { cout << "I am Caller Function" << endl; pf(s); } int main() { string str = "Test CallBack Function"; PF pf1 = funcOne; //实例化一个函数指针,指向func函数 caller(pf1, str); pf1=funcTwo; caller(pf1, str); system("pause"); return 0; } 回调函数的一个很实用的例子就是泛型算法中的max算法,具体可以参见本文末尾的第一篇参考文档, 如果你在自行写代码中发生了 error C2679: 二进制“«”: 没有找到接受“std::string”类型的右操作数的运算符(或没有可接受的转换)错误 说明你没有把string头文件导入,导入即可 个人能力有限,错误之处请留言指正,不胜感激。 参考: http://learn.akae.cn/media/ch24s05.html http://baike.baidu.com/view/414773.htm

2012-05-09 · 1 min · bystander