C++数据结构: 二叉搜索树 (非递归)

来源:互联网 发布:php rsa加密解密 编辑:程序博客网 时间:2024/05/21 06:46

理想情况下BST的插入删除查找花费的时间都是对数级别的,但我们肯定不能依赖“理想情况”。基于下面3个理由:
1. 很多时候输入得序列都是有序或基本有序的
2. 访问一个节点过后很可能再次访问这个节点,或者这个节点附近的节点。
3. 多次删除过后会破坏树的平衡性(可以改变一下删除方式来解决,但是这样的代价比较大)

而BST在最差的请况下会退化成一个链表,这显然不是我们想要的结果。所以感觉BST的实际效用不大!

之前写BST是用的Java的递归算法,这次用C++实现,我就选择了非递归算法。非递归实现的原理不难,但实现起来总有很多细节需要注意。特别是对于C++!

实现简述:
1. 先说说插入吧,插入的关键(至少我认为)是找到插入位置的父节点。就和链表一样,不是吗?所以,要插入一个节点,实际上是要操作该节点的父节点。
2. 删除实现起来比插入麻烦多了,3种情况:

a. 要删除的节点没有子节点。
b. 要删除的节点只有一个子节点
c. 要删除的节点有两个子节点

想象一下前两种情况,这不就是链表的删除操作吗?!!!
同插入操作一样,要删除一个节点,我们实际上是要操作该节点的父节点。需要注意的是,根节点没有父亲(链表头结点也没有前驱),所以实现的时候要考虑根节点的情况。

最后一种情况,要删除一个拥有2个子树的节点比较复杂。转换一下思路,用该节点的后继(或前驱)替换该节点,然后删除该节点的后继(或前驱)。

3.拷贝构造函数,这是我觉得我写的最好的一个函数。用的是递归的方式。注释里有说明。

#ifndef BST_H#define BST_H#include <iostream>using namespace std;template <typename K, typename V>class BSTNode//节点类{public:    K key;    V value;    BSTNode *left;    BSTNode *right;    BSTNode(const K &k, const V &v, BSTNode *lft = nullptr, BSTNode *rht = nullptr) :        key(k), value(v), left(lft), right(rht) {}};template <typename K, typename V>class BST{public:    BST() :size(0), root(nullptr) {}    BST(const BST &b);    //析构函数,逆序删除BST    ~BST()    {        postOrder(deleteNode);        root = nullptr;        size = 0;    }    bool isEmpty() const { return size == 0; };    unsigned getSize() const { return size; }    void insert(const K &k, const V &v);    bool remove(const K &k);    BSTNode<K, V> *get(const K &k);    bool set(const K &k, const V &v);    BSTNode<K, V>* findMin(BSTNode<K, V> *t);//返回以t为根节点的BST中的最小元素    void postPrint();//后序遍历打印    void postOrder(void(*visit)(BSTNode<K, V>*))//以visit方式后序遍历BST,是另一个postOrder的驱动程序    {        this->visit = visit;        postOrder(root);    }protected:    BSTNode<K, V> *root;//根节点    unsigned int size;//BST中的节点数量    void postOrder(BSTNode<K, V> *t);//后序遍历,实现函数    void(*visit)(BSTNode<K, V>*);      //函数指针,结合遍历对树进行操作。    static void deleteNode(BSTNode<K, V> *t)    {delete t;}    static void output(BSTNode<K, V>* t)    {cout << t->value << ' ';}    BSTNode<K, V> *createNode(BSTNode<K, V> *t);//配合下一个函数使用,创建新节点    void copyNode(BSTNode<K, V> *father, BSTNode<K, V> *t);//拷贝构造函数用来拷贝一个节点};template<typename K, typename V>BST<K, V>::BST(const BST &b):size(0), root(nullptr){    if (!b.isEmpty())    {        size = b.size;        root = new BSTNode<K, V>(b.root->key, b.root->value, nullptr, nullptr);        copyNode(root, b.root);    }}template<typename K, typename V>//O(N)void BST<K, V>::insert(const K & k, const V & v){    if (root == nullptr)        root = new BSTNode<K, V>(k, v, nullptr, nullptr);    else {//寻找正确的位置,以及该位置的父节点        BSTNode<K, V> *t = root, *father = nullptr;        while (t != nullptr)        {            father = t;//t节点的父节点            if (k < t->key)                t = t->left;            else if (k > t->key)                t = t->right;            else {                t->value = v;//覆盖                return;//小心别陷入死循环,并且这里size不递增            }        }        BSTNode<K, V> *newNode = new BSTNode<K, V>(k, v, nullptr, nullptr);        if (k < father->key)//添加节点            father->left = newNode;        else            father->right = newNode;    }    ++size;}template<typename K, typename V>//O(N)BSTNode<K, V>* BST<K, V>::findMin(BSTNode<K, V>* t){    if (t == nullptr)        return nullptr;    while (t->left != nullptr)        t = t->left;    return t;}template<typename K, typename V>//O(N)bool BST<K, V>::remove(const K & k){    BSTNode<K, V> *t = root, *father = nullptr;    while (t != nullptr)    {        father = t;//t节点的父节点        if (k < t->key)            t = t->left;        else if (k > t->key)            t = t->right;        if (t != nullptr && k == t->key)//注意这里t可能为nullptr            if (t->left == nullptr || t->right == nullptr)            {                //newSon为t的非空子树,father为t的父亲。newSon将接替t成为father的子树。                BSTNode<K, V> *newSon = (t->left == nullptr ? t->right : t->left);                if (k == root->key)                    root = newSon;//root特殊,相当于链表的头结点,此时它的father就是它。                else if (t->key > father->key)                    father->right = newSon;                else if (t->key < father->key)                    father->left = newSon;                delete t;                --size;                return true;//删除成功            }            else {                K minNodeKey = findMin(t->right)->key;                V minNodeVal = findMin(t->right)->value;                bool flag = remove(minNodeKey);//先删除,再赋值                t->key = minNodeKey;                t->value = minNodeVal;                return flag;//删除成功            }    }    return false;//没有元素k,删除失败}template<typename K, typename V>//O(N)BSTNode<K, V> *BST<K, V>::get(const K & k){    BSTNode<K, V> *t = root;    while (t != nullptr && t->key != k)    {        if (k < t->key)            t = t->left;        else if (k > t->key)            t = t->right;    }    return t;}template<typename K, typename V>//O(N)设置成功返回true,否则false.bool BST<K, V>::set(const K &k, const V &v){    BSTNode<K, V> *t = root;    while (t != nullptr && t->key != k)    {        if (k < t->key)            t = t->left;        else if (k > t->key)            t = t->right;    }    if (t != nullptr)    {        t->value = v;        return true;    }    return false;}template<typename K, typename V>//O(N)void BST<K, V>::postPrint(){    if (!isEmpty())    {        postOrder(output);        cout << endl;    }    else        cout << "Empty Tree!" << endl;}template<typename K, typename V>//O(N)逆序以visit方式访问void BST<K, V>::postOrder(BSTNode<K, V> *t){    if (t != nullptr)    {        postOrder(t->left);        postOrder(t->right);        visit(t);    }}template<typename K, typename V>//创建一个没有子树的新节点。BSTNode<K, V> *BST<K, V>::createNode(BSTNode<K, V> *t){    if (t == nullptr)        return nullptr;    return new BSTNode<K, V>(t->key, t->value, nullptr, nullptr);}template<typename K, typename V>//O(N)递归拷贝void BST<K, V>::copyNode(BSTNode<K, V> *father, BSTNode<K, V> *t){    if (t == nullptr)//基准情况,确保拷贝空树或者访问空节点的情况下能返回。        return;    BSTNode<K, V> *leftChild = createNode(t->left);//1.创建子节点的数据域    BSTNode<K, V> *rightChild = createNode(t->right);    father->left = leftChild;//2.创建父节点的子节点    father->right = rightChild;    copyNode(leftChild, t->left);//3.递归。本轮中的子节点将成为下一轮的父节点,然后重复步骤1、2    copyNode(rightChild, t->right);}#endif
0 0
原创粉丝点击