数据结构----二叉树的遍历

一.实验要求

    二叉树的遍历操作是树形结构其他众多操作的基础。本实验旨在使学生进一步加深对二叉树的先序、中序和后序等三种遍历次序特点的理解,熟悉二叉链表存储结构,熟练掌握二叉树上的递归算法的设计技术。


二.实验题目

    构造一棵二叉树,使用二叉链表方式存储,试设计程序,按照先序、中序、后序三种方式将这棵二叉树遍历出来,要求使用递归和非递归两种实现方式。 


三.实现提示

1.二叉树的线性链表存储数据结构

[cpp]  view plain  copy
  1. typedef char elemtype;  
  2.  typedef struct bitree{  
  3.  elemtype data;  
  4.  struct bitree *lchild,*rchild;  
  5.  }BiTree;  
  6.    

2.二叉树的构造方式(参考):

[cpp]  view plain  copy
  1. BiTree *create()  
  2. {     
  3. BiTree *q[100]; //定义q数组作为队列存放二叉链表中结点,100为最//大容量  
  4. BiTree *s; //二叉链表中的结点  
  5. BiTree *root ; //二叉链表的根指针  
  6. int front=1,rear=0; //定义队列的头、尾指针  
  7. char ch;    //结点的data域值  
  8. root=NULL;  
  9. cin>>ch;  
  10. while(ch!='#'//输入值为#号,算法结束  
  11. {   s=NULL;  
  12. if(ch!=','//输入数据不为逗号,表示不为虚结点,否则为虚结点  
  13. {   s=new BiTree;  
  14. s->data=ch;  
  15. s->lchild=NULL;  
  16. s->rchild=NULL;  
  17. }  
  18. rear++;  
  19. q[rear]=s; //新结点或虚结点进队  
  20. if(rear==1)  
  21. root=s;  
  22. else  
  23. {   if((s!=NULL)&&(q[front]!=NULL))  
  24. {   if(rear%2==0)  
  25. q[front]->lchild=s; //rear为偶数,s为双亲左孩子  
  26. else  
  27. q[front]->rchild=s;//rear为奇数,s为双亲右孩子  
  28. }  
  29. if(rear%2==1) front++;   //出队  
  30. }  
  31. cin>>ch;  
  32. }  
  33. return root;  
  34. }  


四.思考及选做

  1.本实验给出了建立二叉树的二叉链表存储结构的一种方法,是否还有更简单的方法?

  2.对于非递归先序遍历一般需要对每个结点进行二次进栈,这就需要一个标志位,如何处理这个标志位,使得既不需要构造新的存储结构也不需要增加一个新的标志栈。 


五.我的实现

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include <iostream>  
  4. #include<stack>  
  5. using namespace std;  
  6.    
  7.  /*******************数据结构的定义*************************/  
  8.  typedef char elemtype;  
  9.  typedef struct bitree  
  10.  {  
  11.    elemtype data;  
  12.    struct bitree *lchild,*rchild;  
  13.  }BiTree;  
  14.    
  15.    
  16.  /**********************功能函数*******************************/  
  17.  /* 
  18.    建树. 输入格式为: a(b,c(d,e)) 
  19.  */  
  20.   BiTree *create(char *s,BiTree *&root)  
  21.  {    
  22.     int i;  
  23.      bool isRight=false;  
  24.      stack<BiTree*> s1;          //用栈存放结点   
  25.      stack<char> s2;              //存放分隔符  
  26.      BiTree *p,*temp;  
  27.      root->data=s[0];  
  28.      root->lchild=NULL;  
  29.      root->rchild=NULL;  
  30.      s1.push(root);  
  31.      i=1;  
  32.      while(i<strlen(s))  
  33.      {  
  34.          if(s[i]=='(')  
  35.          {  
  36.              s2.push(s[i]);  
  37.              isRight=false;  
  38.          }      
  39.          else if(s[i]==',')      
  40.          {  
  41.              isRight=true;  
  42.          }  
  43.          else if(s[i]==')')  
  44.          {  
  45.              s1.pop();  
  46.              s2.pop();  
  47.          }  
  48.          else if(isalpha(s[i]))  
  49.          {  
  50.              p=(BiTree *)malloc(sizeof(BiTree));  
  51.              p->data=s[i];  
  52.              p->lchild=NULL;  
  53.              p->rchild=NULL;  
  54.              temp=s1.top();  
  55.              if(isRight==true)      
  56.              {  
  57.                  temp->rchild=p;  
  58.                  cout<<temp->data<<"的右孩子是"<<s[i]<<endl;  
  59.              }  
  60.              else  
  61.              {  
  62.                  temp->lchild=p;  
  63.                  cout<<temp->data<<"的左孩子是"<<s[i]<<endl;  
  64.              }  
  65.              if(s[i+1]=='(')  
  66.                  s1.push(p);  
  67.          }  
  68.          i++;  
  69.      }      
  70.  }  
  71.  /* 
  72.    递归打印函数 。  
  73.  */  
  74.  void display(BiTree *root)  
  75.  {  
  76.      if(root!=NULL)  
  77.      {  
  78.          printf("%c",root->data);  
  79.          if(root->lchild!=NULL)  
  80.          {  
  81.              printf("(");  
  82.              display(root->lchild);  
  83.          }  
  84.          if(root->rchild!=NULL)  
  85.          {  
  86.              printf(",");  
  87.              display(root->rchild);  
  88.              printf(")");  
  89.          }  
  90.      }  
  91.  }  
  92.    
  93.  /* 
  94.    先序遍历。递归 。  
  95.  */  
  96.  void preOrder1(BiTree *root)  
  97.  {  
  98.       if(root!=NULL)  
  99.       {  
  100.         printf("%c ",root->data);  
  101.         preOrder1(root->lchild);  
  102.         preOrder1(root->rchild);  
  103.       }   
  104.  }  
  105.    
  106.  /* 
  107.    先序遍历。非递归 。  
  108.     1)访问结点P,并将结点P入栈; 
  109.     2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P; 
  110.     3)直到P为NULL并且栈为空,则遍历结束。 
  111.  */  
  112.  void preOrder2(BiTree *root)  
  113.  {  
  114.      stack<BiTree*> s;    //也可以用数组来实现   
  115.      BiTree *p=root;  
  116.      while(p!=NULL||!s.empty())  
  117.      {  
  118.          while(p!=NULL)  
  119.          {  
  120.              cout<<p->data<<" ";  
  121.              s.push(p);  
  122.              p=p->lchild;  
  123.          }  
  124.          if(!s.empty())  
  125.          {  
  126.              p=s.top();  
  127.              s.pop();  
  128.              p=p->rchild;  
  129.          }  
  130.      }  
  131.  }  
  132.    
  133.  /* 
  134.    中序遍历。递归。  
  135.  */  
  136.  void inOrder1(BiTree *root)  
  137.  {  
  138.      if(root!=NULL)  
  139.      {  
  140.          inOrder1(root->lchild);  
  141.          printf("%c ",root->data);  
  142.          inOrder1(root->rchild);  
  143.      }  
  144.  }  
  145.    
  146.  /* 
  147.    中序遍历。非递归。  
  148.    1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理; 
  149.    2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子; 
  150.    3)直到P为NULL并且栈为空则遍历结束; 
  151.  */  
  152.  void inOrder2(BiTree *root)  
  153.  {  
  154.      stack<BiTree*> s;  
  155.      BiTree *p=root;  
  156.      while(p!=NULL||!s.empty())  
  157.      {  
  158.          while(p!=NULL)  
  159.          {  
  160.              s.push(p);  
  161.              p=p->lchild;  
  162.          }  
  163.          if(!s.empty())  
  164.          {  
  165.              p=s.top();  
  166.              cout<<p->data<<" ";  
  167.              s.pop();  
  168.              p=p->rchild;  
  169.          }  
  170.      }  
  171.  }  
  172.    
  173.  /* 
  174.    后序遍历 。递归。  
  175.  */  
  176.  void postOrder1(BiTree *root)  
  177.  {  
  178.      if(root!=NULL)  
  179.      {  
  180.          postOrder1(root->lchild);  
  181.          postOrder1(root->rchild);  
  182.          printf("%c ",root->data);  
  183.      }  
  184.  }  
  185.    
  186.  /* 
  187.    后序遍历 。非递归。  
  188.    要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。 
  189.    如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但 
  190.    是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况, 
  191.    则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩 
  192.    子前面被访问,左孩子和右孩子都在根结点前面被访问。 
  193.  */  
  194.  void postOrder2(BiTree *root)  
  195.  {  
  196.       stack<BiTree*> s;  
  197.      BiTree *cur;                      //当前结点   
  198.      BiTree *pre=NULL;                 //前一次访问的结点   
  199.      s.push(root);  
  200.      while(!s.empty())  
  201.      {  
  202.          cur=s.top();  
  203.          if((cur->lchild==NULL&&cur->rchild==NULL)||  
  204.             (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))  
  205.          {  
  206.              cout<<cur->data<<" ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过   
  207.                s.pop();  
  208.              pre=cur;   
  209.          }  
  210.          else  
  211.          {  
  212.              if(cur->rchild!=NULL)  
  213.                  s.push(cur->rchild);  
  214.              if(cur->lchild!=NULL)      
  215.                  s.push(cur->lchild);  
  216.          }  
  217.      }      
  218.    
  219.  }  
  220.    
  221.  /***********************main函数*************************/  
  222.  int main()  
  223.  {  
  224.     char s[100];                
  225.     while((scanf("%s",s)))  
  226.     {  
  227.        BiTree *root=(BiTree *)malloc(sizeof(BiTree));  
  228.        create(s,root);  
  229.        printf("\n");  
  230.        printf("先序递归遍历:");   
  231.        preOrder1(root);  
  232.        printf("\n");  
  233.        printf("中序递归遍历:");   
  234.        inOrder1(root);  
  235.        printf("\n");  
  236.        printf("后序递归遍历:");   
  237.        postOrder1(root);  
  238.        printf("\n");  
  239.        printf("\n");  
  240.        printf("先序非递归遍历:");   
  241.        preOrder2(root);  
  242.        printf("\n");  
  243.        printf("中序非递归遍历:");   
  244.        inOrder2(root);  
  245.        printf("\n");  
  246.        printf("后序非递归遍历:");   
  247.        postOrder2(root);  
  248.        printf("\n\n");  
  249.          
  250.     }  
  251.    
  252.      return 0;  
  253.  }   
  254.    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值