二叉搜索树

来源:互联网 发布:php打印直角三角形 编辑:程序博客网 时间:2024/06/05 20:28
一、二叉搜索树的性质:
1、每个结点都有一个作为搜索依据的关键码,并且这个关键码是互不相同的
2、左子树上的所有结点的关键码都小于根节点的关键码
3、右子树上的所有结点的关键码都大于根节点的关键码
4、左右子树也是二叉搜索树
例:


二、二叉树搜索树所支持的操作

1、查找
  在二叉搜索树上进行查找,是从根节点出根据关键码的大小选择一条分支向下进行查找。一般情况下最多查找树的高度次就能得出结果,所以大多数情况下二叉搜索树的平均查找时间是O(logN)。但是如果删除多的话,二叉搜索树会逐渐向左倾斜,退化成链表,时间复杂度就是O(N).
例:

(1)、查找3

(2)、查找8


(3)、查找最小值
   在这棵树不为空的情况下,判断根节点有没有左子树。如果根节点没有左子树的话,则直接返回根节点。如果有左子树的话,则沿左分支查找最后一个数。
      
[cpp] view plain copy
  1. Node* _FindMin(Node* cur)  
  2.       {  
  3.              assert(cur);  
  4.              while (cur->_left)  
  5.              {  
  6.                     cur = cur->_left;  
  7.              }  
  8.              return cur;  
  9.       }  


(4)、查找最大值
   在这棵树不为空的情况下,判断根节点有没有右子树。如果根节点没有右子树的话,则直接返回根节点。如果有右子树的话,则沿右分支查找最后一个数。
   
[cpp] view plain copy
  1. Node* _FindMax(Node* cur)  
  2.    {  
  3.           assert(cur);  
  4.           while (cur->_right)  
  5.                  cur = cur->_right;  
  6.           return cur;  
  7.    }  


(5)、查找第k个数


[cpp] view plain copy
  1. Node* _Find(Node* cur,int k)  
  2. {  
  3.        int num =_Size(cur->_left);  
  4.        if (k == num + 1)  
  5.               return cur;  
  6.        else if (k <= num)  
  7.        {  
  8.               return _Find(cur->_left,k);  
  9.        }  
  10.        else  
  11.        {  
  12.               return _Find(cur->_right,k-num-1);  
  13.        }  
  14. }  




2、插入
  插入一个数使得二叉树仍然是一颗二叉搜索树。从根节点出发搜索插入位置,然后把新节点作为叶子结点插入。这样的话不需要移动结点,只需要修改一个叶子结点的空指针就行。
   
[cpp] view plain copy
  1. void _Insert(Node* &cur,const T& x)  
  2.    {  
  3.           if (cur == NULL)  
  4.           {  
  5.                  cur = new Node(x);  
  6.                  return;  
  7.           }  
  8.           if (x < cur->_data)  
  9.           {  
  10.                  _Insert(cur->_left, x);  
  11.           }  
  12.           else if (cur->_data < x)  
  13.           {  
  14.                  _Insert(cur->_right,x);  
  15.           }  
  16.    }  

例:


3、删除
  删除比较复杂一点,但是可以分为两种情况。

 (1、假如要删除的结点有两个孩子,则应该将右子树上关键码最小的结点与要删除的结点交换,再删除右子树上关键码最小的那个结点。
例:


     (2、假如要删除的结点只有一个孩子
例:

假如只有右孩子或者没有孩子与只有左孩子是相同的道理。

[cpp] view plain copy
  1. void _Remove(Node* &cur,const T& x)  
  2. {  
  3.        if (cur == NULL)  
  4.               return;  
  5.        if (x < cur->_data)  
  6.        {  
  7.               _Remove(cur->_left,x);  
  8.        }  
  9.        else if (cur->_data < x)  
  10.        {  
  11.               _Remove(cur->_right,x);  
  12.        }  
  13.        else  
  14.        {  
  15.               if (cur->_left != NULL&&cur->_right != NULL) //如果要删除的结点有两个孩子  
  16.               {  
  17.                     Node* del = cur;  
  18.                     cur->_data =_FindMin(cur->_right)->_data;  
  19.                     _Remove(cur->_right,cur->_data);  
  20.               }  
  21.               else                   //如果要删除的结点是叶子结点或只有一个孩子的结点  
  22.               {  
  23.                     Node* del = cur;  
  24.                     cur = (cur->_left != NULL) ? cur->_left : cur->_right;  
  25.                     delete del;  
  26.               }  
  27.        }  
  28. }  


原创粉丝点击