话说昨天因为校园网的问题导致现在才发博文~唉,想吐槽~

这个是昨天写的,觉得,用来回顾还是很不错的,比较具体的都在笔记中,尤其我觉得里面经验性的东西还是不错的。

2013-8-26

今天在回顾我以前写的笔记,笔记时间应该是在大二。话说,现在我在实验室一边听着胡彦斌的《葬英雄》一边写着学习笔记~

看了以往的笔记,感觉,以前的字写的确实不怎么样,现在嘛,嘿嘿,也不怎么样。不过,感觉还是很不一样的。想想当初学习C++的辛苦,在看着现在写出来的程序,觉得自己还是进步了不少的。C++这门语言,应该算是最难学的语言了吧,我觉得汇编是比C++简单些的。

还有一点,对于一门语言是否精通,我觉得有个很简单的标准,简单的有点苛刻,就是,能否独立的制作这门语言的编译器。如果连编译器都做出来了,那绝对是精通的。你应该会认同吧?

回到正题。

之前在写一些模板类和函数的时候,经常会遇到因为函数参数使用了引用类型而导致不能传递常量参数的情况。这种情况,我当时还是觉得有点无解的。毕竟C++中引用的本质是常指针,也就是:type * const typename;作为指针,肯定是要指向某个变量的地址的,使用空指针和未初始化的指针要命的。但是今天看了我两年前的笔记,突然发现,C++对于常引用提供了很好的解决方法,就是声明一个const的引用参数,形式如下:

  1. int testfunction(const int & n)
  2.  
  3. {
  4.  
  5. return n;
  6.  
  7. }

对于这样的函数,给n传递一个常数,比如10,是能够正常使用的。其原理,我没搞懂,一般来说,汇编指令中的常数一般是夹杂在指令码中的,而引用的本质是指针,唉,哪位大神明白其原理,还望指导一下。

另外其实有个事情我上个学期的时候意识到的一点就是,当一个函数参数使用了const声明的时候,是有多一重好处的,就是,能够同时允许使用常量以及变量。比如,字符串类的构造函数其参数就是这样的,声明为const类型后,就能够使用字符串常量以及指向字符串的指针,好用得很。当然了,const最本质的限制就是,不能对传递来的数据进行更改,但是这里我记着存在两种逻辑,EffectiveC++中讲过的。

刚才上面提到了使用我之前对于CString类制作的尝试,在这里我刚才想了半天,只记得是和C++的const成员函数相关,但是具体是什么忘记了。刚才在书翻了半天,找到了const成员函数这一块,一看,就想起来了。其实const成员函数,我个人觉得最主要的用途之一,其实是为类的const类型对象提供相应的方法。

书中给了这样的一个例子,简单的两行代码。

  1. onst Stock land = Stock(“balabalabala”);
  2.  
  3. land.show();

如果show函数不是cosnt成员数,编译器将拒绝(这词用的好)第二行代码,原因就是,show函数无法保证land中的值不会被修改。一般函数(非成员函数)是通过参数来保证的,而很显然,show函数无参数,无法保证。

这里想要调用show函数唯一的方法就是在类的声明中保证show函数不会修改参数,也就是将其声明为const类型的成员函数。就这样。

同时在我当时的代码的相关函数,比如复制构造函数也因此而导致了问题,因为赋值构造函数的参数是const类型的,因此导致当时未声明为const类型的函数在其中出现违规调用的情况,哪怕函数的功能其仅仅是返回一个字符串首地址。对我来说,这个教训还是很深刻的。后来解决方案也很简单,就是,将相关的函数声明为const类型,problem solved。

C++这门语言要注意的细节还真的是不少的。

另外关于const类型,还有一点要谈的,就是我在上个学期的一个小尝试,比较有趣,之前的博客园文章中貌似也发表过的,今天再长谈一番。

这个尝试就是,去修改一个类型为const的整数的值。当时出现这个念头,很大程度上是因为当时我对于数据存储的理解,也就是,内存中的数据用来表示什么,完全决定于你把它当成什么。

为了稍微体现一下我的这个观点,我在这先写一小段代码,展示下结果。

代码如下:

  1. int num_str = 0x00313233;
  2.  
  3. cout << hex << num_str << endl;
  4.  
  5. cout << (char *)&num_str << endl;

输出结果:

就这么一段很简单的代码,输出结果却完全不一样,尽管,源自同一片内存

另外上面这段代码涉及大端小端的问题,有兴趣请留言啊。

接着往下说,就是如何修改一个const常量的值。这个是因为C/C++中,const常量是有内存去存储的,而非宏之类的单纯替换。这个方法和上面代码的方法是一致的,通过类型转换,将其改变为你想要的类型来进行翻译和使用。看着这段代码:

  1. const int constval = ;
  2.  
  3. int * pnval = (int *)&constval;
  4.  
  5. *pnval = ;
  6.  
  7. cout << constval << endl;

现在看这段代码,觉得蛮有几分调皮的意思。而且这里的值和以前的那篇文章貌似都是一样的。

这段代码你运行后,一般的结果依旧是10,原因的话,我当时看了一下汇编代码,应该是编译器优化,最后一行的constval的值被直接用常数10给取代了。但是如果你以调试的模式来查看,就会发现,在第三行代码运行后,cosntval的值被改为了9.就是这样的。

现在有截图了,看运行截图:

现在,我们换个类型,改为结构体,来使编译器放弃这种优化,代码如下:

  1. struct teststruct
  2.  
  3. {
  4.  
  5. int val;
  6.  
  7. };
  8.  
  9. const teststruct constval = {};
  10.  
  11. teststruct * pnval = (teststruct *)&constval;
  12.  
  13. pnval->val = ;
  14.  
  15. cout << constval.val << endl;

运行结果:

代码整体上是差不多的,但是在这里,结果如预期的那样,确实被修改了。

所以在这里,对于什么const也好,结构也好,指针也好,其存储本质都是内存中以字节为单位排列的二进制数,其意义,不同的解释方式会有不同的结果。

你当它是什么,他就是什么。

今天上午的时候不小心把流量超了,下午去买了张校园网充值卡,结果,到现在还是上不了网……同志,我不知道你看到这文章会是什么时候……

闲着也是闲着,室友们打逆战,当时我就比较感慨这种联网游戏是怎么实现的~唉,腾讯还是挺NB的。我上不了网,所以干脆把数据结构之二叉树又写一遍,写数据结构又不需要上网~

这次写二叉树,没用模板,但是改的话,还是比较快的。这个大家都懂得,我用char类型的做在是因为其输入方便。

二叉树的建立本次采用的是用先序的方式,#表示下一节点为空,常规的字符为节点数据。相信熟悉二叉树的同学和前辈们都了解的~

先看节点类和二叉树类的声明:

  1. class BinaryNode
  2.  
  3. {
  4.  
  5. //定义为class比较好,有利于函数扩充
  6.  
  7. public:
  8.  
  9. BinaryNode();
  10.  
  11. char m_val;//暂定为字符,代码简单
  12.  
  13. BinaryNode * pLeftNode;
  14.  
  15. BinaryNode * pRightNode;
  16.  
  17. };
  18.  
  19. BinaryNode::BinaryNode():m_val(), pLeftNode(NULL), pRightNode(NULL)
  20.  
  21. {
  22.  
  23. ;
  24.  
  25. }
  26.  
  27. class CBinaryTree
  28.  
  29. {
  30.  
  31. private:
  32.  
  33. BinaryNode m_Root;
  34.  
  35. void Method(BinaryNode * & pNode);//递归函数
  36.  
  37. void Del(BinaryNode * & pNode);
  38.  
  39. void FS(BinaryNode * pNode);
  40.  
  41. void MS(BinaryNode * pNode);
  42.  
  43. void BS(BinaryNode * pNode);
  44.  
  45. public:
  46.  
  47. CBinaryTree();
  48.  
  49. ~CBinaryTree();
  50.  
  51. void InputTree();
  52.  
  53. void Search(int nMode = );
  54.  
  55. };

节点类其实就是个带初始化的结构体,没太多说的,常规套路。二叉树类主要两个方法,一个是树的创建,即InputTree,另外一个是Search方法,这个函数整合了三种遍历方式,即前 中 后,换个顺序而已,简单得很。

在二叉树类中,有五个内建方法,Method,用于二叉树的递归构造,Del用于二叉树的清除工作,同样使用递归,而下面的三个函数分别是前 中 后三种方法的递归调用函数。

可以注意到,Method函数以及Del函数的参数都是指针的引用,也就是说需要对指针的值进行修改。其实我刚才向类想Del方法虽然涉及删除,但是不使用指针引用貌似也完全可以。而Method函数则是必须使用指针引用的。因为每个递归函数,只负责本节点的数据处理,而单节点的来源只能来自于参数。这里的思想,我觉得有点类似于发派任务,函数调用后,只负责本节点的数据工作,对于子节点处理,仅有下级的递归函数处理。所以可以看到我的Method函数非常简单。

另外我的这段代码中,第一次的任务是由非递归函数处理的,算是,使用递归函数引导函数吧,通过引导函数,完成第一次的较为特殊的处理后,再由递归函数完成后面的重复性操作。

当然,如果我类中参数定义为指针而不是一个结构体对象,那么直接使用递归函数开始处理也是完全可以的。

还是上不了外网,连QQ截图都没法用,所以,我又把树的分层遍历写了~

刚才看室友们玩逆战的塔防局,他们有个高手带着,一晚上连续通关两次,不过这也是他们从上个学期开始玩逆战到现在唯二的两次通管局,以往都是最后一关失败。但是现在有大腿抱着就是不一样啊。

刚才写的分层遍历代码形式上和前两天发的那个图的遍历思路是一样的,都是通过使用栈来实现分层遍历。不过,我做的这个分层遍历找不到每一层的边界。所以是一起打出来的。但是根据输入能够判断出,确实实现了分层遍历。

贴下树遍历的截图,分别前中后,以及分层遍历。输入是以前序的方式输入的。

最后依旧附上二叉树的全部代码:

  1. #include <iostream>
  2. #include <queue>
  3.  
  4. using namespace std;
  5. class BinaryNode
  6. {
  7. //定义为class比较好,有利于函数扩充
  8. public:
  9. BinaryNode();
  10. char m_val;//暂定为字符,代码简单
  11. BinaryNode * pLeftNode;
  12. BinaryNode * pRightNode;
  13. };
  14. BinaryNode::BinaryNode():m_val(), pLeftNode(NULL), pRightNode(NULL)
  15. {
  16. ;
  17. }
  18. class CBinaryTree
  19. {
  20. private:
  21. BinaryNode m_Root;
  22. void Method(BinaryNode * & pNode);//递归函数
  23. void Del(BinaryNode * & pNode);
  24. void FS(BinaryNode * pNode);
  25. void MS(BinaryNode * pNode);
  26. void BS(BinaryNode * pNode);
  27. public:
  28. CBinaryTree();
  29. ~CBinaryTree();
  30. void InputTree();
  31. void Search(int nMode = );
  32. void LevelSearch();//分层遍历
  33. };
  34.  
  35. CBinaryTree::CBinaryTree()
  36. {
  37. ;//nothing
  38. }
  39.  
  40. CBinaryTree::~CBinaryTree()
  41. {
  42. if(m_Root.m_val == )
  43. return;
  44. if(m_Root.pLeftNode != NULL)
  45. Del(m_Root.pLeftNode);
  46. if(m_Root.pLeftNode != NULL)
  47. Del(m_Root.pRightNode);
  48. }
  49.  
  50. void CBinaryTree::InputTree()
  51. {
  52. char val = ;
  53. cin >> val;
  54. if(val == '#')
  55. {
  56. return;
  57. }
  58. else
  59. {
  60. m_Root.m_val = val;
  61. Method(m_Root.pLeftNode);
  62. Method(m_Root.pRightNode);
  63. }
  64. }
  65.  
  66. void CBinaryTree::Del(BinaryNode * & pNode)
  67. {
  68. if(pNode->pLeftNode != NULL)
  69. Del(pNode->pLeftNode);
  70. if(pNode->pRightNode != NULL)
  71. Del(pNode->pRightNode);
  72. delete pNode;
  73. }
  74.  
  75. void CBinaryTree::Method(BinaryNode * & pNode)
  76. {
  77. char val = ;
  78. cin >> val;
  79. if(val != '#')
  80. {
  81. pNode = new BinaryNode;
  82. pNode->m_val = val;
  83. Method(pNode->pLeftNode);
  84. Method(pNode->pRightNode);
  85. }
  86. else
  87. {
  88. pNode = NULL;
  89. }
  90. }
  91.  
  92. void CBinaryTree::FS(BinaryNode * pNode)
  93. {
  94. cout << pNode->m_val;
  95. if(NULL != pNode->pLeftNode)
  96. FS(pNode->pLeftNode);
  97. if(NULL != pNode->pRightNode)
  98. FS(pNode->pRightNode);
  99. }
  100.  
  101. void CBinaryTree::MS(BinaryNode * pNode)
  102. {
  103. if(NULL != pNode->pLeftNode)
  104. MS(pNode->pLeftNode);
  105. cout << pNode->m_val;
  106. if(NULL != pNode->pRightNode)
  107. MS(pNode->pRightNode);
  108. }
  109.  
  110. void CBinaryTree::BS(BinaryNode * pNode)
  111. {
  112. if(NULL != pNode->pLeftNode)
  113. BS(pNode->pLeftNode);
  114. if(NULL != pNode->pRightNode)
  115. BS(pNode->pRightNode);
  116. cout << pNode->m_val;
  117. }
  118.  
  119. void CBinaryTree::Search(int nMode)
  120. {
  121. if( == m_Root.m_val)
  122. {
  123. return;
  124. }
  125. switch(nMode)
  126. {
  127. case :
  128. cout << m_Root.m_val;
  129. if(NULL != m_Root.pLeftNode)
  130. FS(m_Root.pLeftNode);
  131. if(NULL != m_Root.pRightNode)
  132. FS(m_Root.pRightNode);
  133. break;
  134. case :
  135. if(NULL != m_Root.pLeftNode)
  136. MS(m_Root.pLeftNode);
  137. cout << m_Root.m_val;
  138. if(NULL != m_Root.pRightNode)
  139. MS(m_Root.pRightNode);
  140. break;
  141. case :
  142. if(NULL != m_Root.pLeftNode)
  143. BS(m_Root.pLeftNode);
  144. if(NULL != m_Root.pRightNode)
  145. BS(m_Root.pRightNode);
  146. cout << m_Root.m_val;
  147. break;
  148. }
  149.  
  150. }
  151.  
  152. void CBinaryTree::LevelSearch()
  153. {
  154. queue<BinaryNode> qBN;
  155. //cout << m_Root.m_val << endl;
  156. qBN.push(m_Root);
  157. while(!qBN.empty())
  158. {
  159. cout << qBN.front().m_val;
  160. if(NULL != qBN.front().pLeftNode)
  161. qBN.push(*qBN.front().pLeftNode);
  162. if(NULL != qBN.front().pRightNode)
  163. qBN.push(*qBN.front().pRightNode);
  164. qBN.pop();
  165. }
  166. }
  167.  
  168. int main()
  169. {
  170. cout << "Hello world!" << endl;
  171. CBinaryTree tree;
  172. tree.InputTree();
  173. tree.Search();
  174. cout << endl;
  175. tree.Search();
  176. cout << endl;
  177. tree.Search();
  178. cout << endl;
  179. tree.LevelSearch();
  180. return ;
  181. }

C++ const && 二叉树合集的更多相关文章

  1. [题解+总结]NOIP动态规划大合集

    1.前言 NOIP2003-2014动态规划题目大合集,有简单的也有难的(对于我这种动态规划盲当然存在难的),今天就把这些东西归纳一下,做一个比较全面的总结,方便对动态规划有一个更深的理解. 2.NO ...

  2. C# 调用windows api 操作鼠标、键盘、窗体合集...更新中

    鼠标操作window窗体合集...更新中 1.根据句柄查找窗体 引自http://www.2cto.com/kf/201410/343342.html 使用SPY++工具获取窗体   首先打开spy+ ...

  3. dp合集 广场铺砖问题&&硬木地板

    dp合集 广场铺砖问题&&硬木地板 很经典了吧... 前排:思想来自yali朱全民dalao的ppt百度文库免费下载 后排:STO朱全民OTZ 广场铺砖问题 有一个 W 行 H 列的广 ...

  4. 9.15 DP合集水表

    9.15 DP合集水表 显然难了一些啊. 凸多边形的三角剖分 瞄了一眼题解. 和蛤蛤的烦恼一样,裸的区间dp. 设f[i][j]表示i~j的点三角剖分最小代价. 显然\(f[i][i+1]=0,f[i ...

  5. 9.14 DP合集水表

    9.14 DP合集水表 关键子工程 在大型工程的施工前,我们把整个工程划分为若干个子工程,并把这些子工程编号为 1. 2. --. N:这样划分之后,子工程之间就会有一些依赖关系,即一些子工程必须在某 ...

  6. es6常用基础合集

    es6常用基础合集 在实际开发中,ES6已经非常普及了.掌握ES6的知识变成了一种必须.尽管我们在使用时仍然需要经过babel编译. ES6彻底改变了前端的编码风格,可以说对于前端的影响非常巨大.值得 ...

  7. DP+贪心水题合集_C++

    本文含有原创题,涉及版权利益问题,严禁转载,违者追究法律责任 本次是最后一篇免费的考试题解,以后的考试题目以及题解将会以付费的方式阅读,题目质量可以拿本次作为参考 本来半个月前就已经搞得差不多了,然后 ...

  8. 学渣乱搞系列之Tarjan模板合集

    学渣乱搞系列之Tarjan模板合集 by 狂徒归来 一.求强连通子图 #include <iostream> #include <cstdio> #include <cs ...

  9. NOIP动态规划大合集

    1.前言 NOIP2003-2014动态规划题目大合集,有简单的也有难的(对于我这种动态规划盲当然存在难的),今天就把这些东西归纳一下,做一个比较全面的总结,方便对动态规划有一个更深的理解. 2.NO ...

随机推荐

  1. 使用AzCopy跨账户迁移blob

    昨天北美紧急通知要停掉几个开发和测试的订阅,当天必须完成,因为事情比较多,搞得有点我措手不及,但是唯一的遗憾是Azure VM. 因为在上面做了很多东西,很多资料和环境都是做好的,如果被删除掉实在可惜 ...

  2. 最全的CMD命令

    CMD命令:开始->运行->键入cmd或command(在命令行里可以看到系统版本.文件系统版本) . appwiz.cpl:程序和功能 . calc:启动计算器 . certmgr.ms ...

  3. shadowmap 及优化

    对于子阴影的走样, 条纹 开zbias resterizeState zbias = 1000...大概这样 另一个方法是画背面 backface是指一个人肚子那面,后背那面 而不是肚子的里面那层 所 ...

  4. sampleGradient(sampler,uv,dds,ddy)

    vsm里面用这个梯度采样 采放了z,z*z的shadowmap 这种采样方式和普通sample有什么区别

  5. PIX的使用

    这几天pix的一个问题可坑死我了,之前用的时候有蓝色的链接,点过去就可以查看相应资源,后来都是黑色的了没有可以点的链接. 看文档翻来翻去也没进展,后来找到了, 先打开render那个窗口 这样even ...

  6. Js高程笔记->引用类型

    1 . Object 对象    2 . Array 对象 :       检测方法:ES5 : isArray       转换方法: toLocaleString , toString , val ...

  7. [geeksforgeeks] Convert a given Binary Tree to Doubly Linked List

    http://www.geeksforgeeks.org/in-place-convert-a-given-binary-tree-to-doubly-linked-list/ Given a Bin ...

  8. volatile关键字的使用

    (简要概括:volatile变量有两个作用:一个是告诉编译器不要进行优化:另一个是告诉系统始终从内存中取变量的地址,而不是从缓存中取变量的值) 一.前言 1.编译器优化介绍: 由于内存访问速度远不及C ...

  9. SEO优化的黑帽手法是否值得使用?

    PR劫持 可能很多人也会听到说,什么网站权重越高越好,这也就是后面越来越多人都对谷歌的PR的宣传看的很重,自建站的都追求PR值,权重越高代表这个网站越受信任. 比如一个新站PR值为0,一个老站PR为6 ...

  10. HDU 4588 Count The Carries(找规律,模拟)

    题目 大意: 求二进制的a加到b的进位数. 思路: 列出前几个2进制,找规律模拟. #include <stdio.h> #include <iostream> #includ ...