数据结构:二叉树

二叉树是一种高效的数据结构,平均操作时间为O(lgN)。本文介绍了树的定义、结点类型、遍历方式,以及二叉树的深度和性质。讨论了二叉查找树的平均深度为O(lgN),并阐述了二叉树在表达式树和查找树中的应用,包括删除操作的策略。

一般对于大量数据访问,如果通过链表的线性访问时间会过长,不宜使用。二叉树可以很很好的解决这个问题,其大部分操作的运动平均时间为 O(lgN)。
树的定义:
一棵树可以看作是一些点的集合。这个集合可以为空集,若不为空集,则可以看作是由根结点(root)和一个或者多个子树组成,这些子树的每一个根结点都和根结点连接。
因此对含有 N 个结点的树拥有 N-1 条边。基于以下事实:每条边都连接他的父亲,而除了根结点外,每个结点都有父亲结点。

几个定义:
叶子结点:没有儿子结点的结点
兄弟结点:拥有相同父亲的结点
路径:从 n1nk 的路径表示为序列 n1,n2,...,nk
路径的长:路径上的边的条数
树的深度:对于结点 ni 来说,ni 的深度就是根结点到 ni 的路径长

树的实现:
树结点的基本结构:

struct TreeNode{
    Object element;
    TreeNode* firstChild;
    TreeNode* nextSibling;
}

树的遍历及应用–UNIX/DOS 中的目录结构
目录的遍历

void FileSystem::listAll(int depth = 0) const
{
    printName(depth); //print the name of Object
    if(isDirectory())
        for each file c in this directory(for each child)
            c.listAll(depth+1)
}
输出结果为深度为i的目录将会被缩进i次打印其名

这种遍历叫做前序遍历,因为对结点本身的处理要先于处理他的儿子结点
还有一种遍历方式叫做后序遍历,在后序遍历中,在一个结点的工作是在它的儿子结点被计算完成后再进行的。

目录大小计算

int FileSystem::size()const
{
    int totalSize = sizeOfThisFile();
    if(isDirectory())
        for each file c in this directory 
            totalSize +=c.size();
    return totalSize;

}。

二叉树:一棵每个结点都不有超过两个儿子的树
二叉树的一个性质是二叉树的深度要比结点个数 N 小的多,平均深度为 O((N)),对于二叉查找树来说,其深度平均为 O(lg(N))

实现:

struct BinaryNode
{
    Object element;
    BinaryNode* left;
    BinaryNode* right;
}

二叉树的应用:
表达式树
表达式树的叶子结点存放的都是操作数(operand),其他结点存放的都是操作符。我们可以递归的产生一个带括号的左表达式,再打印出根结点的符号,再打印出带括号的右表达式从而得到一个中缀表达式,这也称为中序遍历(左,根,右);还有一种策略就是递归的打印出左子树,右子树,根结点,这种策略我们称之为后续遍历。
构造一棵表达式树
算法思想:首先一次一个符号的读入表达式。如果符号是操作数,就建立一个单结点树并将它压入栈中。如果符号是操作符,那么就从栈中弹出两棵树 T1 和 T2 并形成一棵新的树,该树的根结点就是操作符,它的左右儿子分别是 T2 和 T1。然后将指向这棵树的指针压入栈中。

查找树–二叉查找树
对于树中的每个结点 x,它的左子树中所有项的值小于 x 中的项,而它的右子树中所有的项的值大于 x 中的项。一般都是通过递归的定义来实现二叉查找树,二叉查找树的平均深度为 O(lgN)。

template<typename Comparable>
class BinarySearchTree
{
    public:
        BinarySearchTree();
        BinarySearchTree(const BinarySearchTree& rhs);
        ~BinarySearchTree();

        const Comparable& findMin() const;
        const Comparable& findMax() const;
        bool contains(const Comparable& x) const;
        bool isEmpty()const;
        void printTree() const;

        void makeEmpty();
        void insert(const Comparable&x);
        void remove(const Comparable&x);

        const BinarySearchTree& operator=(const Comparable& rhs);
    private:
        struct BinaryNode
        {
            Comparable element;
            BinaryNode* left;
            BinaryNode* right;
            BinaryNode(const Comparable& theElement,BinaryNode* 
            lt,BinaryNode*rt):element(theElement),left(lt),
             right(rt){}
        }
        BinaryNode* root;
        void insert(const Comparable& x,BinaryNode*&t)const;
        void remove(const Comparable& x,BinaryNode*&t)const;
        BinaryNode* findMin(BinaryNode* t)const;
        BinaryNode* findMax(BinaryNode* t)const;
        bool contains(const Comparable&x,BinaryNode* t)const;
        void makeEmpty(BinaryNode* &t);
        void printTree(BinaryNode* t)const;
        BinaryNode* clone(BinaryNode* t)const;
};
bool BinarySearchTree::contains(const Comparable&x)const
{
    return contains(x,root);
}
void BinarySearchTree::insert(const Comparable&x)const
{
    insert(x,root);
}
void BinarySearchTree::remove(const Comparable&x)const
{
    remove(x,root);
}
bool BinarySearchTree::contains(const Comparable&x,BinaryNode*t)
{
    if(t==NULL)
        return false;
    else if(x<t->element)
        return(x, t->left);
    else if(x>t->element)
        return(x, t->right);
    else
        return true;
}
BinaryNode* BinarySearchTree::findMin(BinaryNode*t)const
{
    if(t==NULL)
        return NULL;
    if(t->left==NULL)
        return t;
    return findMin(t->left);
    /* 非递归实现
        if(t!=NULL)
           while(t->left!=NULL)
               t = t->left;
        return t;
    */
}

BinaryNode* BinarySearchTree::findMin(BinaryNode*t)const
{
    if(t!=NULL)
        while(t->right!=NULL)
            t = t->right;
    return t;
    /*递归实现
    if(t==NULL)
        return NULL;
    if(t->right==NULL)
        return t;
    return finMax(t->right);
    */
}
void BinarySearchTree::insert(const Comparable&x,BinaryNode*&t) const
{
    if(t==NULL)
        t = new BinaryNode(x,NULL,NULL);
    else if(x<t->element)
        insert(x,t->left);
    else if(x>t->element)
        insert(x,t->right);
    else
    ;    //duplicate do nothing
}

二叉树的删除操作是最困难的操作,因为删除后需要对结构进行重新调整。

  1. 删除结点为叶子结点:直接删除
  2. 删除结点含有一个儿子:直接用该结点的儿子结点来替换该结点
  3. 删除结点含有两个儿子:一般的策略就是用其右子树的最小数据来替换该结点的数据并递归的删除那个结点。因为右子树中的最小的结点不可能有左儿子,因此满足只有一个儿子的情况,删除参照情况 2 即可。
    void BinarySearchTree::remove(const Comparable&x,BinaryNode*& t)
    {

    }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值