搜索二叉树

二叉查找树(BinarySearch Tree,也叫二叉搜索树,或称二叉排序树Binary Sort Tree)或者是一棵空树,或具有如下性质:

  1. 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同。
  2. 左子树上所有节点的关键码(key)都小于根节点的关键码(key)。
  3. 右子树上所有节点的关键码(key)都大于根节点的关键码(key)。
  4. 左右子树都是二叉搜索树。

二叉搜索树相关操作:

(1)插入:新节点

在二叉查找树中插入新结点,要保证插入新结点后仍能满足二叉查找树的性质。插入过程如下:

a、若二叉查找树root为空,则使新结点为根;

b、若二叉查找树root不为空,则查找该节点应插入的位置。若新结点的关键字小于插入点的关键字,则将新结点插入到插入点的左子树中,大于则插入到插入点的右子树中。否则,不插入,返回失败。

(2)查找:关键码的节点

a.从根节点开始查找,若关键字小于目前节点的关键字,则到目前节点的左子树中查询;若关键字大于目前节点的关键字,则到目前节点的右子树中查询;否则,查找成功,返回当前节点。

b.若到空还没找到,则查找失败。

(3)、删除

删除某个结点后依然要保持二叉查找树的特性。删除过程如下:

a、若删除点是叶子结点,则设置其双亲结点的对应指针为空。

b、若删除点只有左子树,或只有右子树,则设置其双亲结点的指针指向左子树或右子树。

c、若删除点的左右子树均不为空,则:采用替代删除法

1)查询删除点的右子树中的非空最小节点(即最左节点),交换要删除节点与右最小节点的关键码与值,删除右最小节点。

2)查询删除点的左子树中的非空最大节点(即最右节点),交换要删除节点与左最大节点的关键码与值,删除左最大节点。

注:中序遍历二叉查找树可得到一个关键字的有序序列。

#include<iostream>
using namespace std;
//搜索二叉树
template<class K,class V>
struct BSTreeNode
{
	K _key;
	V _val;
	BSTreeNode<K,V>* _left;
	BSTreeNode<K,V>* _right;
	BSTreeNode(K& key,V& val)
		:_key(key)
		, _val(val)
		, _left(NULL)
		, _right(NULL)
	{}
};
template<class K,class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:
	BSTree()
		:_root(NULL)
	{}
	~BSTree()
	{
		_Destroy(_root);
		_root = NULL;
	}
	bool Insert(K& key, V& val)
	{
		if (_root == NULL)
		{
			_root = new Node(key, val);
			return true;
		}
		else
		{
			Node* parent = NULL;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					return false;
				}
			}
			cur = new Node(key, val);
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}
			return true;
		}
	}
	Node* Find(const K& key)
	{
		if (_root == NULL)
			return NULL;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
				cur = cur->_right;
			else if (cur->_key>key)
				cur = cur->_left;
			else
				return cur;
		}
		return NULL;
	}
	bool Remove(const K& key)
	{
		if (_root == NULL)
			return false;
		Node* cur = _root;
		Node* parent = NULL;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key>key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				Node* del = NULL;
				if (cur->_left == NULL)
				{
					del = cur;
					if (cur == _root)
					{
						_root = cur->_right;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
				}
				else if (cur->_right == NULL)
				{
					del = cur;
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
					}
				}
				else//左右都不为空
				{
					Node* rightMin = cur->_right;
					parent = cur;
					while (rightMin->_left)
					{
						parent = rightMin;
						rightMin = rightMin->_left;
					}
					cur->_key = rightMin->_key;
					cur->_val = rightMin->_val;

					del=rightMin;
					if (parent->_left == rightMin)
						parent->_left = NULL;
					else
						parent->_right = NULL;
				}
				delete del;
				return true;
			}
		}
		return false;
	}
	void InOrder()
	{
		if (_root == NULL)
			return;
		_InOrder(_root);
		cout << endl;
	}
	bool InsertR(K& key, V& val)
	{
		return _InsertR(_root, key, val);
	}
	Node* FindR(const K& key)
	{
		return _FindR(_root, key);
	}
	bool RemoveR(K key)
	{
		return _RemoveR(_root, key);
	}
protected:
	void _Destroy(Node* root)
	{
		if (root == NULL)
			return;
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}
	bool _InsertR(Node*& root, K& key, V& val)
	{
		if (root == NULL)
		{
			root = new Node(key, val);
			return true;
		}
		if (root->_key > key)
			return _InsertR(root->_left, key, val);
		else if (root->_key < key)
			return _InsertR(root->_right, key, val);
		else
			return false;
	}
	Node* _FindR(Node* root, const K& key)
	{
		if (root == NULL)
			return NULL;
		if (root->_key < key)
			return _FindR(root->_right, key);
		else if (root->_key>key)
			return _FindR(root->_left, key);
		else
			return root;
	}
	bool _RemoveR(Node*& root, K& key)
	{
		if (root == NULL)
			return false;
		if (root->_key < key)
			return _RemoveR(root->_right, key);
		else if (root->_key>key)
			return _RemoveR(root->_left, key);
		else
		{
			Node* del = root;
			if (root->_left == NULL)
			{
				root = root->_right;
			}
			else if (root->_right == NULL)
			{
				root = root->_left;
			}
			else
			{
				Node* rightMin = root->_right;
				Node* parent = root;
				while (rightMin->_left)
				{
					parent = rightMin;
					rightMin = rightMin->_left;
				}
				root->_key = rightMin->_key;
				root->_val = rightMin->_val;
				del = rightMin;
				if (parent->_left == rightMin)
					parent->_left = NULL;
				else
					parent->_right = NULL;
			}
			delete del;
			return true;
		}
	}
protected:
	void _InOrder(Node* root)
	{
		if (root == NULL)
			return;
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}
private:
	Node* _root;
};
void Test1()
{
	int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
	BSTree<int, int> t;
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
	{
		t.Insert(a[i], i);
	}
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
	{
		cout<<"是否存在"<<a[i]<<"  "<<t.Find(a[i])->_key<<endl;
	}
	t.InOrder();
	cout << 5 << t.Remove(5) << endl;
	cout << 8 << t.Remove(8) << endl;
	cout << 2 << t.Remove(2) << endl;
	cout << 1 << t.Remove(1) << endl;
	cout << 3 << t.Remove(3) << endl;
	cout << 7 << t.Remove(7) << endl;
	t.InOrder();
}
void Test2()
{
	int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
	BSTree<int, int> t;
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
	{
		t.InsertR(a[i], i);
	}
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
	{
		cout << "是否存在" << a[i] << "  " << t.FindR(a[i])->_key << endl;
	}
	t.InOrder();
	cout << 5 << t.RemoveR(5) << endl;
	cout << 8 << t.RemoveR(8) << endl;
	cout << 2 << t.RemoveR(2) << endl;
	cout << 1 << t.RemoveR(1) << endl;
	cout << 3 << t.RemoveR(3) << endl;
	cout << 7 << t.RemoveR(7) << endl;
	cout << 9 << t.RemoveR(9) << endl;
	cout << 0 << t.RemoveR(0) << endl;
	cout << 4 << t.RemoveR(4) << endl;
	cout << 6 << t.RemoveR(6) << endl;

	cout << 5 << t.RemoveR(5) << endl;
	cout << 6 << t.RemoveR(6) << endl;
	t.InOrder();
}

#include"SBTree.h"
int main()
{
	//Test1();
	Test2();
	system("pause");
	return 0;
}

注:搜索树的缺陷是一定情况下会退化为单链表。如果插入顺序为1,2,3。则树的插入,查找,删除复杂度皆为O(n).

时间: 2024-10-22 06:43:52

搜索二叉树的相关文章

判断一个数列是不是搜索二叉树后续遍历输出的结果

剑平面阿里被问到这个,刚开始画了下看有什么性质,乱蒙了几个都被推翻了,初始感觉就是要O(n)的,因为印象中BST的构树都可以O(nlogn)搞定.然后剑平说最后一个数肯定是根节点,一下反应过来了,就是二分出间隔点然后两边递归判断,不过这好像还是构树的思路,可以把整棵树构造出来.然后剑平说不是二分,直接遍历.不科学啊,明显的二分,然后去网上搜一下,都是遍历的,O(n^2)的吧.想了想,二分是当做合法的情况来构树的,不合法怎么判断?构造出搜索二叉树后中序遍历一下不就行了么,妥妥的O(nlogn)吧.

java递归方法建立搜索二叉树,具备查找关键字,插入新节点功能

二叉排序树的定义: 二叉排序树满足以下三个性质(BST性质): <1>若它的左子树非空,则左子树上所有节点的值均小于根节点的值 <2>若它的右子树非空,则右子树上所有节点的值均大于根节点的值 <3>左,右子树本身又各是一棵二叉排序树 根据二叉排序树的BST性质,可以说二叉排序树每个节点上的值(或称关键字)都是唯一的,并且二叉排序树以中序遍历输出的结果必然是一个有序的递增序列. 如下图所示: 用递归方法建立二叉排序树,减少了繁复的比较程序,效率较高.只需要知道每个节点的值

数据结构--‘搜索二叉树’

'二叉树'是数据结构中比较重要的一部分,这里主要讨论一下'搜索二叉树',针对'搜索二叉树的插入.删除和查找节点进行分情况讨论,希望能够帮助读者更加的理解搜索二叉树的原理. ◆搜索二叉树的性质: 1.每个节点都有一个一个作为搜索依据的关键码,所有节点的关键码都不相同. 2.左子树所有的关键码(key)都小于根节点的关键码(key). 3.右子树所有的关键码(key)都大于根节点的关键码(key). 4.左.右子树都是二叉搜索树. 实现'搜索二叉树'的节点结构可以实现为K形式,和K.V形式,若实现K

【数据结构】搜索二叉树的(递归与非递归)实现,包括:增Insert,删Remove,查Find

搜索二叉树,是二叉树一种特殊的结构. 特点: (1)每个节点都有一个关键码,并且关键码不重复. (2)左子树上的每个节点的关键码都小于根节点的关键码. (3)右子树上的每个节点的关键码都大于根节点的关键码. (4)左右子树都是搜索二叉树. 下面,为方便大家理解,我举例画一个搜索二叉树,如下: 代码见下: #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; //搜索二叉树的节点结构 template&

《github一天一道算法题》:搜索二叉树接口实现大合集

读书.思考.写代码! 说明: (1)这里实现了搜索二叉树的全部常用操作 (2)限于时间和精力,实现的较为粗糙,内存泄露.成员变量访问控制.返回类型.异常安全等没有照顾的到 (3)一切实现的手段都是贴近底层操作,关注原理.以后可能对推倒重来,实现一个完备的接口系统. /********************************************* * [email protected] * 题目:二叉树接口实现大合集 * 具体:二叉树的创建.插入.最大值.最小值.前中后序递归遍历与非递

搜索二叉树的操作

搜索二叉树的数据结构定义: /*二叉搜索树的结构定义*/ typedef struct TreeNode* SearchTree; typedef struct TreeNode* Position; struct TreeNode { int Element; SearchTree Left; SearchTree Right; } 搜索二叉树的插入操作: SearchTree Insert(int x, SearchTree T) { if(T == NULL)//空树 { T = mall

搜索二叉树应用——简单字典实现

搜索二叉树基本概念请看上篇博客这两个问题都是典型的K(key)V(value)问题,我们用KV算法解决. 判断一个单词是否拼写正确:假设把所有单词都按照搜索树的性质插入到搜索二叉树中,我们判断一个单词拼写是否正确就是在树中查找该单词是否存在(查找key是否存在). 结构声明下 typedef char* KeyType; typedef struct BSTreeNode { struct BSTreeNode *_left; struct BSTreeNode *_right; KeyType

搜索二叉树之字典实现

利用搜索二叉树判断一个单词是否拼写正确: 假设把所有单词都按照搜索树的性质插入到搜索二叉树中,我们判断一个单词拼写是否正确就是在树中查找该单词是否存在(查找key是否存在). /***************************************** *Date:2018年3月26日14:42:54 *Author: Meng *WebSite:msyci.com *QQ:3515955122 *****************************************/ # i

栈和队列----将搜索二叉树转换成双向链表

将搜索二叉树转换成双向链表 对于BST 来说,有本身的值域,有指向左孩子和右孩子的两个指针:对于双向链表来说,有本身的值域,有指向上一个节点和下一个节点的指针.将这个BST转换成双向链表,对于每一个节点来说,原来的right指针等价于转换后的next指针,原来的left指针等价于转换后的left指针,最后返回双向链表的头节点. [解析] 用队列等容器收集二叉树 中序遍历的结果的方法.其时间复杂度是O(N),空间复杂度是O(N). 1. 生成一个队列,记为queue,按照二叉树的中序遍历的顺序,将