BST概念:
BST树叫二叉搜索树,是树的最基本数据结构。主要用处在按值查找数据,这里就有人问了,查询数据直接在一个有序数组中用二分算法不就行了,这样是可以,但这仅仅是一个算法。如果,我们还要为这个数组新增新删,复杂度就为O(n),这时我们的关注点就要聚焦于数据结构了,把底层数组结构实现成BST树,增删查改时间复杂度都为O(long2n)。当然,更高级的还有AVL树,RB树,另外还有哈希表。(注:这里也说明了算法和数据结构相辅相成)
知识点:
-
成员变量 struct Node{int data, Node* left, Node* right}; Node* root;
-
非递归实现时,由于无法找到父节点,所以要记录父节点
-
删除非递归:
(1)分析问题,待删节点分别有0,1,2个孩子;
(2)查找待删节点位置;
(3)2 -》 0/1;2个孩子的情况转换成0/1个孩子的情况,只需将old->data=cur->data就行
(4)0/1孩子的情况一致,cur把它的孩子给它的父亲就行,无论它的孩子是否为nullptr,cur是待删节点
(5)特殊情况考虑:若删除的是root,首先对两个孩子的结果不影响,但是对0/1情况要处理,root指向cur的孩子 -
递归实现一:框架
void func(Node* cur)
{
func(cur->left);
func(cur->right);
}
很简单,调用两次自身,参数分别穿左右孩子,就能遍历整个树。
-
递归实现二:参数
(1)传值func(int i):下一层不影响上一层的,如i表示当前层数,即使下一层改变完回退后,上一层i也不改变,原来是什么还是什么。
(2)传引用func(int &i):下一层影响上一层的,如i表示计数,下一层函数num++,回退后,上一层也要改变,要不然基数还有什么意义。
(3)总结:数组/指针穿的是指针都不会用错,如果参数是容器的话,记得穿引用或指针,如果是变量的话,一定要想清楚,其中子集树中的i常常传值,需要用参数带回去的一般红引用。 -
递归实现三:返回值
返回值不是void的函数递归真的很烧脑,如果想不通,建议直接拿参数带回去,记得这种参数一般都是传引用。但接下来,我们还是要分析一波返回值不是void类型的函数,直接来看例子吧:
Node* getLastK(Node* cur, int& k)
{
if (cur == nullptr)
return nullptr;
Node* res = getLastK(cur->right, k); //(1)
if (res != nullptr)
{
return res;
}
if (--k == 0)
{
return cur;
}
return getLastK(cur->left, k); //(2)
}
这里,有两处调用了自身函数(1)(2)。(2)很简单,直接就把值返还给上一层就行了。那么,(1)如果这样做return getLastK(cur->right, k); ,这样就永远执行不到下面的语句了,所以它的返回值要有判断。
代码
五个部分:成员变量、构造析构、非递归增删查改、递归增删查改、经典题型
#include<iostream>
#include<vector>
namespace user
{
template<typename T>
class BST
{
private://成员方法
struct Node
{
Node(T val = T()) :data(val), left(nullptr), right(nullptr) {}
~Node() {}
T data;
Node* left;
Node* right;
};
Node* root;
public://构造析构
BST() :root(nullptr) {}
~BST()
{
if (root != nullptr)
{
Delete(root);
}
}
void Delete(Node* cur)
{
if (cur->left != nullptr)
{
Delete(cur->left);
}
if (cur->right != nullptr)
{
Delete(cur->right);
}
delete cur;
}
public://非递归
//增
void nonInsert(T val)
{
if (root == nullptr)
{
root = new Node(val);
return;
}
Node* cur = root;
Node* parent = nullptr;
while (cur != nullptr)
{
parent = cur;
if (val < cur->data)
{
cur = cur->left;
}
else if (val > cur->data)
{
cur = cur->right;
}
else
{
std::cout << "程序不支持相同的元素" << std::endl;
break;
}
}
Node* node = new Node(val);
if (val < parent->data)
{
parent->left = node;
}
else
{
parent->right = node;
}
}
//按值删除,按位置删除也没有意义
void nonRemove(T val)
{
Node* cur = root;
Node* parent = nullptr;
//找位置
while (cur != nullptr && cur->data != val)
{
parent = cur;
if (val < cur->data)
{
cur = cur->left;
}
else
{
cur = cur->right;
}
}
if (cur == nullptr)
{
std::cout << "no val\n";
return;
}
//3 -> 1/2
if (cur->left != nullptr && cur->right != nullptr)
{
Node* old = cur;
parent = cur;
cur = cur->left;
while (cur->right != nullptr)
{
parent = cur;
cur = cur->right;
}
old->data = cur->data;
}
//1,2本质一样
Node* child = cur->left;
if (child == nullptr)
{
child = cur->right;
}
if (root == cur) //判断root
{
root = child;
}
else
{
if (cur == parent->left)
{
parent->left = child;
}
else
{
parent->right = child;
}
}
delete cur;
}
//查
bool nonselect(int val)
{
Node* cur = root;
while (cur != nullptr)
{
if (val == cur->data)
{
return true;
}
if (val < cur->data)
{
cur = cur->left;
}
else
{
cur = cur->right;
}
}
return false;
}
//非递归遍历
public://递归实现
//递归删除
//递归插入
//递归查找
//中序
void inOrder()
{
std::cout << "inOrder: ";
inOrder(root);
std::cout << "\n";
}
void inOrder(Node* cur)
{
if (cur == nullptr)
return;
inOrder(cur->left);
std::cout << cur->data << " ";
inOrder(cur->right);
}
//前序
void preOrder()
{
std::cout << "preOrder: ";
preOrder(root);
std::cout << std::endl;
}
void preOrder(Node* cur)
{
if (cur == nullptr)
return;
std::cout << cur->data << " ";
preOrder(cur->left);
preOrder(cur->right);
}
//层序
void levelOrder()
{
std::cout << "levelOrder: ";
int height = level();
for (int i = 1; i <= height; ++i)
{
levelOrder(root, 1, i);
}
std::cout << std::endl;
}
void levelOrder(Node* cur, int i, int height)
{
if (cur == nullptr)
{
return;
}
if (i == height)
{
std::cout << cur->data << " ";
}
else
{
levelOrder(cur->left, i + 1, height);
levelOrder(cur->right, i + 1, height);
}
}
//高度
int level()
{
return level(root);
}
int level(Node* cur)
{
if (cur == nullptr)
return 0;
int leftHeight = level(cur->left) + 1;
int rightHeight = level(cur->right) + 1;
return leftHeight > rightHeight ? leftHeight : rightHeight;
}
// 递归实现获取BST树节点的总数量
int number()
{
return number(root);
}
int number(Node* cur)
{
if (cur == nullptr)
return 0;
return number(cur->left) + number(cur->right) + 1;
}
public://经典例题
//将树镜像,中序从小到大变为从大到小
void mirror()
{
mirror(root);
}
void mirror(Node* cur)
{
if (cur == nullptr)
return;
Node* tmp = cur->left;
cur->left = cur->right;
cur->right = tmp;
mirror(cur->left);
mirror(cur->right);
}
// 判断一颗二叉树是否是BST树
bool isBST()
{
const int SIZE = number();
T* arr = new T[SIZE]();
int pos = 0;
isBST(root, arr, pos);
for (int i = 0; i < SIZE - 1; ++i)
{
std::cout << arr[i] << " ";
if (arr[i] > arr[i + 1])
{
delete[]arr; //2.所以用智能指针,要不然这里就很容易忘了析构
return false;
}
}
delete[]arr;
return true;
}
void isBST(Node* cur, T* arr, int& i)//1.这里的i前面的依靠后面的,需要用&接收,和子集树中的变量作用完全不一样
{
if (cur == nullptr)
return;
isBST(cur->left, arr, i);
arr[i++] = cur->data;
isBST(cur->right, arr, i);
}
// 找满足指定值区间的元素并打印
void findAreaData(int first, int last)
{
std::vector<T> vec;
findAreaData(root, first, last, vec);
for (auto val : vec)
{
std::cout << val << " ";
}
std::cout << std::endl;
}
void findAreaData(Node* node, int first, int last, std::vector<T>& vec)
{
if (node == nullptr)
return;
findAreaData(node->left, first, last, vec);
if (node->data > last)
{
return;
}
if (first <= node->data && last >= node->data)
{
vec.push_back(node->data);
}
findAreaData(node->right, first, last, vec);
}
// 找BST树中,指定的两个值的最近公共祖先节点
int getLCA(int a1, int a2)
{
int min = a1;
int max = a2;
if (a2 < a1)
{
min = a2;
max = a1;
}
return getLCA(root, min, max);
}
int getLCA(Node* cur, int min, int max)
{
if (cur->data < min)
{
return getLCA(cur->right, min, max);
}
else if (cur->data > max)
{
return getLCA(cur->left, min, max);
}
else
{
return cur->data;
}
}
//判断是否是子树
bool isChildTree(user::BST<T>& bst)
{
Node* p = query(_root, bst._root->data);
return isChildTree(p, bst._root);
}
bool isChildTree(Node* node, Node* Cnode)
{
if (node == nullptr && Cnode == nullptr)
{
return true;
}
if (node == nullptr)
{
return false;
}
if (Cnode == nullptr)
{
return true;
}
if (node->_data != Cnode->_data)
{
return false;
}
return (isChildTree(Node * node->_left, Node * Cnode->_left)
&& isChildTree(Node * node->_right, Node * Cnode->_right));
}
// 找BST树中,中序遍历倒数第K个节点的值并返回
int getLastK(int k)
{
return getLastK(root, k)->data;
}
Node* getLastK(Node* cur, int& k)
{
if (cur == nullptr)
return nullptr;
Node* res = getLastK(cur->right, k);
if (res != nullptr)
{
return res;
}
if (--k == 0)
{
return cur;
}
return getLastK(cur->left, k);
}
// 递归实现重建二叉树的过程
void rebuild(int* ar, int arsize, int* br, int brsize)
{
_root = rebuild(ar, 0, arsize - 1, br, 0, brsize - 1);
}
Node* rebuild(int* ar, int i, int iend, int br[], int j, int jend)
{
if (i > iend || j > jend)
return nullptr;
// 用前序遍历数组的第一个元素创建根节点
Node* node = new Node(ar[i]);
for (int k = j; k <= jend; ++k)
{
if (ar[i] == br[k])
{
node->_left = rebuild(ar, i + 1, i + (k - j), br, j, k - 1);
node->_right = rebuild(ar, i + (k - j) + 1, iend, br, k + 1, jend);
break;
}
}
return node;
}
};
}
void insertArray(user::BST<int>& bst, int* ar, int size)
{
for (int i = 0; i < size; ++i)
{
bst.nonInsert(ar[i]);
}
}
int main()
{
int ar[] = { 58, 28, 12, 23, 34, 46, 80, 79, 92, 99 };
const int SIZE = sizeof(ar) / sizeof(ar[0]);
user::BST<int> bst;
insertArray(bst, ar, sizeof(ar) / sizeof(ar[0]));
bst.preOrder();
bst.levelOrder();
std::cout << "number: " << bst.number() << std::endl;
std::cout << "nonselect: " << bst.nonselect(78) << std::endl;
std::cout << "isBST: " << bst.isBST() << std::endl;
bst.findAreaData(20, 80);
std::cout << "getLCA: " << bst.getLCA(80, 46) << std::endl;
std::cout << "getLastK: " << bst.getLastK(4) << std::endl;
//bst.mirror();
//bst.inOrder();
/*
for (int i = 0; i < SIZE; ++i)
{
bst.nonRemove(ar[i]);
bst.inOrder();
}*/
return 0;
}