文章目录
二叉搜索树
概念
左子树的值小于根,右子树的值大于根
根的值大于左子树,小于右子树
二叉搜索树就是用来查找的
假如我们要查找7:7比3大,到3的右子树=5,7比5大,到5的右子树7,查找到了
二叉搜索树的中序遍历,可以实现从小到大排序的遍历
时间复杂度
最坏情况1:查找:高度次
最坏情况2:O(N):
如下图:这个效率就特别差,和单链表没有区别
后续用AVL树,RB树
应用
搜索树的应用
- 搜索,key搜索模型,key/value模型
- 排序+去重
key模型
可以用来判断值在不在,效率很搞O(logN)
应用场景
- 搜索树存储小区业主的车牌号,扫描,存在就通过,不存在就不让过
- 搜索树存储同学的学号
- 给一个英文作文,检查里面的单词拼写是否正确(我们把单词都存放进去,进行搜索存在与否)
key/value模型
通过一个值查找另外一个值
应用场景
- 高铁站刷身份证进站,用身份证查早是否右买票
实现
key模型
树的节点
1 2 3 4 5 6 7 8 9 10 11 12
| template <class K>
struct BSTNode { K _val; BSTNode<K> *_left; BSTNode<K> *_right; BSTNode(const K &val) : _val(val), _right(nullptr), _left(nullptr) { } };
|
BStree的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| template <class K> struct BSTree { typedef BSTNode<K> Node;
private: Node *_root;
public: BSTree() : _root(nullptr) { } };
|
Insert
非递归版本
- 插入一个值,从根往下面走,要插入的值比它大,走右边,比它小走左边,如果这个值已近存在了,就不要插入
- 直到走到空,就是我们要插入的地方
- 我们需要把这个节点链接上去,所以我们需要空节点对应的父节点,父节点连接上新添加的节点
- 如果根节点就是空,直接插入在根节点即可
例如:我们插入一个10
10>8,先走右边,到9,10>9走右边,走到了空,把它插入到这个地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| bool Insert(const K &key) { if (_root == nullptr) { _root = new Node(key); return true; } else { Node *cur = _root; Node *prev; while (cur) { if (cur->_val > key) { prev = cur; cur = cur->_left; } else if (cur->_val < key) { prev = cur; cur = cur->_right; } else { return false; } } cur = new Node(key); if (prev->_val < key) { prev->_right = cur; } else { prev->_left = cur; } return true; } }
|
递归版本
我们使用引用就不需要用父节点来连接
例如:我们链接上的节点为10,走到9的右,root即是空,也是9右指针的别名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| bool _InsertR(Node *&root, const K &key) { if (root == nullptr) { root = new Node(key); return true; } if (root->_val > key) { return _InsertR(root->_left, key); } else if (root->_val < key) { return _InsertR(root->_right, key); } else { return false; } }
bool InsertR(const K &key) { return _InsertR(_root, key); }
|
Find
非递归版本
从根节
点往下走,比它大,走右边,比它小走左边,相等就找到了,走到空就说明没找到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| bool Find(const K &key) { Node *cur = _root; while (cur) { if (cur->_val > key) { cur = cur->_left; } else if (cur->_val < key) { cur = cur->_right; } else { return true; } } return false; }
|
递归版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Node *FindR(const K &key) { return _Find(_root, key); } Node *_FindR(Node *root, const K &key) { if (root == nullptr) { return nullptr; } if (root->_val == key) { return root; } else if (root->_val > key) { return _FindR(root->_left, key); } else { return _FindR(root->_right, key); } }
|
Erase
非递归版本
- 先找到要查找到要删除的节点
- 如果要删除的节点左子树为空,如果它是它父亲的左节点,它的父亲节点的左节点连接上删除节点的右指针
例如删除3,左为空,3是1的右节点,把1的右节点,连接到3的右节点
- 如果要删除的节点右子树为空,它为父节点的右节点,把它父节点的右节点连接到删除节点的左节点
例如删除10,右为空,10 是9的右节点,把10的左节点,连接到9的右节点上
- 如果要删除的节点左右子树都为空,要使用替换法删除,可以把要删除的节点的右子树的最左边或者要删除节点的左子树的最右边,把它和要删除节点进行替换,在把那个替换的节点删除
例如删除5,左右节点都不为空,把5右节点的最左边和5进行替换,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| bool Erase(const K &key) { Node *cur = _root; Node *parent = nullptr; while (cur) { if (cur->_val < key) { parent = cur; cur = cur->_right; } else if (cur->_val > key) { parent = cur; cur = cur->_left; } else {
if (cur->_left == nullptr) { if (parent == nullptr) { _root = _root->_right; } else { if (parent->_left == cur) { parent->_left = cur->_right; } else if (parent->_right == cur) { parent->_right = cur->_right; } } delete cur; cur = nullptr; } else if (cur->_right == nullptr) { if (parent == nullptr) { _root = _root->_left; } else { if (parent->_left == cur) { parent->_left = cur->_left; } else if (parent->_right == cur) { parent->_right = cur->_left; } } delete cur; cur = nullptr; } else { Node *node = cur->_right; Node *parent = cur; if (node->_left != nullptr) {
while (node->_left) { parent = node; node = node->_left; } swap(cur->_val, node->_val); parent->_left = node->_right; delete node; node = nullptr; } else { swap(cur->_val, node->_val); parent->_right = node->_right; delete node; node = nullptr; } }
return true; } } return false; }
|
递归版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| Node *EraseR(const K &key) { _EraseR(key, _root); } bool _EraseR(const K &key, Node *&root) { if (root == nullptr) return false; if (root->_val > key) { return _EraseR(key, root->_left); } else if (root->_val < key) { return _EraseR(key, root->_right); } else { Node *del = root; if (root->_left == nullptr) {
root = root->_right; }
else if (root->_right == nullptr) { root = root->_left; } else {
Node *min = root->_right; while (min->_left) { min = min->_left; } swap(min->_val, root->_val); return _EraseR(key, root->_right); } delete del; return true; } }
|
InOrder
中序遍历,左根右
在类里面递归遍历,我们可以使用子函数,这样外部就不需要用类里面的私有成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void InOrder() { _InOrder(_root); }
void _InOrder(Node *root) { if (root == nullptr) return; _InOrder(root->_left); cout << root->_val << " "; _InOrder(root->_right); }
|
KV模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
| template <class K,class V>
struct BSTNode { K _key; V _val; BSTNode<K,V> *_left; BSTNode<K,V> *_right; BSTNode(const K &key,const V& val) : _val(val), _right(nullptr), _left(nullptr),_key(key) { } };
template <class K,class V> struct BSTree { typedef BSTNode<K,V> Node;
private: Node *_root;
public: BSTree() : _root(nullptr) { }
bool Insert(const K &key,const V& val) { if (_root == nullptr) { _root = new Node(key,val); return true; } else { Node *cur = _root; Node *prev; while (cur) { if (cur->_key > key) { prev = cur; cur = cur->_left; } else if (cur->_key < key) { prev = cur; cur = cur->_right; } else { return false; } } cur = new Node(key,val); if (prev->_key < key) { prev->_right = cur; } else { prev->_left = cur; } return true; } }
Node* Find(const K &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 nullptr; } void InOrder() { _InOrder(_root); }
void _InOrder(Node *root) { if (root == nullptr) return; _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); }
bool Erase(const K &key) { Node *cur = _root; Node *parent = nullptr; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else {
if (cur->_left == nullptr) { if (parent == nullptr) { _root = _root->_right; } else { if (parent->_left == cur) { parent->_left = cur->_right; } else if (parent->_right == cur) { parent->_right = cur->_right; } } delete cur; cur = nullptr; } else if (cur->_right == nullptr) { if (parent == nullptr) { _root = _root->_left; } else { if (parent->_left == cur) { parent->_left = cur->_left; } else if (parent->_right == cur) { parent->_right = cur->_left; } } delete cur; cur = nullptr; } else { Node *node = cur->_right; Node *parent = cur; if (node->_left != nullptr) {
while (node->_left) { parent = node; node = node->_left; } swap(cur->_val, node->_val); swap(cur->_key, node->_key); parent->_left = node->_right; delete node; node = nullptr; } else { swap(cur->_val, node->_val); swap(cur->_key, node->_key); parent->_right = node->_right; delete node; node = nullptr; } }
return true; } } return false; }
};
|