数据结构 《5》----二叉搜索树 ( Binary Search Tree )

来源:互联网 发布:阿里云是邮箱吗 编辑:程序博客网 时间:2024/06/05 15:58

二叉树的一个重要应用就是查找。

二叉搜索树 满足如下的性质:

           左子树的关键字 < 节点的关键字 < 右子树的关键字




1. Find(x)   

有了上述的性质后,我们就可以像二分查找那样查找给定的关键字x

具体如下: if x < node->val, Search in left sub-tree;

                   else if x > node->val, Search in right sub-tree;

                   else, found it!


2. Insert(x)

插入操作像Find(x)一样非常简单。要保证插入后,树仍然保持 左子树<本身<右子树, 

那如何找到具体的插入位置呢? 我们可以换个思路考虑问题,假设x已经在树中,那它所在的位置就是插入位置!

Bingo! 上面的搜索算法得到的搜索路径的最后就是我们所求!

具体思路是: 

按照Find的方法,搜索x, 如果发现已经有节点的值=x, 则返回;

否则, 在搜索路径的最后插入新的节点(x)


Figure 2: 插入关键字5


3. Delete(x)

删除操作相对麻烦一些。要考虑删除的节点有几个孩子。

首先搜索关键字x, 若没有,则返回。否则,删除该节点。

1> 若节点 has no child, 直接删除节点即可,能够保证所有节点满足 左子树<本身<右子树

2> 若节点 has one child,(不妨设为仅有右孩子)



3> 若 two children

为了保证搜索二叉树的性质,讲右子树中的最小值赋值给当前节点,然后递归删除右子树的最小节点



时间复杂度分析:

注意到上述的操作复杂度都是 O(h), h为树的高度。

因此如果二叉树是如下图的情况,二叉树将退化为链表,复杂度变为线性。


为了避免这种情况,在插入删除的时候引入平衡操作,保证树满足某一种平衡条件。这就是二叉平衡树。


// copyright @ L.J.SHOU Nov.8, 2013// Binary Search Tree#include "search-tree.h"#include "binary-tree-printer.h"#include <cstdlib>#include <queue>#include <iostream>using namespace std;const int N=10;const int M=10;typedef int ElementType;/*struct TreeNode{  ElementType val;  TreeNode* left;  TreeNode* right;  TreeNode(ElementType x)    : val(x), left(NULL), right(NULL){}};*/TreeNode* Destroy(TreeNode *t){  if(t != NULL)  {    t->left = Destroy(t->left);    t->right = Destroy(t->right);delete t;  }  return NULL;}int Height(TreeNode *t){  if(t == NULL)     return -1;  int left  = Height(t->left);   int right = Height(t->right);   if(left > right)     return left + 1;  else     return right + 1;}TreeNode* Find(TreeNode *t, ElementType x){  if(t != NULL)  {    if(x < t->val)  return Find(t->left, x);    else if(x > t->val)  return Find(t->right, x);else  return t;  }  return NULL;}TreeNode* FindMin(TreeNode *t){ // iterative  TreeNode* p = t;  while(p && p->left)    p = p->left;  return p;}TreeNode* FindMax(TreeNode* t){ // recursive  if(t == NULL)     return NULL;  else if(t->right == NULL)    return t;  else    return FindMax(t->right);}TreeNode* Insert(TreeNode* t, ElementType x){ // recursive  if(t == NULL)  {    t = new TreeNode;t->val = x;t->left = t->right = NULL;  }  else if(x < t->val)    t->left = Insert(t->left, x);  else if(x > t->val)    t->right = Insert(t->right, x);  /* else x is already in the tree;       we'll do nothing */  return t;}TreeNode* Delete(TreeNode* t, ElementType x){ /* recursive */  TreeNode* p(NULL);  if(t == NULL)    cerr << "Element " << x << " Not Found" << endl;  else{    if(x < t->val)  t->left = Delete(t->left, x);else if(x > t->val)  t->right = Delete(t->right, x);else{ /* t->val = x */  if(t->left && t->right)  { /* two children */    /* find min in the right sub-tree */    p = FindMin(t->right);t->val = p->val;t->right = Delete(t->right, t->val);  }  else  { /* one or no child */    p = t;if(t->left == NULL)  t = t->right;else if(t->right == NULL)  t = t->left;delete p;  }}  }  return t;}void PreOrderVisit(TreeNode* t){  if(t)  {cout << t->val << " ";    PreOrderVisit(t->left);    PreOrderVisit(t->right);  }}void InOrderVisit(TreeNode* t){  if(t)  {    InOrderVisit(t->left);cout << t->val << " ";    InOrderVisit(t->right);  }}void LevelOrderVisit(TreeNode* t){  if(t == NULL) return;  TreeNode *node(NULL);  queue<TreeNode* > q;  q.push(t);  while(!q.empty())  {node = q.front(); q.pop();    cout << node->val << " ";if(node->left)  q.push(node->left);if(node->right)  q.push(node->right);  }}int main(){  TreeNode* t(NULL);    srand(time(0));  for(int i=0; i<N; ++i)    t = Insert(t, rand()%M+1);  cout << "PreOrder: ";  PreOrderVisit(t);  cout << endl;  cout << "InOrder: ";  InOrderVisit(t);  cout << endl;  cout << "LevelOrder: ";  LevelOrderVisit(t);  cout << endl;  cout << "Height: " << Height(t) << endl;  cout << "Min: " << FindMin(t)->val << endl;  cout << "Max: " << FindMax(t)->val << endl;  PrintBinaryTree(t);  t = Destroy(t);  return 0;}






4 0