二叉树

一、简单介绍

1、以前的数据结构重点都死在结构,而现在的二叉搜索树重在应用 

2、二叉搜索树的简单性质

(1)每一个节点的key值都是不同的

(2)所有的节点的左节点都小于当前节点,所有的右节点大于当前节点

(3)所有节点的左右子树都是二叉搜索树

3、二叉搜索树应用在查找上面,时间复杂度与二分查找相类似

注意哈希表也是用来查找的(key形式是用来过滤的,而KV形式是用来查找信息的)

4、STL也有搜索树(以前只是对vector和list比较了解)

(1)map 是KV形式,底层实现是使用红黑树(也是一种二叉搜索树,是针对二叉搜索树的性质被设计出来的)

二叉搜索树的缺陷:在插入顺序为[0,1,2,3,4,5,6,7,8,9]的顺序插入顺序的时候,查找效率是比较低的,所以有了平衡树。红黑树

(2)set 是value形式的,底层实现是红黑树

c++11应用还应用了一下的两种用来查找的容器

(3)unorder_map是key/ value形式的,底层实现是使用哈希表(无序的

(4)unorder_set是key形式的,底层实现是使用哈希表

5、上述的数据结构的区别和联系

(1)查找的时间复杂度为:红黑树o(lgN)而哈希表为o(1)(红黑树1000000只需要查找20次)

(2)效率不同

(3)JAVA中 unorder哈希表都挂在一个链上的时候,就自动挂为红黑树

二、大体声明

1、KV节点的定义:

template<class K,class V>
struct BSTNode
{
	BSTNode<K, V>* _left;
	BSTNode<K, V>* _right;
	K _key;
	V _value;
public:
	BSTNode(const K& key, const V& value)
		:_left(NULL)
		, _right(NULL)
		, _key(key)
		, _value(value)
	{}
};

2、大体声明

template<class K,class V>
class BSTree
{
	typedef BSTNode<K, V> Node;
public:
	BSTree();
	
public://增删查改的非递归写法
	bool Insert(const K& key, const V& value);//返回值设计成bool防冗余
	bool Remove(const K& key);
	Node* Find(const K& key)//不能该key,改key后整体会乱

public:
	Node* Find_R(const K& key);
	bool Insert_R(const K& key, const V& value);
	bool Remove_R(const K& key);

protected://增删查改的递归写法,Remove和Insert巧用引用
	Node* _Find_R(Node* root, const K& key);
	bool _Insert_R(Node*& root, const K& key, const V& value);
	bool  _Remove_R(Node*& root, const K& key);

public:
	void Inorder_NonR();//方便测试
	
protected:
	Node* _root;
}

三、具体实现

1、默认构造函数

<pre name="code" class="cpp">BSTree()
	:_root(NULL)
{}


2、增删查(非递归写法)

(1)增

bool Insert(const K& key, const V& value)//返回值设计成bool防冗余
{
	if (_root == NULL)
	{
		_root = new Node(key, value);
		return true;
	}
	Node* cur = _root;
	Node* parent = NULL;//记录cur的上一个节点
	while (cur)
	{
		if (cur->_key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_key>key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			return false;
		}
	}
	if (parent->_key > key)
	{
		parent->_left = new Node(key, value);
	}
	else
	{
		parent->_right = new Node(key, value);
	}
	return true;
}

(2)查

Node* Find(const K& key)//不能该key,改key后整体会乱
{
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key > key)
		{
			cur = cur->_left;
		}
		else if (cur->_key < key)
		{
			cur = cur->_right;
		}
		else
			return cur;
	}
	return NULL;
}

(3)删(最麻烦)

bool Remove(const K& key)
{
	if (_root == NULL)
		return false;
	if (_root->_left == NULL&&_root->_right == NULL)//是叶子节点或者根节点
	{
		if (_root->_key == key)
		{
			delete _root;
			_root = NULL;
			return true;
		}
		else
		{
			return false;
		}
	}
	Node* parent = NULL;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_key>key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else//相等的情况
		{
			Node* del = cur;
			if (cur->_left == NULL)//节点这有左子树或者右子树
			{
				if (parent == NULL)
				{
					_root = cur->_right;
				}
				else
				{
					if (parent->_left == cur)
					{
						parent->_left == cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
				}	
			}
			else if (cur->_right == NULL)
			{
				if (parent == NULL)
				{
					_root = cur->_left;
				}
				else
				{
					if (parent->_left == cur)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;
					}
				}
			}
			else
			{//找到最左的节点,替换法删除
				parent = cur;
				Node* firstLeft = cur->_right;
				while (firstLeft->_left != NULL)
				{
					parent = firstLeft;
					firstLeft = firstLeft->_left;
				}
				std::swap(cur->_key, firstLeft->_key);
				std::swap(cur->_value, cur->_value);
				del = firstLeft;
				if (parent->_left == firstLeft)
				{
					parent->_left = firstLeft->_right;//因为为右子树的最左节点,所以没有左节点
				}
				else
				{
					parent->_right = firstLeft->_right;
				}				
			}
			delete del;
			return true;
		}
	}
	return false;
}

3、增删查(递归写法)

(1)增

主函数:

bool Insert_R(const K& key, const V& value)
{
	return _Insert_R(_root, key, value);
}

递归函数:

bool _Insert_R(Node*& root, const K& key, const V& value)
{
	if (root == NULL)
	{
		root = new Node(key, value);
		return true;
	}
	if (root->_key > key)
	{
		return _Insert_R(root->_left, key, value);
	}
	else if (root->_key < key)
	{
		return _Insert_R(root->_right, key, value);
	}
	else
	{
		return false;
	}
}

(2)查

主函数:

Node* Find_R(const K& key)
{
	return _Find_R(_root, key);
}

递归函数:

Node* _Find_R(Node* root, const K& key)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_key == key)
	{
		return root;
	}
	if (root->_key > key)
	{
		return _Find_R(root->_left, key);
	}
	else
	{
		return _Find_R(root->_right, key);
	}
	return NULL;
}

(3)删

主函数:

bool Remove_R(const K& key)
{
	return _Remove_R(_root, key);
}

递归函数:

bool  _Remove_R(Node*& root, const K& key)
{
	if (root == NULL)
	{
		return false;
	}
	if (root->_key > key)//有的时候条件判断的顺序要变通一下,突出重点,而不是一味的按顺序
	{
		return _Remove_R(root->_left, key);
	}
	else if (root->_key < key)
	{
		return _Remove_R(root->_right, key);
	}
	else
	{
		Node* del = root;
		if (root->_left == NULL)
		{
			root = root->_right;//root指针,而root->_right是将指针的值赋值给他,所以后面delete del是没有什么问题的
		}
		else if (root->_right == NULL)
		{
			root = root->_left;
		}
		else
		{
			Node* firstLeft = root->_right;//寻找右子树的最左的叶子节点,或者寻找左子树的最右的叶子节点
			while (firstLeft->_left != NULL)
			{
				firstLeft = firstLeft->_left;
			}
			std::swap(root->_key, firstLeft->_key);
			std::swap(root->_value, firstLeft->_value);
			return _Remove_R(root->_right, key);//只能写这种写法,是因为firstLeft的有节点可能存在,不能简单的置为NULL	
		}					//del = firstLeft;这种也是不对的因为firstLeft这个时候可能是有右节点的
		delete del;
		del = NULL;//delet和NULL搭配使用
		return true;
	}		
	return false;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值