您的位置:首页 > 其它

二叉树

2016-06-08 17:53 106 查看
一、简单介绍

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  搜索