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
- C++数据结构: 二叉搜索树 (非递归)
- 数据结构之搜索二叉树递归&非递归
- 【数据结构】二叉搜索树的递归与非递归实现
- 数据结构(二)二叉搜索树-非递归实现遍历
- C语言数据结构实现二叉树递归与非递归遍历(数据结构第四次实验)
- 二叉搜索树(非递归)
- 二叉搜索树-非递归
- 数据结构——排序/搜索二叉树(非递归)的基本操作实现
- 【c++】二叉搜索树的插入、查找、非递归删除
- 二叉搜索树(递归和非递归分别实现)
- C++实现二叉搜索树(递归&非递归)
- 二叉搜索树---递归及非递归
- (C语言)二叉树非递归后序(数据结构十五)
- 数据结构之二叉树遍历(递归和非递归)
- 数据结构-二叉树(包含递归和非递归版本)
- 【数据结构】二叉树的遍历(递归与非递归)
- 数据结构与算法分析学习笔记--第四章(搜索二叉树,递归和非递归实现删除、插入)
- 【数据结构】搜索二叉树的(递归与非递归)实现,包括:增Insert,删Remove,查Find
- 内核线程 http://blog.chinaunix.net/uid-24467128-id-3246495.html
- fio
- javascript以及jquery的学习
- JAVA基础知识回顾(基本数据类型,switch参数,equals与==的区别,Object有哪些公用方法)-1
- C/C++代码命名和格式规范
- C++数据结构: 二叉搜索树 (非递归)
- 一对多查询 只显示一条数据 数据合并
- Android调用短信和播放声音源码
- STL: bind1st, bind2nd 的使用(C++)
- input type = "range"滑块和output的使用
- 泄密事件不断 内网安全该如何保障?
- 解决:502 bad gateway
- 【C++】迷宫
- Web缓存