您的位置:首页 > 理论基础 > 数据结构算法

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.拷贝构造函数,这是我觉得我写的最好的一个函数。用的是递归的方式。注释里有说明。

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: