二叉树的前序、中序、后序遍历

来源:互联网 发布:java getservername 编辑:程序博客网 时间:2024/05/09 06:28

树形结构是一类重要的非线性数据结构,其中以树和二叉树最为常用。

二叉树是每个结点最多有两个子树的有序树。通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用作二叉查找树和二叉堆或是二叉排序树。二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2的 i -1次方个结点;深度为k的二叉树至多有2^(k) -1个结点;对任何一棵二叉树T,如果其终端结点数(即叶子结点数)为n0,度为2的结点数为n2,则n0 = n2 + 1。

二叉树的链式存储结构是一类重要的数据结构,其形式定义如下:

[cpp] view plaincopy
  1. //二叉树结点  
  2. typedef struct BiTNode{  
  3.     //数据  
  4.     char data;  
  5.     //左右孩子指针  
  6.     struct BiTNode *lchild,*rchild;  
  7. }BiTNode,*BiTree;  


二叉树的创建:

通过读入一个字符串,建立二叉树的算法如下:

[cpp] view plaincopy
  1. //按先序序列创建二叉树  
  2. int CreateBiTree(BiTree &T){  
  3.     char data;  
  4.     //按先序次序输入二叉树中结点的值(一个字符),‘#’表示空树  
  5.     scanf("%c",&data);  
  6.     if(data == '#'){  
  7.         T = NULL;  
  8.     }  
  9.     else{  
  10.         T = (BiTree)malloc(sizeof(BiTNode));  
  11.         //生成根结点  
  12.         T->data = data;  
  13.         //构造左子树  
  14.         CreateBiTree(T->lchild);  
  15.         //构造右子树  
  16.         CreateBiTree(T->rchild);  
  17.     }  
  18.     return 0;  
  19. }  

二叉树的遍历:

遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。

递归算法:

[cpp] view plaincopy
  1. //输出  
  2. void Visit(BiTree T){  
  3.     if(T->data != '#'){  
  4.         printf("%c ",T->data);  
  5.     }  
  6. }  
  7. //先序遍历  
  8. void PreOrder(BiTree T){  
  9.     if(T != NULL){  
  10.         //访问根节点  
  11.         Visit(T);  
  12.         //访问左子结点  
  13.         PreOrder(T->lchild);  
  14.         //访问右子结点  
  15.         PreOrder(T->rchild);  
  16.     }  
  17. }  
  18. //中序遍历  
  19. void InOrder(BiTree T){  
  20.     if(T != NULL){  
  21.         //访问左子结点  
  22.         InOrder(T->lchild);  
  23.         //访问根节点  
  24.         Visit(T);  
  25.         //访问右子结点  
  26.         InOrder(T->rchild);  
  27.     }  
  28. }  
  29. //后序遍历  
  30. void PostOrder(BiTree T){  
  31.     if(T != NULL){  
  32.         //访问左子结点  
  33.         PostOrder(T->lchild);  
  34.         //访问右子结点  
  35.         PostOrder(T->rchild);  
  36.         //访问根节点  
  37.         Visit(T);  
  38.     }  
  39. }  

非递归算法:

<1>先序遍历:

【思路】:访问T->data后,将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,再先序遍历T的右子树。

[cpp] view plaincopy
  1. /* 先序遍历(非递归) 
  2.    思路:访问T->data后,将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,再先序遍历T的右子树。 
  3. */  
  4. void PreOrder2(BiTree T){  
  5.     stack<BiTree> stack;  
  6.     //p是遍历指针  
  7.     BiTree p = T;  
  8.     //栈不空或者p不空时循环  
  9.     while(p || !stack.empty()){  
  10.         if(p != NULL){  
  11.             //存入栈中  
  12.             stack.push(p);  
  13.             //访问根节点  
  14.             printf("%c ",p->data);  
  15.             //遍历左子树  
  16.             p = p->lchild;  
  17.         }  
  18.         else{  
  19.             //退栈  
  20.             p = stack.top();  
  21.             stack.pop();  
  22.             //访问右子树  
  23.             p = p->rchild;  
  24.         }  
  25.     }//while  
  26. }  


<2>中序遍历

【思路】:T是要遍历树的根指针,中序遍历要求在遍历完左子树后,访问根,再遍历右子树。
         先将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,访问T->data,再中序遍历T的右子树。

[cpp] view plaincopy
  1. void InOrder2(BiTree T){  
  2.     stack<BiTree> stack;  
  3.     //p是遍历指针  
  4.     BiTree p = T;  
  5.     //栈不空或者p不空时循环  
  6.     while(p || !stack.empty()){  
  7.         if(p != NULL){  
  8.             //存入栈中  
  9.             stack.push(p);  
  10.             //遍历左子树  
  11.             p = p->lchild;  
  12.         }  
  13.         else{  
  14.             //退栈,访问根节点  
  15.             p = stack.top();  
  16.             printf("%c ",p->data);  
  17.             stack.pop();  
  18.             //访问右子树  
  19.             p = p->rchild;  
  20.         }  
  21.     }//while  
  22. }  

<3>后序遍历

【思路】:T是要遍历树的根指针,后序遍历要求在遍历完左右子树后,再访问根。需要判断根结点的左右子树是否均遍历过。

[cpp] view plaincopy
  1. //后序遍历(非递归)  
  2. typedef struct BiTNodePost{  
  3.     BiTree biTree;  
  4.     char tag;  
  5. }BiTNodePost,*BiTreePost;  
  6.   
  7. void PostOrder2(BiTree T){  
  8.     stack<BiTreePost> stack;  
  9.     //p是遍历指针  
  10.     BiTree p = T;  
  11.     BiTreePost BT;  
  12.     //栈不空或者p不空时循环  
  13.     while(p != NULL || !stack.empty()){  
  14.         //遍历左子树  
  15.         while(p != NULL){  
  16.             BT = (BiTreePost)malloc(sizeof(BiTNodePost));  
  17.             BT->biTree = p;  
  18.             //访问过左子树  
  19.             BT->tag = 'L';  
  20.             stack.push(BT);  
  21.             p = p->lchild;  
  22.         }  
  23.         //左右子树访问完毕访问根节点  
  24.         while(!stack.empty() && (stack.top())->tag == 'R'){  
  25.             BT = stack.top();  
  26.             //退栈  
  27.             stack.pop();  
  28.             BT->biTree;  
  29.             printf("%c ",BT->biTree->data);  
  30.         }  
  31.         //遍历右子树  
  32.         if(!stack.empty()){  
  33.             BT = stack.top();  
  34.             //访问过右子树  
  35.             BT->tag = 'R';  
  36.             p = BT->biTree;  
  37.             p = p->rchild;  
  38.         }  
  39.     }//while  
  40. }  


<4>层次遍历

【思路】:按从顶向下,从左至右的顺序来逐层访问每个节点,层次遍历的过程中需要用队列。

[cpp] view plaincopy
  1. //层次遍历  
  2. void LevelOrder(BiTree T){  
  3.     BiTree p = T;  
  4.     //队列  
  5.     queue<BiTree> queue;  
  6.     //根节点入队  
  7.     queue.push(p);  
  8.     //队列不空循环  
  9.     while(!queue.empty()){  
  10.         //对头元素出队  
  11.         p = queue.front();  
  12.         //访问p指向的结点  
  13.         printf("%c ",p->data);  
  14.         //退出队列  
  15.         queue.pop();  
  16.         //左子树不空,将左子树入队  
  17.         if(p->lchild != NULL){  
  18.             queue.push(p->lchild);  
  19.         }  
  20.         //右子树不空,将右子树入队  
  21.         if(p->rchild != NULL){  
  22.             queue.push(p->rchild);  
  23.         }  
  24.     }  
  25. }  


测试用例:


输入:

ABC##DE#G##F###

输出:


代码:

[cpp] view plaincopy
  1. #include<iostream>  
  2. #include<stack>  
  3. #include<queue>  
  4. using namespace std;  
  5.   
  6. //二叉树结点  
  7. typedef struct BiTNode{  
  8.     //数据  
  9.     char data;  
  10.     //左右孩子指针  
  11.     struct BiTNode *lchild,*rchild;  
  12. }BiTNode,*BiTree;  
  13.   
  14. //按先序序列创建二叉树  
  15. int CreateBiTree(BiTree &T){  
  16.     char data;  
  17.     //按先序次序输入二叉树中结点的值(一个字符),‘#’表示空树  
  18.     scanf("%c",&data);  
  19.     if(data == '#'){  
  20.         T = NULL;  
  21.     }  
  22.     else{  
  23.         T = (BiTree)malloc(sizeof(BiTNode));  
  24.         //生成根结点  
  25.         T->data = data;  
  26.         //构造左子树  
  27.         CreateBiTree(T->lchild);  
  28.         //构造右子树  
  29.         CreateBiTree(T->rchild);  
  30.     }  
  31.     return 0;  
  32. }  
  33. //输出  
  34. void Visit(BiTree T){  
  35.     if(T->data != '#'){  
  36.         printf("%c ",T->data);  
  37.     }  
  38. }  
  39. //先序遍历  
  40. void PreOrder(BiTree T){  
  41.     if(T != NULL){  
  42.         //访问根节点  
  43.         Visit(T);  
  44.         //访问左子结点  
  45.         PreOrder(T->lchild);  
  46.         //访问右子结点  
  47.         PreOrder(T->rchild);  
  48.     }  
  49. }  
  50. //中序遍历    
  51. void InOrder(BiTree T){    
  52.     if(T != NULL){    
  53.         //访问左子结点    
  54.         InOrder(T->lchild);    
  55.         //访问根节点    
  56.         Visit(T);    
  57.         //访问右子结点    
  58.         InOrder(T->rchild);    
  59.     }    
  60. }    
  61. //后序遍历  
  62. void PostOrder(BiTree T){  
  63.     if(T != NULL){  
  64.         //访问左子结点  
  65.         PostOrder(T->lchild);  
  66.         //访问右子结点  
  67.         PostOrder(T->rchild);  
  68.         //访问根节点  
  69.         Visit(T);  
  70.     }  
  71. }  
  72. /* 先序遍历(非递归) 
  73.    思路:访问T->data后,将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,再先序遍历T的右子树。 
  74. */  
  75. void PreOrder2(BiTree T){  
  76.     stack<BiTree> stack;  
  77.     //p是遍历指针  
  78.     BiTree p = T;  
  79.     //栈不空或者p不空时循环  
  80.     while(p || !stack.empty()){  
  81.         if(p != NULL){  
  82.             //存入栈中  
  83.             stack.push(p);  
  84.             //访问根节点  
  85.             printf("%c ",p->data);  
  86.             //遍历左子树  
  87.             p = p->lchild;  
  88.         }  
  89.         else{  
  90.             //退栈  
  91.             p = stack.top();  
  92.             stack.pop();  
  93.             //访问右子树  
  94.             p = p->rchild;  
  95.         }  
  96.     }//while  
  97. }  
  98. /* 中序遍历(非递归) 
  99.    思路:T是要遍历树的根指针,中序遍历要求在遍历完左子树后,访问根,再遍历右子树。 
  100.          先将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,访问T->data,再中序遍历T的右子树。 
  101. */  
  102. void InOrder2(BiTree T){  
  103.     stack<BiTree> stack;  
  104.     //p是遍历指针  
  105.     BiTree p = T;  
  106.     //栈不空或者p不空时循环  
  107.     while(p || !stack.empty()){  
  108.         if(p != NULL){  
  109.             //存入栈中  
  110.             stack.push(p);  
  111.             //遍历左子树  
  112.             p = p->lchild;  
  113.         }  
  114.         else{  
  115.             //退栈,访问根节点  
  116.             p = stack.top();  
  117.             printf("%c ",p->data);  
  118.             stack.pop();  
  119.             //访问右子树  
  120.             p = p->rchild;  
  121.         }  
  122.     }//while  
  123. }  
  124.   
  125. //后序遍历(非递归)  
  126. typedef struct BiTNodePost{  
  127.     BiTree biTree;  
  128.     char tag;  
  129. }BiTNodePost,*BiTreePost;  
  130.   
  131. void PostOrder2(BiTree T){  
  132.     stack<BiTreePost> stack;  
  133.     //p是遍历指针  
  134.     BiTree p = T;  
  135.     BiTreePost BT;  
  136.     //栈不空或者p不空时循环  
  137.     while(p != NULL || !stack.empty()){  
  138.         //遍历左子树  
  139.         while(p != NULL){  
  140.             BT = (BiTreePost)malloc(sizeof(BiTNodePost));  
  141.             BT->biTree = p;  
  142.             //访问过左子树  
  143.             BT->tag = 'L';  
  144.             stack.push(BT);  
  145.             p = p->lchild;  
  146.         }  
  147.         //左右子树访问完毕访问根节点  
  148.         while(!stack.empty() && (stack.top())->tag == 'R'){  
  149.             BT = stack.top();  
  150.             //退栈  
  151.             stack.pop();  
  152.             BT->biTree;  
  153.             printf("%c ",BT->biTree->data);  
  154.         }  
  155.         //遍历右子树  
  156.         if(!stack.empty()){  
  157.             BT = stack.top();  
  158.             //访问过右子树  
  159.             BT->tag = 'R';  
  160.             p = BT->biTree;  
  161.             p = p->rchild;  
  162.         }  
  163.     }//while  
  164. }  
  165. //层次遍历  
  166. void LevelOrder(BiTree T){  
  167.     BiTree p = T;  
  168.     //队列  
  169.     queue<BiTree> queue;  
  170.     //根节点入队  
  171.     queue.push(p);  
  172.     //队列不空循环  
  173.     while(!queue.empty()){  
  174.         //对头元素出队  
  175.         p = queue.front();  
  176.         //访问p指向的结点  
  177.         printf("%c ",p->data);  
  178.         //退出队列  
  179.         queue.pop();  
  180.         //左子树不空,将左子树入队  
  181.         if(p->lchild != NULL){  
  182.             queue.push(p->lchild);  
  183.         }  
  184.         //右子树不空,将右子树入队  
  185.         if(p->rchild != NULL){  
  186.             queue.push(p->rchild);  
  187.         }  
  188.     }  
  189. }  
  190. int main()  
  191. {  
  192.     BiTree T;  
  193.     CreateBiTree(T);  
  194.     printf("先序遍历:\n");  
  195.     PreOrder(T);  
  196.     printf("\n");  
  197.     printf("先序遍历(非递归):\n");  
  198.     PreOrder2(T);  
  199.     printf("\n");  
  200.     printf("中序遍历:\n");  
  201.     InOrder(T);  
  202.     printf("\n");  
  203.     printf("中序遍历(非递归):\n");  
  204.     InOrder2(T);  
  205.     printf("\n");  
  206.     printf("后序遍历:\n");  
  207.     PostOrder(T);  
  208.     printf("\n");  
  209.     printf("后序遍历(非递归):\n");  
  210.     PostOrder2(T);  
  211.     printf("\n");  
  212.     printf("层次遍历:\n");  
  213.     LevelOrder(T);  
  214.     printf("\n");  
  215.     return 0;  
  216. }  
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 面对诋毁我的人怎么办 做事太细致速度太慢怎么办 高一儿子早恋了怎么办 儿子18岁谈朋友怎么办 和朋友为钱吵架怎么办 感情里总担心失去怎么办 眼石移出盲僧怎么办 打仗把小便踢肿了怎么办 腿上都是挠的疤怎么办 脚上的肉烂了怎么办 商铺门口有电杆怎么办 漏电保护器坏了怎么办 空开进线烧了怎么办 过压保护灯亮怎么办 美的热水器接地异常怎么办 欠压保护器坏了怎么办 三孔插座没地线怎么办 二胡琴筒裂缝宽怎么办 有了月亮从四星宠满级的怎么办 党委下属没有党支部了党委怎么办 发生日期大于制单日期怎么办 美的空调出现p0怎么办 薯片受潮不脆了怎么办 泡过的莲子煮不烂怎么办 绿豆有煮不熟的怎么办 吃了羊肉吃西瓜怎么办 吃了狗肉和绿豆怎么办 做的衣柜没有门怎么办 蒸馒头熟了会瘪怎么办 3dmax贴图太大了怎么办 嘴皮边缘颜色深怎么办 嘴巴周围肤色暗沉怎么办 中奖彩票被洗了怎么办 牙龈下面长米粒肉疙瘩怎么办 书画印章盖反了怎么办 金龙鱼一个月不吃东西怎么办 罗汉鱼头撞扁了怎么办 房顶开槽埋线白色不一样怎么办 顶上灯挪位置线怎么办 马蜂窝弄掉又来怎么办 蜂窝弄掉又有怎么办