13二叉树的遍历

二叉树的遍历与构建

 

遍历(traversal)指的是对树中每个结点访问一次且仅一次。

访问(visit)是指对结点进行某种处理,比如输出结点值,查找某个(或某些)结点,计算结点的层号、高度、子孙个数等等。

注意:遍历必须按“一定的规律”进行,因为二叉树是非线性结构。

 

遍历方法(即规律)很多,常见的有: 

先序遍历(preorder traversal): DLR遍历(先根结点,后左子树,再右子树)

中序遍历(inorder traversal): LDR遍历 (先左子树,后根结点,再右子树)

后序遍历(postorder traversal): LRD遍历(先左子树,后右子树,再根结点)

 

先序遍历算法:

步骤1)如果当前遇到的结点为空,则直接返回。

步骤2)访问当前结点x(D)。

步骤3)递归地遍历x的左子树(L)。

步骤4)递归地遍历x的右子树(R)。

步骤5)完成对以x为根的二叉树的遍历,返回。

步骤2、3、4交换语句次序,变为中序遍历、后序遍历。

 

二叉树算法

二叉树的存储结构(双链式):             

typedef   struct  Bnode   //结点类型定义

   { element_type   data;   //值域

     struct  Bnode  *Lson, *Rson;  //指向左右儿子的链域

}  Bnode, *Bptr;  // 结点类型名,和指针类型名

 

//先序遍历函数

void preorder(Bptr p)

     {

      if(p==NULL)

 return;

      visit(p);

      preorder(p->Lson);

      preorder(p->Rson);

   }

//中序遍历函数

void inorder(Bptr p)

     {

      if(p==NULL) 

return;

      inorder(p->Lson);

      visit(p);

      inorder(p->Rson);

   }

//后序遍历函数

void pastorder(Bptr p)

     {

     if(p==NULL)

 return;

      pastorder(p->Lson);

      pastorder(p->Rson);

      visit(p);

   }

 

重要点:

中序前驱

情况1,a有左儿子s(又分二种情况)

[1]若s没有右儿子,则s就是a的中序前趋。

[2]若s有右儿子r,那么r的最右子孙t就是a的中序前趋 。

情况2,a没有左儿子(又分三种情况)

[1]若a没有父亲(a是根结点),那么,a没有中序前趋。

[2]若a是其父f的右儿子,那么,f是a 的中序前趋。

[3]若a是其父f的左儿子,如果a在g(最近)的右子树上,则g是a 的中序前趋;否则,a没有中序前趋。

 

遍历的实例运用

 

求二叉树各结点层号的算法

结点含有层数域level,采用先序遍历法

void  level(Bptr p,int i)

 {

     if(p==NULL)

 return;

     p->layer=i; 

     level(p->Lson,i+1);

     level(p->Rson,i+1);

 }

主调语句:  level(root,1);

 

求二叉树各结点高度的算法

结点含有高度域height ,采用后序遍历法

int  high(Bptr p)

   {  int i,j;

if(p==NULL)

return 0;    //空树的高度等于0

    i=high(p->Lson);

    j=high(p->Rson);

    p->height=(i>j)? i+1: j+1;  //求出结点高度

    return  (p->height); 

   }         

 主调语句:h=high(root);

 

输出结点a所有子孙的算法

void descents(Bptr p,element_type a)

   {

   if(p==NULL|| found==3 )

 return;

   if(p->data==a)

 found=1; 

   if(found==1)

 printf("%4d",p->data); 

   descents(p->Lson,a);

   descents(p->Rson,a);

   if(p->data==a)

 found=3;

    }

主调语句:

   found=0;

   descents(root,a);

给各结点进行中序编号算法

void  in_num(Bptr p)

 {

   if(p==NULL)

return;

   in_num(p->Lson);.

  p->in_number=count++;

   in_num(p->Rson);

  }    

 

中序编号性质:

结点在中序序列中的序号(1,2,…… , n)。

任意一个非叶结点v,其中序编号有如下性质:

1)左子树上结点的编号都小于v的编号。

2)右子树上结点的编号都大于v的编号。

3)以v为根的子树中,编号最小的结点,位于该子树的最左端;编号最大的结点,位于该子树的最右端。

4)中序序列中,v的左子树上的结点都排在v的左边,且紧靠v;右子树上的结点都排在v的右边,也紧靠v;v位于其左右子树的子中序序列的中间。

 

 

源代码:

// Btree.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <iostream>

using namespace std;

 

 

//结点的结构体

struct tree

{

         int data;                               //结点的数据域

         tree *left, *right;              //结点的左、右子树

};

 

//树的类

class Btree

{

         static int n;                         //记录叶子结点个数

         static int m;                        //记录树结点的个数

public:

         tree *root;                                   //跟结点

         Btree()

         {

                   root = NULL;

         }

         void create_Btree(int);                                         //构建二叉树树

         void Preorder(tree *);                  //先序遍历

         void inorder(tree *);                   //中序遍历

         void Postorder(tree *);                 //后序遍历

         void display1() { Preorder(root); cout << endl; }

         void display2() { inorder(root); cout << endl; }

         void display3() { Postorder(root); cout << endl; }

         int count(tree *);                      //计算二叉树的个数

         int findleaf(tree *);                   //求二叉树叶子的个数

         int findnode(tree *);                   //求二叉树中度数为1的结点数量,这是当初考数据结构时候的最后一道题目

};

 

int Btree::n = 0;

int Btree::m = 0;

void Btree::create_Btree(int x)

{

         tree *newnode = new tree;                                 //为树结点动态分配内存空间

         newnode->data = x;                                                        //结点存入数据

         newnode->right = newnode->left = NULL;       //当前结点的左、右子树为空

         //如果不存在根结点,此结点为树的根结点

         if (root == NULL)

                   root = newnode;               

         //

         else

         {

                   tree *back =NULL;

                   tree *current = root;

                   //遍历树 找到没有子树的结点

                   while (current != NULL)

                   {

                            back = current;

                            //左子树

                            if (current->data>x)

                                     current = current->left;

                            //右子树

                            else

                                     current = current->right;

                   }

                   //把新结点作为最后结点的左子树

                   if (back->data>x)

                            back->left = newnode;

                   //把新结点作为最后结点的右子树

                   else

                            back->right = newnode;

         }

}

 

int Btree::count(tree *p)

{

         if (p == NULL)

                   return 0;

         //递归计算树的结点个数

         else

                   return count(p->left) + count(p->right) + 1;      //这是运用了函数嵌套即递归的方法。

}

 

void Btree::Preorder(tree *temp)    //这是先序遍历二叉树,采用了递归的方法。

{

         if (temp != NULL)

         {

                   cout << temp->data << " ";

                   Preorder(temp->left);

                   Preorder(temp->right);

         }

}

 

void Btree::inorder(tree *temp)      //这是中序遍历二叉树,采用了递归的方法。

{

         if (temp != NULL)

         {

                   inorder(temp->left);

                   cout << temp->data << " ";

                   inorder(temp->right);

         }

}

 

void Btree::Postorder(tree *temp)     //这是后序遍历二叉树,采用了递归的方法。

{

         if (temp != NULL)

         {

                   Postorder(temp->left);

                   Postorder(temp->right);

                   cout << temp->data << " ";

         }

}

 

int Btree::findleaf(tree *temp)

{

         if (temp == NULL)return 0;

         else

         {        //左、右子树为空,叶子节点+1

                   if (temp->left == NULL&&temp->right == NULL)return n += 1;

                   else

                   {

                            findleaf(temp->left);

                            findleaf(temp->right);

                   }

                   return n;

         }

}

 

int Btree::findnode(tree *temp)

{

         if (temp == NULL)return 0;

         else

         {

                   if (temp->left != NULL&&temp->right != NULL)

                   {

                            findnode(temp->left);

                            findnode(temp->right);

                   }

                   //某结点只存在左子树,结点数+1,再遍历左子树

                   if (temp->left != NULL&&temp->right == NULL)

                   {

                            m += 1;

                            findnode(temp->left);

                   }

                   //某结点只存在右子树,结点数+1,再遍历右子树

                   if (temp->left == NULL&&temp->right != NULL)

                   {

                            m += 1;

                            findnode(temp->right);

                   }

         }

         return m;

}

 

 

void main()

{

         //实例化对象

         Btree A;

         int array[] = { 7, 4, 2, 3, 15, 35, 6, 45, 55, 20, 1, 14, 56, 57, 58 };

        

         //数组的长度

         int k;

         k = sizeof(array) / sizeof(array[0]);

         cout << "建立排序二叉树顺序: " << endl;

         //把数组元素依次存进二叉树结构中

         for (int i = 0; i<k; i++)

         {

                   cout << array[i] << " ";

                   A.create_Btree(array[i]);

         }

 

         cout << endl;

         cout << "二叉树节点个数: " << A.count(A.root) << endl;

         cout << "二叉树叶子个数:" << A.findleaf(A.root) << endl;

         cout << "二叉树中度数为1的结点的数量为:" << A.findnode(A.root) << endl;

 

         cout << endl << "先序遍历序列: " << endl;

         A.display1();

         cout << endl << "中序遍历序列: " << endl;

         A.display2();

         cout << endl << "后序遍历序列: " << endl;

         A.display3();

         getchar();

}

 

posted @ 2018-01-09 18:36  gd_沐辰  阅读(301)  评论(0编辑  收藏  举报