C++ 二叉查找树的实现

 

最近在找工作,复习了下二叉树。 这里用C++重复制造了一个二叉树的轮子和大家分享下。

    本文章是对代码的解释, 源码的贴出放在最后。

在阅读本片代码的时候注意一下几点:

# 用了泛型技术:templeate <class T>

# const 引用 (C++程序员装B必备)

在阅读代码的时候可能会不太习惯。

1. 二叉搜索树的结构

    一个二叉树的如果不为空便是由一个根节点和左右两个只树构成。

    二叉搜索树可以提供对数时间的插入和访问,其节点的放置规则是:任何一个节点的键值一定大于其左树节点的键值,而且小于其右树节点的值。

    所以我们可以定义如下的节点:

 

 1 template <class T>
 2  struct BinaryNode
 3 {
 4     T                element;
 5     BinaryNode        *left;
 6     BinaryNode        *right;
 7     BinaryNode(const T& theElement,
 8         BinaryNode *lt,
 9         BinaryNode *rt):
10     element(theElement),
11         left(lt),
12         right(rt)
13     {
14     }
15 };

复制代码

 

element 表示节点的键值;

left 表示指向左树节点的指针

right表示指向右树节点的指针

2. 二叉搜索树类的属性、方法

    在这里, 这个树类提供了如下几个方法: findMin();findMax();contains();makeEmpty();insert();remove();printTree(); 我们可以先来看下这个类的定义:

 

 1 template <class T>
 2  class BinarySearchTree
 3 {
 4  private:
 5     BinaryNode<T>            *m_root;
 6  public:
 7     BinarySearchTree();
 8     BinarySearchTree(const BinarySearchTree& rhs);
 9     ~BinarySearchTree();
10     const T& findMin() const;
11     const T& findMax() const;
12     bool contains(const T& x) const;
13     void printTree(ORDER_MODE eOrderMode = ORDER_MODE_PREV) const;
14     void makeEmpty();
15     void insert(const T& x);
16     void remove(const T& x);
17  private:
18     //因为树的方法用到了很多递归, 所以这里我们需要申明如下的私有成员函数
19      void insert(const T& x, BinaryNode<T>* &t) ;
20     void remove(const T& x, BinaryNode<T>* &t) ;
21     BinaryNode<T>* findMin( BinaryNode<T>* t) const;
22     BinaryNode<T>* findMax( BinaryNode<T>* t) const;
23     bool contains(const T& x, const BinaryNode<T>* t) const;
24     void makeEmpty(BinaryNode<T>* t);
25     void printTreeInPrev(BinaryNode<T>* t) const;
26     void printTreeInMid(BinaryNode<T>* t)const;
27     void printTreeInPost(BinaryNode<T>* t)const;
28 };

复制代码

 

    这里解释下为什么要重载这么多私有的成员函数。因为树的方法用到了很多递归, 所以这里我们需要重载这些私有成员函数,当我们写代码的时候,我们便可以这样做:

 

 1 template <class T>
 2  bool  BinarySearchTree<T>::contains(const T& x) const
 3 {
 4     return contains(x, m_root);
 5 }
 6 template <class T>
 7  bool BinarySearchTree<T>::contains(const T& x, const BinaryNode<T>* t) const
 8 {
 9     这里调用自己
10 }

复制代码

 

    下面解释各个方法的具体实现。

3.BinarySearchTree的构造、析构以及拷贝构造函数

    类BinarySearchTree的构造、析构以及拷贝构造函数没什么特殊的地方。实现如下:

 

 1 template <class T>
 2 BinarySearchTree<T>::BinarySearchTree()
 3 {
 4     m_root = NULL;
 5 }
 6 template <class T>
 7 BinarySearchTree<T>:: BinarySearchTree(const BinarySearchTree& rhs)
 8 {
 9     m_root = rhs.m_root;
10 }
11 template <class T>
12 BinarySearchTree<T>:: ~BinarySearchTree()
13 {
14     makeEmpty();
15 }

复制代码

 

4. BinarySearchTree::contains(X)

    此方法判断函数树是不是包含元素X. 可以看下具体实现:

 

 1 // return true if the x is found in the tree
 2  template <class T>
 3  bool  BinarySearchTree<T>::contains(const T& x) const
 4 {
 5     return contains(x, m_root);
 6 }
 7 template <class T>
 8  bool BinarySearchTree<T>::contains(const T& x, const BinaryNode<T>* t) const
 9 {
10     if (!t)
11         return false;
12     else if (x < t->element)
13         return contains(x, t->left);
14     else if (x > t->element)
15         return contains(x, t->right);
16     else
17         return true;
18 }

复制代码

 

5. BinarySearchTree::makeEmpty()

    清空这个树。

 

 1 template <class T>
 2  void  BinarySearchTree<T>::makeEmpty()
 3 {
 4     makeEmpty(m_root);
 5 }
 6 template <class T>
 7 void  BinarySearchTree<T>::makeEmpty(BinaryNode<T>* &t)
 8 {
 9     if (t)
10     {
11         makeEmpty(t->left);
12         makeEmpty(t->right);
13         delete t;
14     }
15     t = NULL;
16 }

复制代码

 

    实现非常简单,就是遍历整颗树,delete BinaryNode, 这里需要注意的一点是makeEmpty的参数是一个指针的引用:BinaryNode<T>* &t 

6. BinarySearchTree::findMax() & BinarySearchTree::findMin().

    findMax 和findMin的实现就是遍历树,比较相关的元素:

 

 1 template <class T>
 2 BinaryNode<T>* BinarySearchTree<T>::findMax( BinaryNode<T>* t) const
 3 {
 4     //二叉树的一个特点就是左子叶的值比根节点小, 右子叶的比根节点的大
 5     if (t != NULL)
 6         while (t->right != NULL)
 7             t = t->right;
 8     return t;
 9 }
10 template <class T>
11 BinaryNode<T>* BinarySearchTree<T>::findMin( BinaryNode<T>* t) const
12 {
13     //二叉树的一个特点就是左子叶的值比根节点小, 右子叶的比根节点的大
14     if (!t)
15         return NULL;
16     if (t->left == NULL)
17         return t;
18     else
19         return findMin(t->left);
20 }

复制代码

 

7. BinarySearchTree的插入和删除

    二叉树的插入比较简单, 只要循环得比较某一直,如果此值比根节点的值小,插入左子树,如果大插入右子树,如果相等,什么也不做

 

 1 template <class T>
 2 void BinarySearchTree<T>::insert(const T& x, BinaryNode<T>* &t)
 3 {
 4     if (t == NULL)
 5         t = new BinaryNode<T>(x, NULL, NULL);//注意这个指针参数是引用
 6     else if (x < t->element)
 7         insert(x, t->left);
 8     else if (x > t->element)
 9         insert(x, t->right);
10     else
11         ;//do nothing
12 }

复制代码

 

    二叉树的删除就比较复杂了,我们先得判断这个需要删除的节点有几个之节点,以及考虑到删除这个节点后其子节点引起的连锁反应。

 

 1 template <class T>
 2 void BinarySearchTree<T>::remove(const T& x, BinaryNode<T>* &t)
 3 {
 4     if (t == NULL)
 5         return;
 6     if (x < t->element)
 7         remove(x, t->left);
 8     else if (x > t->element)
 9         remove (x, t->right);
10     else // now ==
11     {
12         if (t->left != NULL &&
13             t->right != NULL)//two child
14         {
15             t->element = findMin(t->right)->element;
16             remove(t->element, t->right);
17         }
18         else
19         {
20             BinaryNode<T> *oldNode = t;
21             t = (t->left != NULL) ? t->left : t->right;
22             delete oldNode;
23         }
24     }
25 }

复制代码

 

    这里实现的方法就是先拿出右树的最小值填充当前节点,以后节点依次干这件事情,然后删除最后的节点。

8. BinarySearchTree的遍历输出

    二叉树的遍历有三种:前序,中序,后序。

        前序遍历的规律是:输出根结点,输出左子树,输出右子树; 
        中序遍历的规律是:输出左子树,输出根结点,输出右子树;
        后序遍历的规律是:输出左子树,输出右子树,输出根结点;

    在这里我先定义了一个枚举来表示着三种类型的遍历方式:

 

1 enum ORDER_MODE
2 {
3     ORDER_MODE_PREV = 0,
4     ORDER_MODE_MID,
5     ORDER_MODE_POST
6 };

复制代码

 

然后分别实现遍历:

 

代码

 1 //Print tree
 2  template <class T>
 3  void BinarySearchTree<T>::printTree(ORDER_MODE eOrderMode /*= ORDER_MODE_PREV*/) const
 4 {
 5     if (ORDER_MODE_PREV == eOrderMode)
 6          printTreeInPrev(m_root);
 7     else if (ORDER_MODE_MID == eOrderMode)
 8          printTreeInMid(m_root);
 9     else if (ORDER_MODE_POST == eOrderMode)
10          printTreeInPost(m_root);
11     else
12         ;//do nothing
13  }
14 template <class T>
15  void BinarySearchTree<T>::printTreeInPrev(BinaryNode<T>* t) const
16 {
17     if (t)
18     {
19         cout << t->element;
20         printTreeInPrev(t->left);
21         printTreeInPrev(t->right);
22     }
23 }
24 template <class T>
25  void BinarySearchTree<T>::printTreeInMid(BinaryNode<T>* t) const
26 {
27     if (t)
28     {
29         printTreeInPrev(t->left);
30         cout << t->element;
31         printTreeInPrev(t->right);
32     }
33 }
34 template <class T>
35  void BinarySearchTree<T>::printTreeInPost(BinaryNode<T>* t) const
36 {
37     if (t)
38     {
39         printTreeInPost(t->left);
40         printTreeInPost(t->right);
41         cout << t->element;
42     }
43 }

复制代码

 

 

到此这个类的介绍,就完毕了, 下面可以敲下如下的测试代码:

 

代码

 1 #include "stdafx.h"
 2 #include "BinarySearchTree.h"
 3
 4
 5  int _tmain(int argc, _TCHAR* argv[])
 6 {
 7     BinarySearchTree<int> binaryTree;
 8     binaryTree.insert(5);
 9     binaryTree.insert(1);
10     binaryTree.insert(2);
11     binaryTree.insert(3);
12     binaryTree.insert(6);
13     binaryTree.insert(8);
14     bool b = binaryTree.contains(1);
15     int x = binaryTree.findMin();
16     cout << b << " "<< x <<endl;
17     x = binaryTree.findMax();
18     cout << x <<endl;
19     binaryTree.remove(2);
20     binaryTree.printTree(ORDER_MODE_PREV);
21     cout <<endl;
22     binaryTree.printTree(ORDER_MODE_MID);
23     cout <<endl;
24     binaryTree.printTree(ORDER_MODE_POST);
25     cout <<endl;
26     return 0;
27 }
28  

复制代码

 

文字转载来源: http://www.cnblogs.com/sld666666/archive/2010/10/23/1859512.html
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值