《算法导论》— Chapter 12 二叉查找树
2015-07-08 21:33
309 查看
序
查找树是一种数据结构,它支持多种动态集合操作,包括Search、Minimum、Maximum、PreDecessor、Successor、Insert、Delete等。它既可以用作字典,也可以用作优先级队列;在二叉查找树(Binary Search Tree)上执行基本操作的时间与树的高度成正比,对于一颗含有n个结点的完全二叉树,基本操作的最坏情况运行时间为floor(logn)。本章讨论二叉查找树的基本性质以及上面提及的基本操作的实现。
GitHub 程序实现代码
1 二叉查找树
1.1 性质
如下图所示,一颗二叉查找树是按照二叉树结构来组织的。这样的树一般用链表结构表示,每一个结点是一个对象,包含关键字key、父亲结点parent、左儿子结点left以及右儿子结点right四个属性。明显的,对于二叉查找树中关键字的存储方式总是满足这样的性质:
设x为二叉查找树中的一个结点,如果y是x左子树中的一个结点,则y−>key<=x−>key,如果y是x右子树中的一个结点,则y−>key>=x−>key。
1.2 基本操作
1.2.1 遍历
根据二叉查找树的性质,可以用一个递归算法按照排列顺序依次输出所有关键字,这就是中序遍历,遍历顺序为根、左子树、右子树。同样的,有前序遍历,根的关键字在左右子树之前输出;后序遍历,根的关键字在其左右子树之后输出。1.2.2 查找
对于二叉查找树,最常见的操作就是查找树中的某个关键字。查找操作同样采用递归的形式实现,其复杂度等于树的高度。操作过程如下图所示:
1.2.3 求最大、最小关键字
对于用作优先级队列的结构,求最大最小关键字是必不可少的操作。要查找二叉查找树中的最小关键字,根据树的性质,只要从根节点开始,沿着各个结点的left指针查找下去,直到遇到NULL为止。
同理,要查找二叉查找树中的最大关键字,根据树的性质,只要从根节点开始,沿着各个结点的right指针查找下去,直到遇到NULL为止。
这两个操作的运行时间都是O(h)。
1.2.4 求前驱、后继
我们知道,中序遍历二叉查找树得到的是一组有序序列,有时候需要求指定结点的前驱与后继。对于给定结点x的后继结点是具有大于或等于x−>key中关键字的最小结点;同理,对于给定结点x的前驱结点是具有小于x−>key中关键字的最大结点。根据二叉查找树的性质,不用对关键字做任何比较就可以得到给定结点的前驱和后继结点。1.2.5 插入
插入和删除操作会引起整个二叉查找树表示的集合的动态变化。要反应出这种变化,就要修改数据结构,但是在修改的同时,还要保持整棵树的性质不变。将新值插入到一颗二叉查找树中的过程如下:
1.2.6 删除
相对于插入操作,删除更加复杂一些,下图详细展示了删除不同结点需要的步骤:对高度为h的二叉查找树,动态集合操作Insert与Delete的运行时间都是O(n)。
2 二叉查找树程序实现
下面给出的程序实现,包括了所有以上提及的基本操作:(1)BinarySearchTree.h
#ifndef _BINARYSEARCHTREE_H_ #define _BINARYSEARCHTREE_H_ #include <iostream> typedef struct BSTNode{ BSTNode *left; BSTNode *right; BSTNode *parent; int key; BSTNode(int data) : left(NULL), right(NULL), parent(NULL), key(data){} }; class BinarySearchTree{ public: BinarySearchTree(); ~BinarySearchTree(); //插入删除操作 void Insert(int data); BSTNode *Delete(int data); BSTNode *root; }; //查找操作 BSTNode *Search(BSTNode * node, int data); //遍历操作 void InOrderWalk(BSTNode * node); void PreOrderWalk(BSTNode * node); void PostOrderWalk(BSTNode * node); //查询最大最小值 BSTNode *Maximum(BSTNode * node); BSTNode *Minimum(BSTNode * node); //查找前驱与后继 BSTNode *PreDecessor(BSTNode *node); BSTNode *Successor(BSTNode *node); #endif
(2)BinarySearchTree.cpp
#include "BinarySearchTree.h" #include <iostream> BinarySearchTree::BinarySearchTree() { root = NULL; } BinarySearchTree::~BinarySearchTree() { delete root; } //向二分查找树中插入数据data void BinarySearchTree::Insert(int data) { BSTNode *node = new BSTNode(data); BSTNode *p = root, *q = NULL; while (p != NULL) { q = p; if (p->key > data) p = p->left; else p = p->right; } node->parent = q; if (q == NULL) root = node; else if (q->key > data) q->left = node; else q->right = node; } //从二分查找树中删除数据 BSTNode *BinarySearchTree::Delete(int data) { BSTNode *node = Search(root, data); BSTNode *ret , *tmp; if (node == NULL) return node; //如果目标结点只有一个子女则删除该结点,否则删除其后继结点 if (node->left == NULL || node->right == NULL) ret = node; else ret = Successor(node); //如果被删结点有左右孩子,将其链接到被删结点的父节点 if (ret->left != NULL) tmp = ret->left; else tmp = ret->right; if (tmp != NULL) tmp->parent = ret->parent; //如果被删结点的父节点为空,则说明要删的是根节点 if (ret->parent == NULL) root = tmp; else if (ret == ret->parent->left) ret->parent->left = tmp; else ret->parent->right = tmp; if (ret != node) node->key = ret->key; return ret; } //查找以node结点为根的子树中值为data的结点 BSTNode *Search(BSTNode * node, int data) { if (node == NULL || node->key == data) return node; if (data < node->key) return Search(node->left, data); else return Search(node->right, data); } //遍历操作 void InOrderWalk(BSTNode * node) { if (node != NULL) { InOrderWalk(node->left); std::cout << node->key << "\t"; InOrderWalk(node->right); } } void PreOrderWalk(BSTNode * node) { if (node != NULL) { std::cout << node->key << "\t"; InOrderWalk(node->left); InOrderWalk(node->right); } } void PostOrderWalk(BSTNode * node) { InOrderWalk(node->left); InOrderWalk(node->right); std::cout << node->key << "\t"; } //查询最大最小值 BSTNode *Maximum(BSTNode * node) { while (node->left != NULL) node = node->left; return node; } BSTNode *Minimum(BSTNode * node) { while (node->right != NULL) node = node->right; return node; } //查找前驱与后继 BSTNode *PreDecessor(BSTNode *node) { if (node->left != NULL) return Maximum(node->left); BSTNode *p = node->parent; while (p != NULL && node == p->left) { node = p; p = node->parent; } return p; } BSTNode *Successor(BSTNode *node) { if (node->right != NULL) return Minimum(node->right); BSTNode *p = node->parent; while (p != NULL && node == p->right) { node = p; p = node->parent; } return p; }
(3)main.cpp
#include "BinarySearchTree.h" #include <iostream> #include <cstdlib> #include <ctime> using namespace std; const int MAX = 101; const int N = 10; int main() { BinarySearchTree *bst = new BinarySearchTree(); //设置随机化种子,避免每次产生相同的随机数 srand(time(0)); //构造一个随机数组成的二分查找树 for (int i = 0; i < N; i++) bst->Insert(rand() % MAX); //遍历查找树 cout << "先序遍历二分查找树bst:" << endl; PreOrderWalk(bst->root); //遍历查找树 cout << endl << "中序遍历二分查找树bst:" << endl; InOrderWalk(bst->root); //遍历查找树 cout << endl << "后序遍历二分查找树bst:" << endl; PostOrderWalk(bst->root); int x = 45; BSTNode *node = Search(bst->root, x); if (node) { cout << endl << "二分查找树bst中存在结点x = " << x << endl; bst->Delete(x); cout << endl << "删除二分查找树中结点x = " << x << "成功!" << endl; //遍历查找树 cout << endl << "先序遍历二分查找树bst:" << endl; PreOrderWalk(bst->root); //遍历查找树 cout << endl << "中序遍历二分查找树bst:" << endl; InOrderWalk(bst->root); //遍历查找树 cout << endl << "后序遍历二分查找树bst:" << endl; PostOrderWalk(bst->root); cout << endl << endl; } else{ cout << endl << "二分查找树bst中不存在结点x = " << x << endl; cout << endl << endl; } system("pause"); return 0; }
测试结果(查找失败的情况):
测试结果(查找成功并删除):
3 随机构造的二叉查找树
在本章的最后介绍了一种随机构造二叉查找树的理论方法,这主要是针对普通二叉查找树基本操作运行时间O(h)考虑的,这种方式可以使得:一棵在n个关键字上随机构造的二叉查找树的期望高度为O(logn)。
这一部分感觉应用不多吧,木有仔细看,^||^~~
相关文章推荐
- mysql max和count、limit优化
- LeetCode-Two Sum-解题报告
- LintCode解题笔记 - 在O(1)时间复杂度删除链表节点
- js使用cookies的例子
- Oracle数据库之开发PL/SQL子程序和包
- centos6.3 安装python2.7.3
- LeetCode-Add Two Numbers-解题报告
- 在mac上构建Jenkins+unity3d+xcode发布流程
- iOS - 地图 - 百度地图 - 准备阶段
- LeetCode Binary Tree Right Side View
- [1]开发准备-使用C#.NET开发基于本地数据缓存的PC客户端
- 推荐一个免费的构建Beyesian贝叶斯概率网络的JAVA,C#,.NET, R, Matlab,Python,Ruby 的API
- ios8自适应布局
- Section 1.2.2 Milking Cows
- 什么是单模光纤和多模光纤?各有什么优缺点?
- 堆栈帧的组织——C/C++内存管理必须掌握
- PID控制原理
- LeetCode-Median of Two Sorted Arrays-解题报告
- 算法复习之快速排序
- poj 2689