我强大的二叉树(先序、层序创建,先序、中序、后序、层序遍历)

 要赶快些,要不然我们寝室就要断电了!
 好了,经过四天的艰苦奋斗,我终于完成了一个比较强大的东西了。是什么东西呢?不是什么软件,不是什么程序,而是我自定义的一个数据结构!这个数据结构是二叉树。这个二叉树课不简单,因为它可以进行先序建立、层序建立,并且能够支持先序、中序、后序、层序的遍历。这个数据结构是我这四天来最有成果的一个了。因此我花费了超过24小时。想想自己在上课、吃饭、睡觉、上厕所都在想这个数据结构。能够有这个东西的横空出世,对我来说可真是可喜可贺啊。
 今天晚上一直在研究层序创建二叉树的问题。昨天研究的是层序遍历二叉树的问题,因此我自己创建了一个链式队列(详见http://student.csdn.net/space.php?uid=999749&do=blog&id=48348)。有了这个队列,我就可以顺利地使用队列来进行层序遍历了。层序遍历的基本思想是:首先把根节点压入队尾,然后判断是否队列为空。如果为空,则退出循环。(当然没有出队的元素队伍是不会为空的)随后在循环体内进行出队操作,然后调用目标函数,再对左右孩子进行插入队尾的操作。如此循环,知道队列为空为之。这样的效果还真的不错。有了队列这个数据结构,我只需要几条语句就可以搞定层序遍历。
 但是层序建立二叉树就没有那么简单了。其原因比较复杂,不好言传。但是今天晚上在我的努力下终于完成了。下面就是我为了编写这个功能而写的伪代码:

Code:
  1. 若根为空,则创建根节点。   
  2. 将根节点进队,   
  3. 如果队未空,则进入循环:   
  4. {   
  5.  删除队首元素,并取出来,   
  6.  填充队首元素,   
  7.  若左孩子满足条件,则创建左孩子,并且进队,   
  8.  若右孩子满足条件,则创建右孩子,并且进队,   
  9. }  

 

 说得简单,但是实现起来可是非常的困难的。我一遍又一遍地调试程序,到了现在,这个程序终于成功了。下面是我这个庞大二叉树的代码:

Code:
  1. /*-------------------------------------------  
  2. 蒋轶民制作:E-mail:jiangcaiyang123@163.com  
  3. ---------------------------------------------  
  4. 文件名:JBiTree.h  
  5. ---------------------------------------------  
  6. 作用:这是一种二叉树的模板,它可以应用于任何  
  7. 的需要二叉树的非线性结构的程序中。  
  8. ---------------------------------------------  
  9. 调用规范:①若将任意的类型运用于此,必须重载  
  10. ==运算符,因为在判断两个数据类型的对象是否相  
  11. 等的时候必须要用到它。②使用之前必须先定义类  
  12. 型再包含该文件。例如:  
  13. typedef struct  
  14. {  
  15. char a  
  16. int b;  
  17. unsigned long c;  
  18. };  
  19. #include"JBiTree.h"  
  20. ③若用char类型进行实例化,那么给形参sizeofObj  
  21. 传入的值必须减一。因为字符串是带'/0'的。  
  22. ④具体函数的参数说明:  
  23. void SetImportData( CustomType* importObj,   
  24. int sizeofObj, CustomType defaultObj );  
  25. importObj:导入数据数组的首地址  
  26. sizeofObj:数据数组的总大小,通常是sizeof(..)  
  27. defaultObj:默认忽略建立树的结构数据  
  28.  
  29. bool CreateJBiTreeByPreOrder( JBiTreeNode  
  30. <CustomType>* current );  
  31. current:当前传入的数据节点,通常是GetRoot()  
  32. 相同参数的函数:  
  33. CreateJBiTreeByLevelOrder()  
  34.  
  35. void PreOrderTraverse(   
  36. JBiTreeNode<CustomType>* current,  
  37. bool (*Visit)(CustomType e) );  
  38. current:当前传入的数据节点,通常是GetRoot()  
  39. Visit:具体的应用函数形参  
  40. 相同参数的函数:  
  41. InOrderTraverse()  
  42. PostOrderTraverse()  
  43. LevelOrderTraverse() 
  44. ⑤在建立二叉树的时候,必须设置导入数据,不然会出错。// 更新于11月13日
  45. -------------------------------------------*/  
  46. #ifndef _JBITREE_H_   
  47. #define _JBITREE_H_   
  48.   
  49. #include "JChainQueue.h"   
  50.   
  51. // 可将任何类型应用于此   
  52. template <typename CustomType>    
  53. struct JBiTreeNode// 二叉树节点结构体(三叉节点)   
  54. {   
  55.  JBiTreeNode():lchild(0), rchild(0){}   
  56.  CustomType elem;   
  57.  JBiTreeNode *lchild, *rchild;   
  58. };// JBiTreeNode   
  59.   
  60. // 可将任何类型应用于此   
  61. template <typename CustomType>    
  62. class JBiTree// 二叉树类   
  63. {   
  64. public:   
  65.  JBiTree():root(0), importData(0), startData(0), nodeCount(0){}// 默认构造函数   
  66.  ~JBiTree(){}// 默认析构函数   
  67.  void SetImportData( CustomType* importObj, int sizeofObj, CustomType defaultObj );// 设置导入的数据   
  68.  JBiTreeNode<CustomType>* GetRoot( void );// 获取根节点   
  69.  bool CreateJBiTreeByPreOrder( JBiTreeNode<CustomType>* current );// 先序创建二叉树   
  70.  bool CreateJBiTreeByLevelOrder( JBiTreeNode<CustomType>* current );// 层序创建二叉树   
  71.  void PreOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e) );// 先序遍历二叉树   
  72.  void InOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e ) );// 中序遍历二叉树   
  73.  void PostOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e ) );// 后序遍历二叉树   
  74.  void LevelOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e ) );// 层序遍历二叉树   
  75. private:   
  76.  JBiTreeNode<CustomType>* root;   
  77.  CustomType* importData, *startData;   
  78.  CustomType defaultData;   
  79.  int nodeCount;   
  80. };   
  81.   
  82. // 设置导入的数据   
  83. template <typename CustomType>   
  84. void JBiTree<CustomType>::SetImportData( CustomType importObj[], int sizeofObj, CustomType defaultObj)   
  85. {   
  86.  startData = importData = importObj;   
  87.  nodeCount = sizeofObj / sizeof( CustomType );   
  88.  defaultData = defaultObj;   
  89. }   
  90.   
  91. // 获取根节点   
  92. template <typename CustomType>   
  93. JBiTreeNode<CustomType>* JBiTree<CustomType>::GetRoot( void )   
  94. {   
  95.  return root;   
  96. }   
  97.   
  98.   
  99. // 层序创建二叉树   
  100. template <typename CustomType>   
  101. bool JBiTree<CustomType>::CreateJBiTreeByLevelOrder( JBiTreeNode<CustomType>* current )   
  102. {   
  103.  JChainQueue<JBiTreeNode<CustomType>*> temp;   
  104.  CustomType* dataTraverse = importData + 1;// 声明一个遍历的指针,从第二个元素开始   
  105.   
  106.  if ( importData == startData + nodeCount || *importData == defaultData )   
  107.   return false;// 若输入数据区为空且头结点为空则返回错误,因为不能创建树   
  108.  if ( current == root )// 若当前为根节点则创建根节点   
  109.  {   
  110.   root = new JBiTreeNode<CustomType>;   
  111.   current = root;   
  112.  } else return false;   
  113.  temp.EnterQueue( current );   
  114.  while ( !temp.IsEmpty() )   
  115.  {   
  116.   current = temp.DeleteQueue();   
  117.   while ( *importData == defaultData )   
  118.    importData++;   
  119.   current->elem = *importData;   
  120.   importData++;   
  121.   if ( dataTraverse != startData + nodeCount )   
  122.   {   
  123.    if ( *dataTraverse != defaultData )   
  124.     temp.EnterQueue( current->lchild = new JBiTreeNode<CustomType> );   
  125.    dataTraverse++;   
  126.   }   
  127.   if ( dataTraverse != startData + nodeCount )   
  128.   {   
  129.    if ( *dataTraverse != defaultData )   
  130.     temp.EnterQueue( current->rchild = new JBiTreeNode<CustomType> );   
  131.    dataTraverse++;   
  132.   }   
  133.  }   
  134.  return true;   
  135. }   
  136. // 先序遍历二叉树   
  137. template <typename CustomType>   
  138. void JBiTree<CustomType>::PreOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e) )   
  139. {   
  140.  if ( current )   
  141.  {   
  142.   (*Visit)( current->elem );   
  143.   PreOrderTraverse( current->lchild, Visit );   
  144.   PreOrderTraverse( current->rchild, Visit );   
  145.  }   
  146. }   
  147.   
  148. // 中序遍历二叉树   
  149. template <typename CustomType>   
  150. void JBiTree<CustomType>::InOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e ) )   
  151. {   
  152.  if ( current )   
  153.  {   
  154.   InOrderTraverse( current->lchild, Visit );   
  155.   (*Visit)( current->elem );   
  156.   InOrderTraverse( current->rchild, Visit );   
  157.  }   
  158. }   
  159. // 后序遍历二叉树   
  160. template <typename CustomType>   
  161. void JBiTree<CustomType>::PostOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e ) )   
  162. {   
  163.  if ( current )   
  164.  {   
  165.   PostOrderTraverse( current->lchild, Visit );   
  166.   PostOrderTraverse( current->rchild, Visit );   
  167.   (*Visit)( current->elem );   
  168.  }   
  169. }   
  170. // 层序遍历二叉树   
  171. template <typename CustomType>   
  172. void JBiTree<CustomType>::LevelOrderTraverse( JBiTreeNode<CustomType>* current, bool (*Visit)(CustomType e ) )   
  173. {   
  174.  JChainQueue<JBiTreeNode<CustomType>*> temp;   
  175.  if ( current == 0 ) return;// 当前节点为空则返回   
  176.  temp.EnterQueue( current );// 将根节点入队列   
  177.  while ( !temp.IsEmpty() )   
  178.  {   
  179.   current = temp.DeleteQueue();   
  180.   (*Visit)( current->elem );   
  181.   if ( current->lchild ) temp.EnterQueue( current->lchild );   
  182.   if ( current->rchild ) temp.EnterQueue( current->rchild );   
  183.  }   
  184. }   
  185. // 先序创建二叉树   
  186. template <typename CustomType>   
  187. bool JBiTree<CustomType>::CreateJBiTreeByPreOrder( JBiTreeNode<CustomType>* current )   
  188. {   
  189.  if ( importData == startData + nodeCount || *importData == defaultData )   
  190.   return false;// 若输入数据区为空且头结点为空则返回错误,因为不能创建树   
  191.  if ( current == root )// 若当前为根节点则创建根节点   
  192.  {   
  193.   root = new JBiTreeNode<CustomType>;   
  194.   current = root;   
  195.  }   
  196.  current->elem = *importData;   
  197.  importData++;   
  198.  if ( importData != startData + nodeCount )   
  199.  {   
  200.   if ( *importData != defaultData )   
  201.   {   
  202.    current->lchild = new JBiTreeNode<CustomType>;   
  203.    CreateJBiTreeByPreOrder( current->lchild );   
  204.   }   
  205.   else importData++;   
  206.  }   
  207.  if ( importData != startData + nodeCount )   
  208.  {   
  209.   if ( *importData != defaultData )   
  210.   {   
  211.    current->rchild = new JBiTreeNode<CustomType>;   
  212.    CreateJBiTreeByPreOrder( current->rchild );   
  213.   }   
  214.   else importData++;   
  215.  }   
  216.  return true;   
  217. }   
  218. #endif  

 下面是我随便使用一个实例进行调用:

Code:
  1. #include<iostream>   
  2. #include"JBiTree.h"   
  3. using namespace std;   
  4. bool Display( char e )   
  5. {   
  6.  cout<<e;   
  7.  return true;   
  8. }   
  9.   
  10. int main( int argc, char** argv )   
  11. {   
  12.  JBiTree<char> jbtr;   
  13.  char dis[] = "124___3579____68AC__D__B___";   
  14.  //char dis[] = "1234_56";   
  15.  //char dis[] = "1245____36__7_89___";   
  16.  jbtr.SetImportData( dis, sizeof(dis)-1, '_' );   
  17.  //jbtr.CreateJBiTreeByLevelOrder( jbtr.GetRoot() );   
  18.  jbtr.CreateJBiTreeByPreOrder( jbtr.GetRoot() );   
  19.  jbtr.LevelOrderTraverse( jbtr.GetRoot(), Display );   
  20.  return 0;   
  21. }   
  22.   

 二叉树很有用。因为在游戏开发中有些图像的索引是BSP树,而BSP树就是二叉树的一种。这次写的二叉树不仅仅是加深对二叉树的理解,而且是对我后续游戏的开发也是非常有帮助的。我希望自己强大的二叉树能够派上用场。

 今天没有什么时间了,而且这个二叉树的模型还有诸多潜在的错误。希望大家能够将我的代码下载出来,并进行测试。并将错误反馈给我。我对大家的工作表示无尽的感谢。

更新于11月13日:大家难道没有发现吗?我的二叉树缺少了一个最重要的东西。销毁二叉树!如果不销毁的话,那么就会造成内存泄露这个重大的错误!这个东西我怎么会忘记呢!没办法,还是先这样吧。以后等我维护的时候再添加这个功能吧。现在先打记一下。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 37
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值