二叉树复习笔记

到目前为止,我们已经介绍了线性数据结构和表数据结构。这些数据结构一般不适用与描述具有层次结构的数据…

树是一个非空的有限元素的集合,其中一个元素为根(root),余下的元素组成t的子数(subtree)
层次中最高层元素为根,其下一级的元素是余下元素所构成的子数的根

二叉树

定义 : 二叉树(binary tree) t 是有限个元素的集合(可以为空)。当二叉树非空时,其中有一个称为根的元素,余下的元素(如果有的话)被组成两个二叉树,分别称为t的左子树和右子树

根本区别
  • 二叉树可以为空
  • 二叉树中每个元素都恰好有两个子树(其中一个或者两个可能为空)。树中每个元素可能有若干子树。
  • 在二叉树中每个元素的子树都是有序的,也就是说可以用左子树和右子树来加以区别。而树的子树之间是无序的。

             +
             /\
        *        /   
        /\       /\
    a      b   c   d
    

    如上为数学表达式树,其含义为 (a*b)+(c/d)

二叉树的特性

特性1:包含n(n>0)个元素的二叉树的边数为n-1

特性2:若二叉树的高度为h,h>=0,则该二叉树至少有h个元素,最多有2^h-1个元素(即每一层至少有一个元素)

特性3:包含n个元素的二叉树的高度最大为n,最小为log(n-1)

特性4:设完全二叉树中一元素的序号为i,1<=i<=n则以下规则成立:

  • 当i = 1时,该元素为二叉树的根。若i>1则该元素的父节点的编号为 i/2
  • 当2i>n时,该元素无左孩子。否则其左孩子的编号为2i
  • 若2i+1>n,该元素无右孩子。否则其右孩子的编号为2i+1

二叉树的描述

公式化描述

在公式化描述的方法中,将二叉树的元素存储在数组中,缺少的部分由null表示,当缺少的元素很少的时候这种表示方法十分有效

链表描述

这是一种二叉树最常用的描述方式,每个元素都是用一个或者两个指针域的节点表示,这两个域被称为LeftChild和RightChild,除了两个指针域外,每个节点还包含一个data域。

用一个变量来保存二叉树的根,并用该变量的名称来指称根节点或者整个二叉树。

在二叉树中不设置指向父节点的指针是没有问题的,因为大部分时候是不需要这个指针的。如果应用需要这个指针,可以在每个节点中增加一个指针域。


二叉树的常用操作

二叉树的常用操作为

  • 确定其高度
  • 确定其元素数目
  • 复制
  • 在屏幕或者纸上显示二叉树
  • 确定两棵二叉树十否一样
  • 删除整棵二叉树
  • 若为数学表达式树,则计算这棵树
  • 若为数学表达式树,则给出对应的带括号的表达式

二叉树的遍历

  • 前序遍历
{
    if(t)
    {
        visit(t);         //访问根节点
        PreOrder(t.left); //访问左子树
        PreOrder(t.right);//访问右子树       
    }
}
  • 中序遍历
void inOrder(binaryTreeNode<T> *t)
{
    if(t)
    {
        inOrder(t.left); //访问左子树
        visit(t);        //访问根节点
        inOrder(t.right);//访问右子树        
    }
}
  • 后序遍历
void postOrder(binaryTreeNode<T> *t)
{
    if(t)
    {
        postOrder(t.left); //访问左子树
        postOrder(t.right);//访问右子树
        visit(t);        //访问根节点

    }
}
  • 逐层遍历
    在逐层遍历的过程中,按从顶到底层的次序访问树中的元素,在同一层中,从左到右进行访问。由于遍历中所使用的数据结构是一个队列而不是一个栈,因此写一个按层遍历的递归程序是很困难的,下面的代码采用队列的数据结构,队列中的元素指向二叉树的节点。当然也可以采用公式化队列。
//--------------------------------------------------
// 广度优先
void bfs_order(btree* tree) {
    btNode* p = tree;
    if (NULL == p) {
        return;
    }

    queue<btNode*> * qu = new queue<btNode*>();
    qu->push(p);

    while (!qu->empty()) {
        p = qu->front();
        qu->pop();
        cout << p->data << "  ";
        if (NULL != p->left) {
            qu->push(p->left);
        }
        if (NULL != p->right) {
            qu->push(p->right);
        }
    }
    delete qu;
}
//--------------------------------------------------

去递归处理

//--------------------------------------------------

// 非递归前序遍历
void pre_order(btree* tree) {
    btNode * p = tree;
    if (NULL == p)
        return;

    stack<btNode*>* st = new stack<btNode*>();
    st->push(p);
    while (!st->empty()) {
        p = st->top();
        st->pop();
        cout << p->data << "  ";
        if (NULL != p->right) {
            st->push(p->right);
        }
        if (NULL != p->left) {
            st->push(p->left);
        }
    }
    delete st;
}
// 非递归后续遍历
//需要注意的是 : 非递归后序遍历方法相对实现比较困难,主要原因就在于父子节点访问缺乏连续
//              解决思路是将前一个访问节点记忆下来,并判断和当前节点之间的关系再做处理
void post_order(btree* tree) {

    btNode* curr = tree;  // 记录当前执行的节点
    btNode* prev = NULL; // 记录前一个访问的节点
    if (NULL == curr) {
        return;
    }
    stack<btNode*>* st = new stack<btNode*>();
    st->push(curr);
    while (!st->empty()) {
        curr = st->top();
        // 如果该节点没有孩子节点则可以直接访问
        if (NULL == curr->left && NULL == curr->right) {
            cout << curr->data << "  ";
            st->pop();
            prev = curr;
            continue;
        }
        // 如果该节点的孩子节点已经被访问过了,也可直接访问
        if (NULL != prev && (prev == curr->right || prev == curr->left)) {
            cout << curr->data << "  ";
            st->pop();
            prev = curr;
            continue;
        }

        // 除了上述情况则需要将孩子节点入栈
        if (NULL != curr->right) {
            st->push(curr->right);
        }
        if (NULL != curr->left) {
            st->push(curr->left);
        }
    }

    delete st;
}

// 非递归中序遍历
void in_order(btree* tree) {
    btNode* p = tree;
    if (NULL == p)
        return;

    stack<btNode*>* st = new stack<btNode*>();
    while (NULL != p || !st->empty()) {
        while (NULL != p) {
            st->push(p);
            p = p->left;
        }
        if (!st->empty()) {
            p = st->top();
            st->pop();
            cout << p->data << "  ";
            p = p->right;
        }
    }
    delete st;
}

代码引用自http://www.xuebuyuan.com/1612933.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值