二叉排序树的特征
二叉排序树或者是一棵空树,或者是具有如下特性的二叉树:
1.每一元素都有一个键值, 而且不允许重复;
2.若它的左子树不空,则左子树上所有结点的值均小于根结点的值;
3.若它的右子树不空,则右子树上所有结点的值均大于根结点的值;
4.它的左、右子树也都分别是二叉排序树。

二叉排序树保存的元素构造
- template <typename Type>
- class Element
- {
- public:
- Element(const Type& _key): key(_key) {}
- Element():key(0) {}
- Type key;
-
-
- };
二叉排序树节点的设计与实现
- template <typename Type>
- class BstNode
- {
- friend class BsTree;
-
- public:
- BstNode(const Element &_data = 0,
- BstNode *_leftChild = NULL,
- BstNode *_rightChild = NULL)
- : data(_data), leftChild(_leftChild), rightChild(_rightChild) {}
-
- const Type &getData() const
- {
- return data.key;
- }
-
- private:
-
- Element data;
- BstNode *leftChild;
- BstNode *rightChild;
-
- void display(int i);
- };
-
-
- template <typename Type>
- void BstNode::display(int i)
- {
-
- if (leftChild != NULL)
- leftChild->display(2*i);
-
-
-
- std::cout << "Number: " << i << ", data.key = " << data.key << std::endl;
-
-
- if (rightChild != NULL)
- rightChild->display(2*i+1);
- }
二叉排序树的构造
- template <typename Type>
- class BsTree
- {
- public:
-
- BsTree(BstNode *init = NULL): root(init) {}
- ~BsTree()
- {
- if (!isEmpty())
- makeEmpty(root);
- }
-
-
-
- bool insert(const Element &item);
-
- void remove(const Element &item)
- {
- remove(item, root);
- }
-
- const BstNode* search(const Element &item)
- {
- return search(item, root);
- }
-
- const BstNode *searchByIter(const Element &item);
-
-
- void display() const
- {
- if (root != NULL)
- root->display(1);
- }
- void visit(BstNode * currentNode) const
- {
- std::cout << "data.key = "
- << currentNode->data.key << std::endl;
- }
- bool isEmpty() const
- {
- return root == NULL;
- }
- void makeEmpty(BstNode *subTree);
-
- void levelOrder() const;
-
- private:
- const BstNode* search(const Element &item,
- const BstNode *currentNode);
- void remove(const Element &item,
- BstNode *¤tNode);
-
- private:
- BstNode *root;
- };
二叉排序树的插入算法
根据动态查找表的定义,“插入”操作在查找不成功时才进行;若二叉排序树为空树,则新插入的结点为新的根结点;否则,新插入的结点必为一个新的叶子结点,其插入位置由查找过程得到。
-
- template <typename Type>
- bool BsTree::insert(const Element &item)
- {
-
- if (root == NULL)
- {
- root = new BstNode(item);
- root->leftChild = root->rightChild = NULL;
- return true;
- }
-
- BstNode *parentNode = NULL;
- BstNode *currentNode = root;
- while (currentNode != NULL)
- {
-
- if (item.key == currentNode->data.key)
- return false;
-
- parentNode = currentNode;
-
- if (item.key < currentNode->data.key)
- currentNode = currentNode->leftChild;
- else
- currentNode = currentNode->rightChild;
- }
-
-
- if (item.key < parentNode->data.key)
- parentNode->leftChild = new BstNode(item);
- else
- parentNode->rightChild = new BstNode(item);
-
- return true;
- }
二叉排序树的查找算法
若二叉排序树为空,则查找不成功;否则:
1.若给定值等于根结点的关键字,则查找成功;
2.若给定值小于根结点的关键字,则继续在左子树上进行查找;
3.若给定值大于根结点的关键字,则继续在右子树上进行查找。
-
-
- template <typename Type>
- const BstNode* BsTree::search(const Element &item,
- const BstNode *currentNode)
- {
- if (currentNode == NULL)
- return NULL;
- if (currentNode->data.key == item.key)
- return currentNode;
-
- if (item.key < currentNode->data.key)
- return search(item, currentNode->leftChild);
- else
- return search(item, currentNode->rightChild);
- }
-
- template <typename Type>
- const BstNode *BsTree::searchByIter(const Element &item)
- {
- for (BstNode *searchNode = root;
- searchNode != NULL;
- )
- {
- if (item.key == searchNode->data.key)
- return searchNode;
-
- if (item.key < searchNode->data.key)
- searchNode = searchNode->leftChild;
- else
- searchNode = searchNode->rightChild;
- }
-
- return NULL;
- }
二叉排序树的删除算法
和插入相反,删除在查找成功之后进行,并且要求在删除二叉排序树上某个结点之后,仍然保持二叉排序树的特性。
删除分三种情况:
1.被删除的结点是叶子节点:其双亲结点中相应指针域的值改为“空”, 并将该节点删除;
2.被删除的结点只有左子树或者只有右子树:其双亲结点的相应指针域的值改为 “指向被删除结点的左子树或右子树”, 然后删除该节点;
3.被删除的结点既有左子树,也有右子树:以其前驱替代之,然后再删除该前驱结点;
-
- template <typename Type>
- void BsTree::remove(const Element &item,
- BstNode *¤tNode)
- {
- if (currentNode != NULL)
- {
-
- if (item.key < currentNode->data.key)
- remove(item, currentNode->leftChild);
-
- else if (item.key > currentNode->data.key)
- remove(item, currentNode->rightChild);
-
-
- else if ((currentNode->leftChild != NULL) && (currentNode->rightChild != NULL))
- {
-
-
-
- BstNode *tmp = currentNode->rightChild;
- while (tmp->leftChild != NULL)
- tmp = tmp->leftChild;
-
-
- currentNode->data.key = tmp->data.key;
-
- remove(currentNode->data, currentNode->rightChild);
- }
-
-
-
-
- else
- {
- BstNode *tmp = currentNode;
-
- if (currentNode->leftChild == NULL)
-
- currentNode = currentNode->rightChild;
-
- else
-
- currentNode = currentNode->leftChild;
-
- delete tmp;
- }
- }
- }
二叉查找树的几个实用操作
-
- template <typename Type>
- void BsTree::makeEmpty(BstNode *subTree)
- {
- if (subTree != NULL)
- {
- if (subTree->leftChild != NULL)
- makeEmpty(subTree->leftChild);
- if (subTree->rightChild != NULL)
- makeEmpty(subTree->rightChild);
-
- delete subTree;
- }
- }
-
- template <typename Type>
- void BsTree::levelOrder() const
- {
- std::queue< BstNode * > queue;
- queue.push(root);
-
- while (!queue.empty())
- {
- BstNode *currentNode = queue.front();
- queue.pop();
-
- visit(currentNode);
- if (currentNode->leftChild != NULL)
- queue.push(currentNode->leftChild);
- if (currentNode->rightChild != NULL)
- queue.push(currentNode->rightChild);
- }
- }
二叉排序树的性能分析
对于每一棵特定的二叉排序树,均可按照平均查找长度的定义来求它的 ASL 值,显然,由值相同的 n 个关键字,构造所得的不同形态的各棵二叉排序树的平均查找长度的值不同,甚至可能差别很大(如果二叉查找树退化成一条链表, 则其插入/删除/查找的性能都会退化为O(N))。
但是在随机情况下, 二叉排序树的搜索, 插入, 删除操作的平均时间代价为O(logN);