二叉查找树的实现以及相关遍历

二查树的实现

二叉树至少可以以如下的两种方式实现:数组和链接结构。为了用数组实现树,节点应声明为某种结构,其中至少包含
一个信息字段和两个"指针字段"。指针字段柏寒课数组的单元下标,数组单元则存储了该节点的左右子节点。

索引信息左子节点右子节点
01342
1316-1
22571
312-1-1
41053
52-1-1
629-1-1
720-1-1
表1-1:树的数组表示

在这里插入图片描述

图1-1:二叉查找树图例

代码:

//*************************************Binary_Search_Tree.h*************************************
#include<queue>
#include<stack>
using namespace std;

template<class T>
class Stack:public stack<T>{...};		//用栈来深度遍历二叉树

template<class T>
class Queue:public queue<T>				//用队列来广度遍历二叉树
{
public:
    T deque()
    {
        T tmp = front();
        queue<T>::pop();
        return tmp;
    }
    void enqueue(const T& el)
    {
        push(el);
    }
};
template<class T>
class BSTNode                			//树节点类
{
public:
    T el;
    BSTNode<T> *left;
    BSTNode<T> *right;
    BSTNode()
    {
        left = right = 0;
    }
    BSTNode(const T& e,BSTNode<T> *l = 0,BSTNode<T> *r = 0)
    {
        el = e;
        left = l;
        right = r;
    }
};

template<class T>
class BST
{
protected:
    BSTNode<T>* root;
    void clear(BSTNode<T>*);            
    T* search(BSTNode<T>*,const T&)const;       //二叉树的查找算法
    void preorder(BSTNode<T>*);                 //二叉树的递归前序遍历算法
    void inorder(BSTNode<T>*);                  //二叉树的递归中序遍历算法
    void postorder(BSTNode<T>*);                //二叉树的递归后序遍历算法
    virtual void visit(BSTNode<T> *p);			//打印树种的 element
    {
        cout<<p->el<<' ';
    }
public:
    BST()
    {
        root = 0;
    }
    ~BST()
    {
        clear();
    }
    void clear()
    {
        clear(root);
        root = 0;
    }
    bool isEmpty() const			//判断树是否为空
    {
        return rppt == 0;
    }
    
    //遍历算法的Interface
    void preorder()
    {
    	preorder(root);
    }
    void inorder()
    {
    	inorder(root);
    }
    void postorder()
    { 
    	postorder(root);
    }


    T* search(const T& el) const
    {
        return search(root,el);
    }
    
    //迭代,非递归实现前、中、后 遍历算法
    void iteraivePreorder();
    void iterativeInorder();
    void iterativePostorder();
    	
    void breadthFirst();  			//二叉树的广度搜索算法
    //..........
};

二叉树查找算法

查找算法的复杂度是由查找过程中的比较次数来度量的。比较次数取决于从根节点到被查找节点唯一路劲上的节点数
目。也就是说,复杂度是达到该节点路径的长度+1。复杂度取决于树的形状。在最坏的情况虚啊,为数转化为链表时。

代码:

#include"Binary_Search_Tree.h"
template<class T>
T* BST<T>::search(BSTNode<T>* p,const T& el) const
{
    while(p!=0)
    {
        if(el == p->el)
        {
            return &p->el;
        }
        else if(el < p->el)
        {
            p = p->left;
        }
        else
        {
            p = p->right;
        }
        return 0;
    }
}

二叉树的遍历算法

1.广度优先遍历

广度优先遍历:

  • 广度优先遍历从最低层(或者最高层)开始,向上(或向下)逐层访问每个节点,
    在每一层上从左到右(或从右到左)访问每个节点。
  • 当使用队列时,这种遍历方式的实现相当直接。假设从上到下、从左到右进行广度优先遍历。
    在访问一个节点后,它的子节点位于第 n+1 层,如果将该节点的所有子节点都放到队列的末尾,
    那么这些节点将在第 n 层的所有结点都访问后在访问。这样,算法就满足了"第 n 层的所有结点 都必须在第 n+1 层的节点之间访问" 的条件。

代码:

//*************************************Breadth_First_Traversal.cpp*************************************

#include "Binary_Search_Tree.h"
using namespace std;

template<class T>
void BST<T>::breadthFirst()
{
    Queue<BSTNode<T>*> queue;
    BSTNode<T> *p = root;
    if(p != 0)
    {
        queue.enqueue(p);
        while (!queue.empty())
        {
            p = queue.dequeue();
            visit(p);
            if(p->left != 0)
            {
                queue.enqueue(p->left);
            }
            if(p->right != 0)
            {
                queue.enqueue(p->right);
            }
        }
    }
}

2.深度优先遍历

深度优先遍历:

  1. 深度优先遍历是尽可能地向左(或向右)进行,在遇到第一个转折点时,向左(或向右)一步,然后,再
    尽可能地向左(或向右)发展。这一过程一直重复,直至访问了所有地节点为止。
  2. 三种遍历:
    · VLR ---- 前序树遍历          根 左 右
    · LVR ---- 中序树遍历          左 根 右
    · LRV ---- 后序树遍历          左 右 根
One:三种遍历的双递归算法

对于双递归实现,函数看起来非常的简洁。但是在简化代码的同时,也给系统带来了沉重的负担
代码:

//*************************************Depth_First_Traversal.cpp*************************************
#include"Binary_Search_Tree.h"
//双重递归来实现

template<class T>
void BST<T>::inorder(BSTNode<T>*p)          //中序遍历    左 --> 根 --> 右
{
    if(p!=0)
    {
        inorder(p->left);
        visit(p);
        inorder(p->right);
    }
}

template<class T>
void BST<T>::preorder(BSTNode<T> *p)        //先序遍历      根 --> 左 --> 右
{
    if(p!=0)
    {
        visit(p);
        preorder(p->left);
        preorder(p->right);
    }
}

template<class T>
void BST<T>::postorder(BSTNode<T> *p)        //后序遍历     左 --> 右 --> 根
{
    if(p!=0)
    {
        postorder(p->left);
        postorder(p->right);
        visit(p);
    }
}

Two:三种遍历的迭代(非递归)算法

递归的效率一般比对应非递归实现低。非递归的实现使用了许多的栈操作,因此需要编写支持函数来处理栈
非递归代码的长度可能是递归的两倍,整个实现复杂,而且虽然省去了两次递归调用但是while循环中都存在着4次调
用:两次push( ) ,一次pop( ),一次visit( )。这样来并未提高效率。

//*************************************iterativePreorder.cpp*************************************
//前序树迭代的遍历实现代码
//根  左  右
#include"Binary_Search_Tree.h"
template<class T>
void BST<T>::iterativePreorder()
{
    Stack<BSTNode<T>*> travStack;
    BSTNode<T> *p = root;
    if(p!=0)
    {
        travStack.push(p);
        while(!travStack.empty())
        {
            p = travStack.pop();
            visit(p);
            if(p->right!=0)
            {
                travStack.push(p->right);
            }
            if(p->left!=0)
            {
                travStack.push(p->left);
            }
        }
    }
}
//*************************************iterativePostorder.cpp*************************************
//后序树迭代的遍历实现代码
//左  右  根
#include"Binary_Search_Tree.h"
template<class T>
void BST<T>::iterativePostorder()
{
    Stak<BSTNode<T>*> travStack;
    BSTNode<T> *P = root;
    BSTNode<T> *q = root;
    while(p!=0)
    {
        for(;p->left != 0;p = p->left)
        {
            travStack.push(p);
        }
        while(p->right == 0 || p->right == q)
        {
            visit(p);
            q = p;
            if(travStack.empty())
            {
                return;
            }
            p = travStack.pop();
        }
        travStack.push(p);
        p = p->right;
    }
}
//*************************************iterativeInorder.cpp*************************************
//中序树迭代的遍历实现代码
//左  根  右
#include"Binary_Search_Tree.h"
template<class T>
void BST<T>::iterativeInorder()
{
    Stack<BSTNode<T>*> travStack;
    BSTNode<T> *p = root;
    while(p!=0)
    {
        while(p!=0)
        {
            if(p->right)
            {
                travStack.push(p->right);
            }
            travStack.push(p);
            p = p->left;
        }
        p = travStack.pop();
        while(!travStack.empty() && p->right == 0)
        {
            visit(p);
            p = travStack.pop();
        }
        visit(p);
        if(!travStack.empty())
        {
            p = travStack.pop();
        }
        else
        {
            p = 0;
        }
    }
}

树的非递归也很复杂。特别是对于这个其中的非递归iterativeInorder( )的代码很难去理解。由此可以看出递归代码的强大。
所以iterativeInorder( )只能在一种情况下使用:非递归实现的执行时间更短,同时函数在程序种经常调用,否则,就应该使用inorder( )双重递归,而不是非递归的代码。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值