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

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

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

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




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;
}






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值