二叉树及二叉树的遍历

二叉树(binary tree)

二叉树的定义

  二叉树的定义:树的度为2的树。

  二叉树的递归定义:二叉树或者是一棵空树,或者是一棵由一个根结点和两棵互不相交的左子树和右子树所组成的非空树,而左右子树又都是一棵二叉树。

二叉树的性质

  1.第i层上至多有2的i-1次方个结点。

  2.深度为h的二叉树至多有2的h次方减1个结点。

  3.每一层都满的二叉树称为满二叉树,只在最后一层右边缺若干个结点的树称为完全二叉树

  (对结点的编号通常都是从满二叉树的树根开始,从上到下从左到右编号)。

  完全二叉树的重要性质:

  根结点序号为i=1的情况下:

  1.编号为i的结点,左孩子编号为2i,右孩子编号为2i+1.

  2.除根结点外,编号为i的结点,其父结点的标号为i/2向下取整。

二叉树的存储结构

  同线性表一样,二叉树有顺序和链接两种存储结构。

1.顺序存储结构

  顺序存储一棵二叉树,首先对该树中每个结点进行编号,然后以各个结点的编号为下标,把各结点的值对应存储到一个一维数组中。

  每个结点的编号与等深度的满二叉树中对应的结点编号相同,即树根编号为1,然后从上到下从左到右编号,i结点的左右孩子为2i和2i+1.

  缺点:对于单支结点较多的二叉树来说很多存储位置空闲。

2.链接存储结构

  链接存储中通常采用的方法是,在每个结点中设置三个域:值域(用来存储对应的数据元素),左指针域和右指针域。

  另一种方法是,在如上的结构中再增加一个parent指针域(便于查找父结点)。

  不带双亲指针的链接存储结构称作二叉链表,既可以由独立分配的结点链接而成,也可以由数组中的元素结点链接而成。

  独立结点的类型可以这样定义:

struct BTreeNode{
    ElemType data;
    BTreeNode* left;
    BTreeNode* right;
};

 

  数组元素结点可以定义为

struct ABTreeNode{
    ElemType data;
    int left,right;
};

  第二种形式中left和right域分别存储左右孩子结点所在单元的下标,所以被定义为整型。

  在数组中建立二叉树的好处是,建立好后可以把整个数组写入到文件中保存起来,需要时再从文件中读入到数组中。

二叉树遍历

  设二叉树由BTreeNode类型的、通过动态分配产生的独立结点链接而成,并设BT为指向根结点的指针。

  前序遍历

void PreOrder(BTreeNode* BT)
{
    if(BT != NULL)
    {
        cout<<BT->data<<' ';  //访问根结点,操作视应用而定
          PreOrder(BT->left);
        PreOrder(BT->right);
    }
}

 

  中序遍历

void InOrder(BTreeNode* BT)
{
    if(BT != NULL)
    {
        InOrder (BT->left);
        cout<<BT->data<<' ';
        InOrder (BT->right);
    }
}

 

  后序遍历

void PostOrder(BTreeNode* BT)
{
    if(BT != NULL)
    {
        PostOrder (BT->left);
        PostOrder (BT->right);
        cout<<BT->data<<' ';
    }
}

 

  按层遍历

  可以按照二叉树的层次结构进行遍历,即按照从上到下从左到右的次序访问各个结点。

  按层遍历算法需要使用一个队列,开始时把整个树的根结点入队,然后每从队列中删除一个结点并输出该结点的值时,都把它的非空的左右孩子结点入队,这样当队列空时算法结束。

按层遍历
//按层遍历
void LevelOrder(BTreeNode* BT)
{
    const int MaxSize = 30; //定义用于存储队列的数组长度
    //在这个算法中,队列的最大长度不会超过二叉树中一层上的最大结点数
    BTreeNode* q[MaxSize];  //定义队列所使用的数组空间
    int front=0, rear=0;    //定义队首指针和队尾指针,初始为空队
    BTreeNode* p;

    if(BT != NULL) //将树根指针进队
    {
        rear = (rear +1) % MaxSize;
        q[rear] = BT;
    }

    while(front!=rear)  //当队列非空时执行循环
    {
        front=(front + 1) % MaxSize;  //使队首指针指向队首元素
        p = q[front];                  //操作并删除队首元素
        cout<<p->data<<' ';
        if(p->left !=NULL)        //若存在左孩子,则该结点指针进队
        {
            rear = (rear +1) % MaxSize;
            q[rear] = p->left;        
        }
        if(p->right !=NULL)        //若存在右孩子,则该结点指针进队
        {
            rear = (rear +1) % MaxSize;
            q[rear] = p->right;        
        }
    }//while end

}

 

 

posted @ 2012-10-31 21:41  圣骑士wind  阅读(2539)  评论(0编辑  收藏  举报