C++数据结构: 二叉搜索树 (非递归)
2015-11-17 14:10
537 查看
理想情况下BST的插入删除查找花费的时间都是对数级别的,但我们肯定不能依赖“理想情况”。基于下面3个理由:
1. 很多时候输入得序列都是有序或基本有序的
2. 访问一个节点过后很可能再次访问这个节点,或者这个节点附近的节点。
3. 多次删除过后会破坏树的平衡性(可以改变一下删除方式来解决,但是这样的代价比较大)
而BST在最差的请况下会退化成一个链表,这显然不是我们想要的结果。所以感觉BST的实际效用不大!
之前写BST是用的Java的递归算法,这次用C++实现,我就选择了非递归算法。非递归实现的原理不难,但实现起来总有很多细节需要注意。特别是对于C++!
实现简述:
1. 先说说插入吧,插入的关键(至少我认为)是找到插入位置的父节点。就和链表一样,不是吗?所以,要插入一个节点,实际上是要操作该节点的父节点。
2. 删除实现起来比插入麻烦多了,3种情况:
a. 要删除的节点没有子节点。
b. 要删除的节点只有一个子节点
c. 要删除的节点有两个子节点
想象一下前两种情况,这不就是链表的删除操作吗?!!!
同插入操作一样,要删除一个节点,我们实际上是要操作该节点的父节点。需要注意的是,根节点没有父亲(链表头结点也没有前驱),所以实现的时候要考虑根节点的情况。
最后一种情况,要删除一个拥有2个子树的节点比较复杂。转换一下思路,用该节点的后继(或前驱)替换该节点,然后删除该节点的后继(或前驱)。
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
相关文章推荐
- 数据结构(Java)——列表的实现
- python 数据结构-元组
- 数据结构中的List、Set、Map用法以及区别
- python 数据结构之-列表
- Redis数据结构
- 小白学算法1.2——链表
- 字典
- 数据结构、算法与应用 (C++描述) 第二版 1.25
- 数据结构--二叉搜索树(java)
- .Net数据结构:CollectionBase
- Redis数据结构详解(一)
- 数据结构、算法与应用 (C++描述) 第二版 1.24
- 数据结构、算法与应用 (C++描述) 第二版 1.23
- 数据结构、算法与应用 (C++描述) 第二版 1.22
- 数据结构(Java)——队列的实例
- 数据结构--队列(java)
- 数据结构、算法与应用 (C++描述) 第二版 1.21
- 数据结构、算法与应用(C++描述) 第二版 1.20
- C++ 数据结构 *** 普通链表
- 数据结构、算法与应用 (C++描述) 第二版 1.19