二叉排序树的基础知识
名称:二叉排序树、二叉搜索树
性质:
1、左子树<根结点
2、右子树>根结点
用途:解决与排名相关的检索要求
构造二叉排序树:
/*
* @Author: mikey.peng
* @Date: 2021-08-08 19:52:23
* @Last Modified by: mikey.peng
* @Last Modified time: 2021-08-08 19:52:23
*/
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;
//结构定义
typedef struct Node{
Node(int key=0,Node *left=nullptr,Node *right=nullptr)
:key(key),left(left),right(right){}
int key;
Node *left,*right;
}Node;
//结构操作
//获取新节点
Node *getNewNode(int key){
return new Node(key);
}
//插入新节点(插入后返回新的根结点的结点地址)
Node *insert(Node *root,int key){
if(root == nullptr) return getNewNode(key);
if(root->key == key) return root;
if(key<root->key)root->left = insert(root->left,key);//向左子树中插入数值
else root->right = insert(root->right,key);
return root;
}
//找到当前节点(两个度的)的前驱结点
Node *predecessor(Node *root){
Node *temp = root->left;
while(temp->right)temp = temp->right;
return temp;
}
//删除操作 //erase是干掉单个结点,clear是干掉整颗树
Node *erase(Node *root,int key){
if(root == nullptr) return root;
if(key < root->key){
root->left = erase(root->left,key);
}else if(root->key<key){
root->right = erase(root->right,key);
}else{
//当前节点就是要删除的结点要分成三种情况来讨论:
//1.度为0的
if(root->left == nullptr&& root->right == nullptr){
delete root;
return nullptr;
}
//2.度为1的
else if(root->right==nullptr || root->left==nullptr){
//如果删除度为1的需要先找到当前节点的唯一子孩子temp
Node *temp = root->left ? root->left:root->right;
delete root;
return temp;
}
//3.度为2的
else{
//首先需要找到当前节点的前驱节点或者后继结点
Node *temp = predecessor(root);
//将前驱结点的值赋值给当前节点
root->key = temp->key;
//到左子树中将当前节点给它删掉
root->left = erase(root->left,temp->key);
}
}
return root;
}
//销毁操作
void clear(Node *root){
if(root == nullptr) return ;
clear(root->left);
clear(root->right);
delete root;
return ;
}
void output(Node *root){
if(root == nullptr)return ;
output(root->left);
cout<<root->key<<" ";
output(root->right);
return ;
}
int main(){
int op,val;
Node *root = nullptr;
while(cin>> op >> val){
switch(op){//op=0执行的是插入操作,op=1执行的是删除操作
case 0: root = insert(root,val);break;
case 1: root = erase(root,val);break;
}
output(root);//中序遍历方式输出二叉排序树
cout<<endl;
}
return 0;
}
AVL树的基础知识
发明者:
G.M.Adelson-Velsky
E.M.Landis
年代:1962年(59岁)
性质:
|H(left)-H(right)|<=1
优点:
由于对每个节点的左右子树的树高做了限制,所以整棵树不会退化成一个链表
使用虚拟空间点NIL 实现AVL树定义
/*
* @Author: mikey.zhaopeng
* @Date: 2021-08-09 20:51:47
* @Last Modified by: mikey.zhaopeng
* @Last Modified time: 2021-08-09 22:46:55
*/
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;
//定义一个虚拟空节点用于替代空地址的 和链表中虚拟头结点作用相似 便于在处理子树空节点的情况
#define NIL (&node::__NIL)//这个NIL结点是有高度(0),有值
struct node{
node(int key=0,int h=0,node *left=NIL,node *right=NIL)
:key(key),h(h),left(left),right(right){}
int key,h;//h表示当前节点所在子树的高度
node *left,*right;
static node __NIL;
};
node node::__NIL;
node *getNewNode(int key){
return new node(key,1);
}
void update_height(node *root){
// if(root->left == nullptr && root->right == nullptr) return ;
// if(root->left == nullptr) root->h = root->right->h +1;
// else if(root->right == nullptr) root->h = root->left->h+1;
//使用NIL虚拟空节点上面这些代码都可以没有
// else
root->h = max(root->left->h,root->right->h)+1;
return ;
}
node *left_rotate(node *root){
node *new_root = root->right;
root->right = new_root->left;
new_root->left = root;
update_height(root);
update_height(new_root);
return new_root;
}
node *right_rotate(node *root){
node *new_root = root->left;
root->left = new_root->right;
new_root->right = root;
update_height(root);
update_height(new_root);
return new_root;
}
node *maintain(node *root){
if(abs(root->left->h-root->right->h)<2) return root;
//此时当前节点需要调整
//首先区分第一个字母是L还是R 此时L
if(root->left->h > root->right->h){
//判断第二个字母是L还是R 此时R
if(root->left->right->h > root->left->left->h){
//LR 先进行小左旋在进行大右旋
root->left = left_rotate(root->left);
}
root = right_rotate(root);
}else {
if(root->right->left->h > root->right->right->h){
root->right = right_rotate(root->right);
}
root = left_rotate(root);
}
return root;
}
node *insert(node *root,int key){
if(root == NIL) return getNewNode(key);
if(root->key == key) return root;
if(root->key > key) root->left = insert(root->left,key);
else root->right = insert(root->right,key);
update_height(root);//重新计算当前节点的高度
return maintain(root);
}
//找到当前节点(两个度的)的前驱结点
node *predecessor(node *root){
node *temp = root->left;
while(temp->right)temp = temp->right;
return temp;
}
node *erase(node *root,int key){
if(root == NIL) return root;
if(key<root->key){
root->left = erase(root->left,key);
}else if(key > root->key) {
root->right = erase(root->right,key);
}else{
//这里度为0和度为1为一种情况 因为temp返回的是度为0的结点地址
if(root->left == NIL || root->right == NIL){
node *temp = root->left =NIL? root->right:root->left;
delete root;
return temp;
}else{
//删除的是度为2的结点地址
node *temp = predecessor(root);
root->key = temp->key;
root->left = erase(root->left,temp->key);
}
}
update_height(root);
return maintain(root);
}
//销毁整棵树
void clear(node *root){
if(root==NIL) return ;
clear(root->left);
clear(root->right);
cout << "delete :" << root->key << endl;
delete root;
return ;
}
void print(node * root){
printf("(%d[%d] | %d,%d)\n",root->key,root->h,root->left->key,root->right->key);
return ;
}
void output(node * root){
if(root == NIL) return ;
print(root);
output(root->left);
output(root->right);
return ;
}
int main(){
int op ,val;
node *root = NIL;
while(cin>>op>>val){
switch(op){
case 0: root = insert(root,val);break;
case 1: root = erase(root,val);break;
}
cout<<endl<<"============avl tree print============"<<endl;
output(root);
cout<<endl<<"============tree print done==========="<<endl;
}
clear(root);
return 0;
}
leetcode - 面试题 04.06. 后继者
class Solution {
public:
TreeNode *pre;
TreeNode *inorder(TreeNode *root,TreeNode *p){
if(root == nullptr) return nullptr;
TreeNode *node;
if(node = inorder(root->left,p)) return node;//如果左子树不为空返回
//pre在这里就会从小到大的访问到每一个结点
if(pre == p) return root;
pre = root;
if(node=inorder(root->right,p))return node;//如果右子树不为空则返回
return nullptr;
}
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
pre =nullptr;
return inorder(root,p);
}
};
- 将二叉搜索树变平衡
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void getNodes(TreeNode *root,vector<TreeNode *> &nodes){
if(root == nullptr) return ;
getNodes(root->left,nodes);
nodes.push_back(root);
getNodes(root->right,nodes);
return ;
}
TreeNode *buildTree(vector<TreeNode *> &nodes,int l,int r){
if(l>r) return nullptr;
int mid = (l+r)>>1;
TreeNode *root = nodes[mid];
root->left = buildTree(nodes,l,mid-1);
root->right = buildTree(nodes,mid+1,r);
return root;
}
TreeNode* balanceBST(TreeNode* root) {
vector<TreeNode *> nodes; //存储这棵树的结点
getNodes(root,nodes);//按照中序遍历获取到每一个结点
return buildTree(nodes,0,nodes.size()-1);//根据动态链表中的结点来建立树,返回的是新建立的树的根结点的地址
}
};
leetcode-108. 将有序数组转换为二叉搜索树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode *buildTree(vector<int> &nums,int l,int r){
if(l>r) return nullptr;
int mid = (l+r)>>1;
TreeNode * root = new TreeNode(nums[mid]);
root->left = buildTree(nums,l,mid-1);
root->right = buildTree(nums,mid+1,r);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return buildTree(nums,0,nums.size()-1);
}
};
leetcode-98. 验证二叉搜索树
class Solution {
public:
int* last = NULL;
TreeNode *pre;
bool inorder(TreeNode *root){
if(root == nullptr) return true;
if(!inorder(root->left))return false;
if (pre != nullptr && root->val<=pre->val){
return false;
}
pre = root;
if(!inorder(root->right))return false;
return true;
}
bool isValidBST(TreeNode* root) {
//fa 1
pre = nullptr;
return inorder(root);
}
};
leetcode-501. 二叉搜索树中的众数
class Solution {
public:
TreeNode *now;//用于记录当前比较节点的值
int cnt,max_cnt;
void getResult(TreeNode *root,vector<int>&ret){
if(root == nullptr) return ;
getResult(root->left,ret);
if(now->val == root->val){
cnt+=1;
}else{
now = root;
cnt = 1;
}
if(max_cnt == cnt){
ret.push_back(now->val);
}else if(cnt>max_cnt){//说明之前找到的都不是最大的众数
max_cnt = cnt;
ret.clear();
ret.push_back(now->val);
}
getResult(root->right,ret);
return ;
}
vector<int> findMode(TreeNode* root) {
int cnt = max_cnt = 0;
now = root;
vector<int> ret;//存储所有的众数
getResult(root,ret);
return ret;
}
};
leetcode-面试题 17.12. BiNode
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode *head,*pre;
TreeNode* convertBiNode(TreeNode* root) {
head = pre = NULL;
inoreder(root);
return head;
}
void inoreder(TreeNode *root){
if(root==NULL) return ;
inoreder(root->left);
if(pre == NULL){
//当前是第一个结点
head = root;
}else{
//让前一个节点向后指向当前节点
pre->right = root;
}
root->left = NULL;
pre = root;
inoreder(root->right);
return ;
}
};
leetcode-剑指 Offer 33. 二叉搜索树的后序遍历序列
class Solution {
public:
int pre;//记录前一个元素的下标
bool verifyPostorder(vector<int>& postorder) {
pre=-1;
return inorder(postorder,0,postorder.size()-1);
}
bool inorder(vector<int> &nums,int l,int r){
if(l>r) return true;//空树满足二叉排序树的性质
int ind=l;
while(nums[ind]<nums[r])++ind;
if(!inorder(nums,l,ind-1)) return false;
if(pre!=-1 && nums[r]<=nums[pre]) return false;
pre = r;//这里r就是根结点
if(!inorder(nums,ind,r-1)) return false;
return true;
}
};
leetcode-1008. 前序遍历构造二叉搜索树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode *buildTree(vector<int>& nums,int l,int r){
if(l>r) return nullptr;
int ind = l+1;
while(ind<=r && nums[ind]<nums[l]) ++ind;
TreeNode *root = new TreeNode(nums[l]);
root-> left = buildTree(nums,l+1,ind-1);
root->right = buildTree(nums,ind,r);
return root;
}
TreeNode* bstFromPreorder(vector<int>& preorder) {
return buildTree(preorder,0,preorder.size()-1);
}
};
leetcode-面试题 04.09. 二叉搜索树序列
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void mergeSequences(
vector<int>&l,int lind,vector<int>&r,int rind,
vector<int>&buff,vector<vector<int>>&ret){
if(lind == l.size() && rind == r.size()){
ret.push_back(buff);
return ;
}
if(lind<l.size()){//说明左子树序列中还有元素,就将左子树序列拿出一个元素添加到buff数组中
buff.push_back(l[lind]);
mergeSequences(l,lind+1,r,rind,buff,ret);
buff.pop_back();//将buff数组还原成原来没有添加的样子
}
if(rind<r.size()){
buff.push_back(r[rind]);
mergeSequences(l,lind,r,rind+1,buff,ret);
buff.pop_back();
}
return ;
}
vector<vector<int>> BSTSequences(TreeNode* root) {
vector<vector<int>> ret;//结果数组
if(root==nullptr){
ret.push_back(vector<int>());//如果为空则放入一个空数组
return ret;
}
//从这开始获取左右子树中的合法序列
vector<vector<int>> l_arr=BSTSequences(root->left);
vector<vector<int>> r_arr=BSTSequences(root->right);
//进行排列组合:左子树中的每一个序列,配上右子树上的每一个序列
for(auto l:l_arr){
for(auto r:r_arr){
vector<int>buff;
buff.push_back(root->val);
mergeSequences(l,0,r,0,buff,ret);//传左右子树的序列,还有左右子树分别选择了多少个元素了,缓冲区,结果数组
}
}
return ret;
}
};