二叉树基本操作

本文介绍了二叉树的定义,包括满二叉树和完全二叉树的概念,并详细讲解了如何进行节点个数、叶子节点个数、树高度、第K层节点个数的计算,以及查找特定节点、销毁二叉树的操作。还探讨了前序、中序、后序遍历的递归和非递归实现,以及层序遍历的队列实现。最后提出二叉树线索化的概念,为后续的非递归遍历铺垫。

要想试着去模拟构建一棵二叉树,就必须了解二叉树在系统中是如何保存的,实际上,二叉树的节点保存在一个数组中,我们以下面二叉树为例:(#为空节点,占一个子节点位置)
这里写图片描述

满二叉树:每一层节点都是完整的,每层节点数(2^(n-1))
完全二叉树:最后一个节点之前不存在空节点。
满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树。

1,求节点个数:(递归)

思路:root为空时,返回0;root不为空时,左子树节点+右子树节点+1(当前节点)

size_t _Size(Node* root)
{
    if(NULL == root)
        return 0;
    return _Size(root->_left)+_Size(root->_right)+1;    
}

2,求叶子节点个数:(递归)

思路:如果root为空时,返回0;如果root的左子树为空且右子树为空时,返回1;

size_t _LeafSize(Node* root)
{
    if(NULL == root)
        return 0;
    if(NULL == root->_left && NULL == root->_right)
        return 1;
    return _LeafSize(root->_left)+_LeafSize(root->_right);      
}

3,求二叉树高度(深度):(递归)

思路:如果root为空,返回0;如果root的左子树且右子树为空,返回1,记录左右子树的高度,判断哪个高就选那个病且加1,(加自身节点)

size_t _Depth(Node* root)
{
    if(NULL == root)
        return 0;
    if(NULL == root->_left && NULL == root->_right)
        return 1;
    size_t LeftDepth = _Depth(root->_left);
    size_t RightDepth = _Depth(root->_right);

    return (LeftDepth>RightDepth)?(LeftDepth+1):(RightDepth+1);         
}

4,求第K层节点个数:(遍历)

思路:如果root为空,返回0;如果root不为空,k为1时返回1,第K层节点数等于第K-1层的节点的左节点加上右节点。

size_t _GetKLevel(Node* root,size_t k)
{
    if(NULL == root)
        return 0;
    if(1 == k)
        return 1;

    return _GetKLevel(root->_left,k-1) + _GetKLevel(root->_right,k-1);      
}

5,找特定节点位置:(遍历)

思路:先遍历所在节点,然后遍历左子树 ,最后遍历右子树

Node* _Find(Node* root,const T& x)
{
    if(NULL == root)
        return NULL;
    if(x == root->_data)
        return root;

    Node* ret = _Find(root->_left,x);
    if(ret)
        return ret;
    return _Find(root->_right,x);
}

6,销毁二叉树:(递归)

思路:先销毁左子树,后销毁右子树,最后销毁root

void Destory(Node* root)
{
    _Destory(root->_left);
    _Destory(root->_right);
    delete root;
    root = NULL;
}

7,前序遍历(递归+非递归)

思路(递归):先root,然后左子树,最后右子树

void _PrevOrder(Node* root)
{
    //root
    Node* cur = root;
    if(cur)
    {
        cout<<cur->_data<<" ";
        _PrevOrder(cur->_left);
        _PrevOrder(cur->_right);
    }
}

思路(非递归):非递归就得借助栈来处理,访问root,并将root压入栈,继续向左子树走,继续访问压栈,直到最左节点,然后取栈顶元素记下来,并pop掉,然后以栈顶元素的右子树节点为起点继续访问,直至cur为空且栈为空

void _PrevOrder(Node* root)
{
    stack<Node*> s;
    Node* cur = root;
    while(cur || !s.empty())
    {
        while(cur)
        {
            cout<<cur->_data<<" "; 
            s.push(cur);
            cur = cur->_left;
        }
        Node* Top = s.top();
        s.pop();
        cur = Top->_right; 
    }
}

8,中序遍历(递归+非递归)

思路(递归):先左子树,然后root,最后右子树

void _InOrder(Node* root)
{
    if(root)
    {
        _InOrder(root->_left);
        cout<<root->_data;
        _InOrder(root->_right);
    }
}

思路(非递归):和前序遍历一个思想,只是某些语句调整一下位置即可

void InOrder(Node* root)
{
    stack<Node*> s;
    Node* cur = root;
    while(cur || !s.empty())
    {
        while(cur)
        {
            s.push(cur);
            cur = cur->_left;
        }
        Node* Top = s.top();
        s.pop();
        cout<<cur->_data<<" "; 
        cur = Top->_right;
    }
}

9,后序遍历(递归+非递归)

思路(递归):先左子树,后右子树,最后root

void _PostOrder(Node* root)
{
    if(root)
    {
        _PostOrder(root->_left);
        _PostOrder(root->_right);
        cout<<root->_data;
    }
}

思路(非递归):后序遍历和前两个遍历一个思想,只不过存在一个问题,就是走到一个节点后,如何判断他的右子树是否已经遍历过?不然就会陷入死循环,这里的解决方法是加一个标志,标明当前节点的上一个节点,这样就能很好的的解决。

void PostOrder(Node* root)
{
    stack<Node*> s;
    Node* cur = root;
    Node* prev = NULL;
    while(cur || !s.empty())
    {
        while(cur)
        {
            s.push(cur);
            cur = cur->_left;
        }
        Node* Top = s.top();

        //判断节点右子树已遍历还是未遍历
        if(Top->_right == prev || Top->_right == NULL)
        {
            s.pop();
            cout<<cur->_data<<" ";
            prev = Top;
        }
        else
            cur = Top->_right;
    }
}

10,层序遍历

思路:层序遍历需要借助队列queue实现,将根节点放入队列中,访问队列队头元素,然后先后判断队头的左右子树是否为空,如果不为空,则放进队列,然后取出队头元素,如果队列不为空,就继续上面步骤,直至队列为空。

void FloorOrder(Node* root)
{
    queue<Node*> q;
    Node* cur = root;
    if(root)
    {
        q.push(cur);
        while(!q.empty())   
        {
            cout<<q.front()->_data<<" ";

            if(q.front()->_left != NULL)
                q.push(q.front()->_left);
            if(q.front()->_right != NULL)
                q.push(q.front()->_right);

            q.pop();        
        }
    }
}

上面就是二叉树的基本操作了,我们发现二叉树的非递归遍历要使用到栈或队列这样的数据结构,那么我们不借助栈或队列可以实现非递归遍历吗?答案是肯定的,下一篇文章我会讲解有关二叉树的线索化,及线索化后的遍历,再一个二叉树线索化后可以很好的使用到迭代器。

下面是二叉树基本操作的完整代码:


#include<iostream>
#include<queue>
#include<stack>
using namespace std;

//二叉树节点的定义
template<class T>
struct BinaryTreeNode
{
    BinaryTreeNode<T>* _left;
    BinaryTreeNode<T>* _right;
    T _data;

    BinaryTreeNode(const T& x)
        :_left(NULL),_right(NULL),_data(x)
    {}
};

//二叉树的定义
template<class T>
class BinaryTree
{
    typedef BinaryTreeNode<T> Node;

public:
    BinaryTree()
        :_rood(NULL)
    {}

    BinaryTree(T* a, size_t n, const T& invalid)    //构造函数(a存节点的数组array,n数组大小,非法值‘#’)
    {
        size_t index = 0;      //下标
        _root = CreateTree(a, n, invalid, index);
    }

    Node* CreateTree(T* a, size_t n, const T& invalid, size_t& index)     //下标参数必须为引用传值
    {
        Node* root = NULL;
        if((index<n) && (a[index] !=invalid))
        {
            root = new Node(a[index]);
            root->_left = CreateTree(a, n, invalid, ++index);
            root->_right = CreateTree(a, n, invalid, ++index);
        }
        return root;
    }

    BinaryTree(const BinaryTree<T>& t)
    {
        _root = _CopyBinaryTree(t._root);
    }
    BinaryTree<T>& operator=(const BinaryTree<T>& t)
    {
        if (this != &t)
        {
            this->~BinaryTree();
            _root = _CopyBinaryTree(t._root);
        }
        return *this;
    }

    ~BinaryTree()
    {
        _Destroy(_root);
    }

    void PrevOrder()  //先序遍历
    {
        _PrevOrder(_root);
        cout << endl;
    }

    void InOrder()   //中序遍历
    {
        _InOrder(_root);
        cout << endl;
    }

    void PostOrder()    //后序遍历
    {
        _PostOrder(_root);
        cout << endl;
    }

    void FloorOrder()   //层序遍历
    {
        queue<Node*> q;
        if (_root)
            q.push(_root);
        while (!q.empty())
        {
            Node* front = q.front();
            cout << front->_data << " ";
            if (front->_left)
            {
                q.push(front->_left);
            }
            if (front->_right)
            {
                q.push(front->_right);
            }
            q.pop();
        }

    }

    size_t Size()   
    {
        return _Size(_root);
    }

    size_t LeafSize()   //求叶子节点数
    {
        return _LeafSize(_root);
    }

    size_t GetKLevel(size_t k)  //K层节点个数
    {
        return _GetKLevel(_root, k);
    }

    size_t Depth()  //深度/高度
    {
        return _Depth(_root);
    }

    Node* Find(const T& x)      //寻找值为X的节点
    {
        return _Find(_root,x);
    }




protected:
    Node* _CopyBinaryTree(Node* root)   //拷贝树
    {
        if (root == NULL)
        {
            return NULL;
        }

        Node* newRoot = new Node(root->_data);
        newRoot->_left = _CopyBinaryTree(root->_left);
        newRoot->_right = _CopyBinaryTree(root->_right);
        return newRoot;
    }

    Node* _Find(Node* root, const T& x)
    {
        if (NULL == root)
        {
            return NULL;
        }   
        if (x == root->_data)
        {
            return root;
        }
        Node* ret = _Find(root->_left, x);
        if (ret)
        {
            return ret;
        }
        return _Find(root->_right, x);
    }

    size_t _Depth(Node* root)
    {
        if (NULL == root)
        {
            return 0;
        }
        if ((NULL == root->_left) && (NULL == root->_right))
        {
            return 1;
        }
        size_t LeftDepth = _Depth(root->_left) + 1;
        size_t RightDepth = _Depth(root->_right) + 1;
        return (LeftDepth >= RightDepth) ? LeftDepth : RightDepth;
    }

    size_t _GetKLevel(Node* root, size_t k)
    {
        if (NULL == root)
        {
            return 0;
        }
        if (1 == k)
        {
            return 1;
        }

        return _GetKLevel(root->_left, k - 1) + _GetKLevel(root->_right, k - 1);
    }

    size_t _LeafSize(Node* root)
    {
        if (NULL == root)
        {
            return 0;
        }
        if ((root->_left == NULL) && (root->_right == NULL))
        {
            return 1;
        }

        return _LeafSize(root->_left) + _LeafSize(root->_right);
    }

    size_t _Size(Node* root)
    {
        if (NULL == root)
        {
            return 0;
        }
        return _Size(root->_left) + _Size(root->_right)+1;
    }

    void _Destroy(Node* root)
    {
        if(root)
        {
            _Destroy(root->_left);
            _Destroy(root->_right);
            delete root;
            root = NULL;
        }
    }


    //void _PrevOrder(Node* root)   //先序遍历(递归)
    //{
    //  if (root)
    //  {
    //      cout << root->_data << " ";
    //      _PrevOrder(root->_left);
    //      _PrevOrder(root->_right);
    //  }
    //}


    void _PrevOrder(Node* root)   //非递归
    {
        stack<Node*> s;
        Node* cur = root;
        while (cur || !s.empty())
        {
            while (cur)
            {
                cout << cur->_data << " ";
                s.push(cur);
                cur = cur->_left;
            }

            Node* Top = s.top();
            s.pop();
            cur = Top->_right;
        }
    }


    //void _InOrder(Node* root)   //中序遍历递归
    //{
    //  if (root)
    //  {
    //      _InOrder(root->_left);
    //      cout << root->_data << " ";
    //      _InOrder(root->_right);
    //  }
    //}

    void _InOrder(Node* root)    //非递归中序遍历
    {
        stack<Node*> s;
        Node* cur = root;
        while (cur || !s.empty())
        {
            while (cur)
            {
                s.push(cur);
                cur = cur->_left;
            }
            Node* Top = s.top();
            s.pop();
            cout << Top->_data << " ";

            cur = Top->_right;
        }
    }


    //void _PostOrder(Node* root)  //后序遍历递归
    //{
    //  if (root)
    //  {
    //      _PostOrder(root->_right);
    //      _PostOrder(root->_left);
    //      cout << root->_data << " ";
    //  }
    //}

    //后序遍历存在一个大的问题,就是遍历一个节点时,不知他的右子树是否遍历过,这就需要一个标志
    void _PostOrder(Node* root)
    {
        stack<Node*> s;
        Node* cur = root;
        Node* prev = NULL;
        while (cur || !s.empty())
        {
            while (cur)
            {
                s.push(cur);
                cur = cur->_left;
            }
            Node* Top = s.top();

            //Top->_right  : 右子树已遍历,未遍历
            if(Top->_right == prev || Top->_right == NULL)
            {
                cout << Top->_data << " ";
                s.pop();
                prev = Top;   //注意prev的赋值位置
            }
            else
            cur = Top->_right;
        }
    }


private:
     Node* _root;
};

void Test()
{
    int array[13] = { 1,2,'#',3,'#','#',4,5,'#',6,'#','#',7 };
    BinaryTree<int> t(array, sizeof(array) / sizeof(int), '#');
    t.PrevOrder();
    t.InOrder();
    t.PostOrder();
    t.FloorOrder();
    cout<<t.Depth()<<endl;
    cout<<t.Find(6)<<endl;
    cout<<t.GetKLevel(4)<<endl;
    cout<<t.LeafSize()<<endl;
    cout<<t.Size()<<endl;
    BinaryTree<int> t2 = t;
    t2.PrevOrder();
    BinaryTree<int> t3(t);
    t3.PrevOrder();
}

int main()
{
    Test();
    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值