数据结构练手04 二叉树之链表实现

晚上和朋友出去小饮了几杯,调侃了下blablabla。。。现在有点晕乎乎的,文章可能很凌乱,算是很抱歉。

下午实现了下链表形式的二叉树,顿时感觉数据结构的实现,理论和实际的差距还是很大的。要走的路还是很长远的。总结下,就是递归很重要,这个是解决树问题的核心钥匙!

对于二叉树,很多实现是基于排序二叉树的线性表示,即可以根据父节点的索引直接定位到子节点的位置,即 parent*2 = leftChild, parent*2+1=rightChild等等,一切可以用公式表示。

本文,我们采用指针形式来实现。

每个数据结构的实现,首要是实现结点类的设计。根据需求,我们知道它有三个指针域,分别指向父节点,左结点,右结点,还有一个数据域。另外需要个性化一些构造函数,满足不同的需求。

 1 template <class T>
 2 struct bNode{
 3     T datum;
 4     bNode<T>* left;
 5     bNode<T>* right;
 6     bNode<T>* parent;
 7     bNode() : datum(0),left(NULL),right(NULL),parent(NULL){}
 8     bNode(const T& x) : datum(x), left(NULL), right(NULL),parent(NULL){}
 9     ~bNode(){left = NULL; right = NULL; parent = NULL;}
10 };

实现完结点结构后,后序的工作是需要定制二叉树类。根据需求,一般来说要实现:查找,插入,删除,遍历,求长度,深度,长度等操作。同时,很重要的是要有一个结点类的head指针提供数据访问的接口。我们把类设计如下:

template<class T>
class BiTree{
    protected:
        bNode<T>* head;    // 头结点,它的右结点指向根节点
        int totalSize;
        bool _search(const T& x, bNode<T>* n) const;  // 内部接口。
    public:

        BiTree() : totalSize(0) {head = new bNode<T>();}
        ~BiTree();
        void clear();
        void init(const T array[], int len, bNode<T>* n = NULL, int beg=1);   // 根据数组来初始化一个满二叉树

        void preOrder(const bNode<T>* node) const;                     // 遍历次序
        void inOrder(const bNode<T>* node) const;
        void postOrder(const bNode<T>* node) const;
        void preOrder() const;
        void inOrder() const;
        void postOrder() const;


        bNode<T>*& root() const { return head->right;}    // 这里为啥要返回一个指针的引用呢?
        bNode<T>* insert(bNode<T>* &node, const T& x, INSERTTYPE t = RIGHT);   // 左插or右插
        BiTree<T>& erase(bNode<T>* &node, T& carry);
        
        bool search(const T& x) const;   // 调用内部_search接口,默认从根结点开始

        int size(bNode<T>*) const;
        bool isEmpty(){return size==0;}
        int depth(bNode<T>* node) const;
        int height(bNode<T>* node) const;
};

其中有七个地方用到了递归,分别是三个遍历,两个求长度、高度,搜索,还有个初始化:

template<class T>
void BiTree<T>::init( const T array[], int len, bNode<T>* n, int beg)
{    
    if (n == NULL)
        n = head;
    bNode<T>* p=NULL;
    if(beg<=len){
        if(beg % 2 == 0){    // 要是左结点,则左插,并且递归调用
            p = insert(n, array[beg-1],LEFT);
            init(array, len, p, 2*beg);  // 递归到左结点
            init(array, len, p, 2*beg+1);// 递归到右结点
        }else{            // 右结点,同时递归调用
            p = insert(n, array[beg-1], RIGHT);
            init(array, len, p, 2*beg);
            init(array, len, p, 2*beg+1);
        }
    }
}


template<class T>
BiTree<T>::~BiTree()
{
    clear();
    delete head;
}

template<typename T>
void BiTree<T>::clear()       // 销毁一棵树
{
    T tmp;
    int s = totalSize;
    for(int i=0; i<s; ++i){
        erase(root(),tmp);
    }
}

template<class T>
bool BiTree<T>::_search(const T& x, bNode<T>* n) const    
{
    if(n == NULL) return false;
    if(n->datum == x) return true;
    return _search(x,n->left) || _search(x,n->right);    递归搜索左右结点
}

template<class T>
bool BiTree<T>::search(const T& x) const    // 调用内部接口,默认从根结点开始
{
    return _search(x, root());
}

template<typename T>
bNode<T>* BiTree<T>::insert(bNode<T>* &node, const T& x, INSERTTYPE t /* = INSERTTYPE::RIGHT */)    // 插入到某结点的左or右
{
    bNode<T>* inode = new bNode<T>(x);
    if( t == INSERTTYPE::LEFT){
        inode->left = node->left;
        if(node->left != NULL)
            node->left->parent = inode;
        node->left = inode;
    }
    if( t == INSERTTYPE::RIGHT){
        inode->right = node->right;
        if(node->right != NULL)
            node->right->parent = inode;
        node->right = inode;
    }
    inode->parent = node;
    ++totalSize;
    return inode;
}
template<typename T>   // 用到了一个技巧,就是交换欲销毁结点和某个子孙叶结点的值,然后销毁该子孙结点,这样树结构基本不变
BiTree<T>& BiTree<T>::erase(bNode<T>* &node, T& carry)
{
    carry = node->datum;
    bNode<T>* p = node;
    while(p && ((p->left != NULL) || (p->right != NULL))){
        if(p->left != NULL){
            p = p->left;
            continue;
        }
        if(p->right != NULL){
            p = p->right;
        }
    }
    node->datum = p->datum;
    if(p == p->parent->left){
        p->parent->left = NULL;
    }else{
        p->parent->right = NULL;
    }
    delete p;
    --totalSize;
    return *this;
}

template<class T>   // 某个结点的大小
int BiTree<T>::size(bNode<T>* node) const
{
    if (node !=NULL)
        return 1 + size(node->left)+size(node->right);
    return 0;
}
template<class T>   // 深度
int BiTree<T>::depth(bNode<T>* node) const
{
    int dep = 0;

    while(node!=root()){
        dep++;
        node = node->parent;
    }
    return dep;
}
template<class T>   // 高度
int BiTree<T>::height(bNode<T>* node) const
{
    if (((node != NULL) && (node->left == NULL) && (node->right == NULL))
        || (node == NULL)) {
        return 0;
    }
    return 1 + ::max(height(node->left), height(node->right));
}
template<typename T>   //先序
void BiTree<T>::preOrder(const bNode<T>* node) const
{
    if(node != NULL){
        cout << node->datum << " ";  //根
        preOrder (node->left);   // 左结点
        preOrder (node->right);   //右结点
 } } template
<typename T> void BiTree<T>::preOrder() const { preOrder(root()); cout << endl; } //中序 template<typename T> void BiTree<T>::inOrder(const bNode<T>* node) const { if(node != NULL){ inOrder (node->left); cout << node->datum << " "; inOrder (node->right); } } template<typename T> void BiTree<T>::inOrder() const { inOrder(root()); cout << endl; } // 后序 template<typename T> void BiTree<T>::postOrder(const bNode<T>* node) const { if(node != NULL){ postOrder (node->left); postOrder (node->right); cout << node->datum << " "; } } template<typename T> void BiTree<T>::postOrder() const { postOrder(root()); cout << endl; }

测试代码如下:

 1 #include <iostream>
 2 #include "biTree.h"
 3 using namespace std;
 4 int main()
 5 {
 6     BiTree<int> btree;
 7     int a[10];
 8     for(int i=0; i<10; ++i){
 9         a[i] = i+1;
10     }
11     btree.init(a,10);
12     cout << "preorder: ";
13     btree.preOrder ();
14     cout << "inorder: ";
15     btree.inOrder();
16     cout << "postorder: ";
17     btree.postOrder();
18     cout << "size of root is " << btree.size(btree.root())<< endl;
19     cout << "depth of root is " << btree.depth(btree.root())<< endl;
20     cout << "height of root is " << btree.height(btree.root()) << endl;
21     cout << "is 40 exist? " << btree.search(40) << endl;
22     cout << "is 6 exist " << btree.search(6) << endl;
23 }

posted @ 2013-05-26 23:04  xield  阅读(373)  评论(0编辑  收藏  举报