二叉树常考算法汇总

目录

1、二叉树的深度优先遍历DFS和广度优先遍历BFS

2、递归和非递归方式遍历二叉树

(1)递归方式遍历二叉树

(2)非递归方式遍历二叉树

3、递归和非递归(层次遍历)方式求二叉树的高度

4、反转二叉树(小米)

5、红黑树和普通的平衡查找树的区别? 红黑树是如何保证自平衡的?(面试题)

(1)应用场景:TreeMap和TreeSet

(2)特性

(3)两者的对比

6、前中序或中后序还原二叉树(前中序-字节跳动)

7、二叉树左右侧视图(字节跳动)

8、二叉树Z形打印(字节跳动) 

9、二叉搜索树转二叉平衡树,插入删除后的平衡(微软-2022)

(1)平衡

(2)插入和平衡

(3)删除和平衡

10、二叉树的序列化和反序列化(旷世) 


1、二叉树的深度优先遍历DFS和广度优先遍历BFS

法1:栈与队列遍历

#include <iostream>
#include <stack>
#include <queue>
using namespace std;

struct BitNode {
    int data;
    BitNode *left, *right;
    BitNode(int x) :data(x), left(NULL), right(NULL){}
};
void CreateBitTree(BitNode *&root) {
    int key;cin>>key;
    if (key == -1) {
        root = NULL;
    } else {
        root = new BitNode(key);
        CreateBitTree(root->left);
        CreateBitTree(root->right);
    }
}


//深度优先搜索,利用栈,先右后左:先将右子树压栈,再将左子树压栈
void DFS(BitNode *root) {
    stack<BitNode*> stk;
    stk.push(root);
    while (!stk.empty()) {
        BitNode *node = stk.top();
        cout << node->data << ' ';
        stk.pop();
        if (node->right) stk.push(node->right);
        if (node->left)  stk.push(node->left);
    }
}

//广度优先搜索,利用队列,先左后右:先将左子树入队,再将左子树入队
void BFS(BitNode *root) {
    queue<BitNode*> que;
    que.push(root);
    while (!que.empty()) {
        BitNode *node = que.front();
        cout << node->data << ' ';
        que.pop();
        if (node->left) que.push(node->left);
        if (node->right) que.push(node->right);
    }
}

int  main() {
    BitNode *root = NULL;
    CreateBitTree(root);//创建二叉树
    cout<<"dfs=";  DFS(root);//深度优先遍历
    cout<<endl;
    cout<<"bfs=";  BFS(root);//广度优先搜索
    return 0;
}

法2:递归遍历

#include <iostream>
#include <queue>
using namespace std;
struct Node {
    int value;
    Node* left;
    Node* right;
    Node(int value):value(value), left(NULL), right(NULL) {}
};

void DFS(Node* head) {
    if (head == NULL) return;
    cout << head->value << " ";
    DFS(head->left);
    DFS(head->right);
}

void BFS(Node* head) {
    if (head == NULL) return;
    queue<Node*> que;
    que.push(head);
    while (!que.empty()) {
        cout << que.front()->value << " ";
        if (que.front()->left != NULL) que.push(que.front()->left);
        if (que.front()->right != NULL) que.push(que.front()->right);
        que.pop();
    }
}
int main() {
    Node* head = new Node(1);
    head->left = new Node(2);
    head->right = new Node(3);
    head->left->left = new Node(4);
    head->left->right = new Node(5);
    head->right->left = new Node(6);
    head->right->right = new Node(7);
    cout << "DFS=";  DFS(head);
    cout << endl;
    cout << "BFS=";  BFS(head);
    return 0;
}

//法1:栈与队列遍历
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
struct BitNode {
	int data;
	BitNode *left, *right;
	BitNode(int x):data(x), left(NULL), right(NULL){}
};
void CreateBitTree(BitNode * &root) {
	int key;cin>>key;
	if (key == -1) {
		root = NULL;
	} else {
		root = new BitNode(key);
		CreateBitTree(root->left);
		CreateBitTree(root->right);
	}
}


//深度优先搜索,利用栈,先右后左:先将右子树压栈,再将左子树压栈
void DFS(BitNode *root) {
	stack<BitNode*> stk;
	stk.push(root);
	while (!stk.empty()) {
		BitNode *node = stk.top();
		cout << node->data << " ";
		stk.pop();
		if (node->right) stk.push(node->right);
		if (node->left) stk.push(node->left);
	}
}

//广度优先搜索,利用队列,先左后右:先将左子树入队,再将左子树入队
void BFS(BitNode *root) {
	queue<BitNode*> que;
	que.push(root);
	while (!que.empty()) {
		BitNode *node = que.front();
		cout << node->data << " ";
		que.pop();
		if (node->left) que.push(node->left);
		if (node->right) que.push(node->right);
	}
}

int main() {
	BitNode *root = NULL;
	CreateBitTree(root);//创建二叉树
	cout<<"dfs="; DFS(root);//深度优先遍历
	cout<<endl;
	cout<<"bfs="; BFS(root);//广度优先搜索
	return 0;
}
/*
输入如下:
1 2 4 -1 -1 5 -1 -1 3 6 -1 -1 7 -1 -1
输入如下:
dfs=1 2 4 5 3 6 7 
bfs=1 2 3 4 5 6 7
*/
//法2:递归遍历
#include <iostream>
#include <queue>
using namespace std;
struct Node {
	int value;
	Node* left;
	Node* right;
	Node(int value):value(value), left(NULL), right(NULL) {}
};

void DFS(Node* head) {
	if (head == NULL) return;
	cout << head->value << " ";
	DFS(head->left);
	DFS(head->right);
}

void BFS(Node* head) {
	if (head == NULL) return;
	queue<Node*> que;
	que.push(head);
	while (!que.empty()) {
		cout << que.front()->value << " ";
		if (que.front()->left != NULL) que.push(que.front()->left);
		if (que.front()->right != NULL) que.push(que.front()->right);
		que.pop();
	}
}
int main() {
	Node* head = new Node(1);
	head->left = new Node(2);
	head->right = new Node(3);
	head->left->left = new Node(4);
	head->left->right = new Node(5);
	head->right->left = new Node(6);
	head->right->right = new Node(7);
	cout << "DFS="; DFS(head);
	cout << endl;
	cout << "BFS="; BFS(head);
	return 0;
}
/*
DFS=1 2 4 5 3 6 7 
BFS=1 2 3 4 5 6 7 
*/

2、递归和非递归方式遍历二叉树

(1)递归方式遍历二叉树

void preOrder(BTNode * head) {
    if (head == NULL) return NULL;
    cout<<head->data<<' ';
    preOrder(head->left);
    preOrder(head->right);
}
void inOrder(BTNode * head) {
    if (head == NULL) return NULL;
    preOrder(head->left);
    cout<<head->data<<' ';
    preOrder(head->right);
}
void postOrder(BTNode * head) {
    if (head == NULL) return NULL;
    preOrder(head->left);
    preOrder(head->right);
    cout<<head->data<<' ';
}

(2)非递归方式遍历二叉树

先序遍历(1个栈):
1、首先申请一个新的栈记为stack
2、然后将头节点head压入stack中
3、每次从stack中弹出栈顶节点,记为cur,然后打印cur节点的值,如果cur右孩子不为空,右孩子先压入stack中,最后如果左孩子不为空的话,将左孩子压入stack中。
4、不断重复步骤3,直到stack为空,全部过程结束。
中序遍历(1个栈):
1、首先申请一个新的栈记为stack,申请一个变量cur,初始令cur等于头节点。
2、先把cur节点雅茹栈中国呢,对以cur节点为头的整棵子树来说,依次把整棵树的左边界压入栈中,即不断令cur=cur.left,重复步骤2。
3、不断重复步骤2,直到发现cur为空,此时从stack中弹出一个节点,记为node,打印node的值,并让cur=node.right,然后继续重复步骤2。
4、当stack为空并且cur为空时,整个过程结束
后序遍历(2个栈):
1、申请一个栈,记为s1,然后将头节点压入s1中    
2、从s1中弹出的节点记为cur,先把cur的左孩子压入s1中,然后cur的右孩子压入s1中
3、在整个过程中,每一个从s1中弹出的节点都放进第二个栈s2中
4、不断重复步骤2和步骤3,直到s1为空,过程停止。
5、从s2中依次弹出节点并打印。
后序遍历(1个栈):
1、首先申请一个新的栈记为stack,将头节点压入stack,同时设置2个变量h和c,在整个流程中,h代表最近一次弹出并打印的节点,c代表
当前stack的栈顶节点,初始时令h为头节点,c为null
2、每次令c等于当前stack的栈顶节点,但是不从stack中弹出节点,此时分以下3种情况:
(1)如果c的左孩子不为空,且h不等于c的左孩子,也不等于c的右孩子,则把c的左孩子压入stack中
(2)如果(1)不成立,并且c的右孩子不为空,并且h不等于c的右孩子,则把c的右孩子压入stack中
(3)如果(1)(2)都不成立,那么从stack中弹出c并打印,然后令h等于c
3、一直重复步骤2,直到stack为空,过程停止。

代码框架详见:非递归方式先序+中序+后序遍历二叉树

前序:
(1)根节点入栈。
(2)循环:出栈并打印,有右则压右,有左压左。
stk.push(head);
while(!stk.empty()) {
    cur=stk.top();cout<<cur->data<<" ";stk.pop();
    if (cur->right) stk.push(cur->right);
    if (cur->left) stk.push(cur->left);
}
中序:
(1)从根节点开始一直往左走,边走边入栈。
(2)循环:出栈并打印,向右走,有右则压右。
while(!stk.empty() || p!=NULL) {
    if (p!=NULL) {
        stk.push(p);
        p=p->left;
    } else {
        p=stk.top();cout<<cur->data<<" ";stk.pop();
        p=p->right;
    }
}

后序:
(1)根节点入栈.
(2)循环:栈顶的左右节点为空或都遍历过,则出栈并打印并标记访问过。有右则压右,有左压左。
stk.push(head);visited=NULL;
while(!stk.empty()) {
    cur=stk.top();

    if ( 
    (cur->left==NULL&&cur->right==NULL) || 
    (visited!=NULL && (cur->left==visited&&cur->right=visited))
    ) {
        cout<<cur->data<<" ";stk.pop();visited=cur;
    }
    if (cur->right) stk.push(cur->right);
    if (cur->left) stk.push(cur->left);
}

#include<iostream>
#include<stack>
using namespace std;
struct BTNode {
	int data;
	BTNode *left;
	BTNode *right;
	BTNode(int _data=-1):data(_data),left(NULL),right(NULL) {}
};

void preOrder(BTNode *head) {
		if (head == NULL)  return ;
		stack<BTNode *> stk;stk.push(head);
		while (!stk.empty()){			
			head= stk.top();stk.pop();cout<<head->data<<" ";
			if(head->right != NULL) stk.push(head->right);
			if(head->left != NULL) stk.push(head->left);
		}
}
 
 
void inOrder(BTNode *head) {
	if (head == NULL)  return ;
	stack<BTNode *> stk;BTNode *node;
	while (!stk.empty() || head != NULL){
		if (head != NULL){
			stk.push(head);
			head = head->left;
		} else{
		    head = stk.top();stk.pop();cout<<head->data<<" ";
			head = head->right;
		}
	}
}
void postOrder(BTNode *head) {
	if (head == NULL) return;
	stack<BTNode *>stk;BTNode *cur, *visited;
	cur=head;visited=NULL;
	stk.push(head);
	while (!stk.empty()) {
		cur = stk.top();
		if ((cur->left==NULL&&cur->right==NULL) || 
		((visited==cur->left || visited==cur->right) && visited!=NULL)) {
			cout << cur->data << " ";
			stk.pop();
			visited = cur;
		} else {
			if (cur->right != NULL) stk.push(cur->right);
			if (cur->left != NULL) stk.push(cur->left);
		}
	}
}
/*void postOrder(BTNode * head){
	if (head == NULL) return ; 
		stack<BTNode *> s1,s2;//= new stack<BTNode>();
		s1.push(head);
		while (!s1.empty()){
			head = s1.top();s1.pop();s2.push(head);
			if(head->left != NULL) s1.push(head->left);
			if (head->right != NULL) s1.push(head->right);
		}
		while (!s2.empty()){
			BTNode *cur = s2.top(); s2.pop(); cout<<cur->data<<" ";
		}
}*/
int main() {
    BTNode *head = new BTNode(1);
    head->left = new BTNode(2);
    head->right = new BTNode(3);
    head->left->left = new BTNode(4);
	head->left->right = new BTNode(5);
	head->right->left = new BTNode(6);
	head->right->right = new BTNode(7);
	cout<<"非递归前序遍历:";preOrder(head);cout<<endl;
    cout<<"非递归中序遍历:";inOrder(head);cout<<endl;
    cout<<"非递归后序遍历:";postOrder(head);cout<<endl;
    return 0;
}
/*输出如下:
非递归前序遍历:1 2 4 5 3 6 7 
非递归中序遍历:4 2 5 1 6 3 7 
非递归后序遍历:4 5 2 6 7 3 1 
*/

3、递归和非递归(层次遍历)方式求二叉树的高度

递归

int getDepth(TreeNode *root)
{
    if(root == NULL) return 0;//空树深度为零
    int leftDepth=getDepth(root.left);
    int rightDepth=getDepth(root.right);
    return leftDepth>rightDepth?leftDepth+1:rightDepth+1;
}

非递归---层次遍历求树的高度
int GetDepth(bitreenode *root) {
    int depth=0;
    bitreenode *p=root;
    queue<bitreenode*> q;
    q.push(p);//根指针入队
    while(!q.empty()) {
        depth++;//高度加一
        int width=q.size();//获取当前层次宽度
        for(int i=0;i<width;i++) {
            p=q.front();//获取队顶元素
            q.pop();//弹出队顶元素
            if(p->leftchild!=NULL) q.push(p->leftchild);
            if(p->rightchild!=NULL) q.push(p->rightchild);
        }
    }
    cout<<depth<<endl;
}

(1)根节点入栈
(2)循环:栈不为空则h++
(3)遍历栈所有元素:栈元素pop,有左入左,有右入右
PS:遍历过程其实就是层次遍历

#include<iostream>
#include<queue>
using namespace std;
struct BTNode {
	int data;
	BTNode *left;
	BTNode *right;
	BTNode(int _data=-1):data(_data),left(NULL),right(NULL) {}
};
int GetDepth(BTNode *root) {
	int depth=0;
	BTNode *p=root;
	queue<BTNode *> q;
	q.push(p);//根指针入队
	while(!q.empty()) {
		depth++;//高度加一
		int width=q.size();//获取当前层次宽度
		for(int i=0;i<width;i++) {
			p=q.front();//获取队顶元素
			q.pop();//弹出队顶元素
			if(p->left!=NULL) q.push(p->left);
			if(p->right!=NULL) q.push(p->right);
		}
	}
	cout<<depth<<endl;
	return depth;
}
int main() {
    BTNode *head = new BTNode(1);
    head->left = new BTNode(2);
    head->right = new BTNode(3);
    head->left->left = new BTNode(4);
	head->left->right = new BTNode(5);
	head->right->left = new BTNode(6);
	head->right->right = new BTNode(7);
	GetDepth(head);
    return 0;
}
/*输出:3 */

4、反转二叉树(小米)

#include <iostream>
#include<queue>
using namespace std;
struct BTNode{
    int val;
    BTNode * left;
    BTNode * right;
    BTNode(int x=0):val(x),left(NULL),right(NULL){};
};
//只打印反转后的二叉树
void reverseBpsPrint(BTNode * root) {
    queue<BTNode *> que; BTNode * node;
    que.push(root);
    while(!que.empty()) {
        node = que.front();
        cout<< node->val <<" ";
        que.pop();
        if(node->right) que.push(node->right);
        if(node->left) que.push(node->left);
    }
}
void swap(BTNode * &a, BTNode * &b) {
    BTNode * c = a; a = b; b = c;
}
//返回反转后的二叉树
BTNode * reserve(BTNode * root) {
    if(root == NULL || (root->left==NULL && root->right==NULL)) 
        return root;
    if(root->left != NULL && root->right != NULL){
        swap(root->left, root->right);
        root->left = reserve(root->left);
        root->right = reserve(root->right);
    } else if (root->left != NULL){
        root->right->val = root->left->val;
        root->left = NULL;
        return root;
    } else{
        root->left->val = root->right->val;
        root->right = NULL;
        return root;
    }
    return root; 
}

void bfsPrint(BTNode * root) {
    queue<BTNode *> que; BTNode * node;
    que.push(root);
    while(!que.empty()) {
        node = que.front();
        cout<< node->val <<" ";
        que.pop();
        if(node->left) que.push(node->left);
        if(node->right) que.push(node->right);
    }
}


int main(){
    BTNode * root = new BTNode(1);//注意此处要new 
    root->left = new BTNode(2); root->right = new BTNode(3);
    root->left->left = new BTNode(4); root->left->right = new BTNode(5); 
    root->right->left = new BTNode(6); root->right->right = new BTNode(7);
    cout<<"1.只打印反转结果=";reverseBpsPrint(root);
    cout<<endl<<"2.递归反转后的=";
    BTNode * reverseRoot = reserve(root); bfsPrint(reverseRoot);
    return 0;
}
/*
1.只打印反转结果=1 3 2 7 6 5 4 
2.递归反转后的=1 3 2 7 6 5 4 
*/

5、红黑树和普通的平衡查找树的区别? 红黑树是如何保证自平衡的?(面试题)

(1)应用场景:TreeMap和TreeSet

Java语言中TreeMap和TreeSet的底层结构就是红黑树。一般工程中喜欢使用红黑树而不是其它二叉查找树

(2)特性

红黑树除了具备二叉查找树的基本特性之外,还具备以下特性:
红黑树(rbtree)5个性质
(1)每个结点要么是“红色”,要么是“黑色”(后面将说明)  
(2)根结点永远是“黑色”的 
(3)所有的叶结点都是空结点,并且是“黑色”的 
(4)如果一个结点是“红色”的,那么它的两个子结点都是“黑色”的 
(5)结点到其子孙结点的每条简单路径都包含相同数目的“黑色”结点 
PS:根到叶子节点的最长路径<=2*最短路径 

平衡二叉树(avl)3个性质
(1)一棵n个结点的AVL树的其高度保持在0(log2(n)),不会超过3/2log2(n+1) 
(2)一棵n个结点的AVL树的平均搜索长度保持在0(log2(n)). 
(3)一棵n个结点的AVL树删除一个结点做平衡化旋转所需要的时间为0(log2(n)).

(3)两者的对比

A. avl树是高度平衡的,频繁的插入和删除,会引起频繁的reblance,导致效率下降,普通的二叉查找树(非平衡二叉查找树)在极端情况下可能会退化为链表的结构,退化后元素的添加、删除、查询时,时间复杂度退化为O(n)
rbtree的高度近似log2n,它的插入、删除、查找的复杂度都是O(logN),红黑树不是高度平衡的,算是一种折中,插入最多2次旋转,删除最多3次旋转;

B. rbtree可以通过[变色、左旋、右旋]实现自平衡,详见:29-红黑树和平衡二叉树有什么区别? | 码农家园

6、前中序或中后序还原二叉树(前中序-字节跳动)

二叉树的 先序+中序=后序,后序+中序=先序_筑梦悠然的博客-CSDN博客

7、二叉树左右侧视图(字节跳动)

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct BTNode {
	int data;
	BTNode *left;
	BTNode *right;
	BTNode(int _data=-1):data(_data),left(NULL),right(NULL) {}
};//分号

vector<int> leftSideView(BTNode *root) {
  vector<int> res;
  if (!root) return res;
  queue<BTNode*> q;
  q.push(root);
  while (!q.empty()) {
      res.push_back(q.back()->data);
      int size = q.size();
      for (int i = 0; i < size; ++i) {
          BTNode *node = q.front();
          q.pop();
          if (node->left) q.push(node->right);
          if (node->right) q.push(node->left);
      }
  }
  return res;
}
vector<int> rightSideView(BTNode *root) {
  vector<int> res;
  if (!root) return res;
  queue<BTNode*> q;
  q.push(root);
  while (!q.empty()) {
      res.push_back(q.back()->data);
      int size = q.size();
      for (int i = 0; i < size; ++i) {
          BTNode *node = q.front();
          q.pop();
          if (node->left) q.push(node->left);
          if (node->right) q.push(node->right);
      }
  }
  return res;
}

int main () {
    BTNode *head = new BTNode(1);
    head->left = new BTNode(2);
    head->right = new BTNode(3);
    head->left->left = new BTNode(4);
	head->left->right = new BTNode(5);
	head->right->left = new BTNode(6);
	head->right->right = new BTNode(7);
	vector<int> vec1 = leftSideView(head);
    for (int i=0; i<vec1.size(); i++) cout<<vec1[i]<<" ";
    cout<<endl;
    vector<int> vec2 = rightSideView(head);
    for (int j=0; j<vec1.size(); j++) cout<<<<vec2[j]<<" ";
    return 0;
}
/*左视图=124,右视图=137*/

8、二叉树Z形打印(字节跳动) 

#include<iostream>
#include<stack>
using namespace std;
struct BTNode {
	int data;
	BTNode *left;
	BTNode *right;
	BTNode(int _data=-1):data(_data),left(NULL),right(NULL) {}
};//分号

//按'Z'或'之'字形打印二叉树
void printTree(BTNode* root) {
    if (root == NULL) return ;
    stack<BTNode*> oddStack,evenStack;//oddStack奇数栈,evenStack偶数栈
    oddStack.push(root); //根节点入奇数栈
    BTNode* tmpNode = NULL; // 临时节点
    int line = 1; //第一行
    while (!oddStack.empty() || !evenStack.empty()) {
        if (line%2 == 1) { // 奇数行
            while (!oddStack.empty()) { // 判断奇数栈是否为空
                tmpNode = oddStack.top(); oddStack.pop();// 奇数栈栈顶元素出栈
                cout<< tmpNode->data <<" ";
                //偶数行进栈顺序:先左后右
                if (tmpNode->left != NULL) evenStack.push(tmpNode->left);
                if (tmpNode->right != NULL) evenStack.push(tmpNode->right);
            }
        } else { // 偶数行
            while (!evenStack.empty()) { // 判断偶数栈是否为空
                tmpNode = evenStack.top(); evenStack.pop();// 偶数栈栈顶元素出栈
                cout<< tmpNode->data <<" ";
                //偶数行进栈顺序:先右后左
                if (tmpNode->right != NULL) oddStack.push(tmpNode->right);
                if (tmpNode->left != NULL) oddStack.push(tmpNode->left);
            }
        }
        line++;//行数+1
    }
}

int main () {
    BTNode *head = new BTNode(1);
    head->left = new BTNode(2);
    head->right = new BTNode(3);
    head->left->left = new BTNode(4);
	head->left->right = new BTNode(5);
	head->right->left = new BTNode(6);
	head->right->right = new BTNode(7);
	printTree(head);
    return 0;
}
/*1 3 2 4 5 6 7*/

9、二叉搜索树转二叉平衡树,插入删除后的平衡(微软-2022)

https://juejin.cn/post/6844904006033080333 这里有具体示意图

(1)平衡

(2)插入和平衡

#include<iostream>
#include<queue>
using namespace std;
struct AVLNode {
	int data;
	AVLNode *lChild;
	AVLNode *rChild;
	AVLNode(int _data=-1):data(_data),lChild(NULL),rChild(NULL) {}
};//分号

//获取树的高度
int Height(AVLNode *p) {
	if (p == NULL) return 0;
	int i = Height(p->lChild);
	int j = Height(p->rChild);
	return i>=j ? i+1 : j+1;
}
//平衡因子=左子树高度-右子树高度
int BalanceFactor(AVLNode *p) {
	return Height(p->lChild) - Height(p->rChild);
}

//LL(左大,提升左节点为根节点)
AVLNode* LL_Rotation(AVLNode *subRoot) {
	AVLNode* temp = subRoot->lChild;
	subRoot->lChild = temp->rChild;
	temp->rChild = subRoot;
	//完成旋转操作之后,该处分支结点(原为subRoot)发生了变化,
	//因此要返回新的分支节点指针供其父节点更新孩子指针
	return temp;
}
//RR(右大,提升右节点为根节点)
AVLNode* RR_Rotation(AVLNode *subRoot) {
	AVLNode* temp = subRoot->rChild;
	subRoot->rChild = temp->lChild;
	temp->lChild = subRoot;
	return temp;
}
//RL(右子树的左子树大,提升右的左节点为根节点)
AVLNode* RL_Rotation(AVLNode *subRoot) {
	//对subRoot右孩子结点LL旋转后,更新subRoot右结点指针
	subRoot->rChild=LL_Rotation(subRoot->rChild);  
	return RR_Rotation(subRoot);//返回新的分支结点供原分支节点的父节点更新孩子指针
}
//LR(左子树的右子树大,提升左的右节点为根节点)
AVLNode* LR_Rotation(AVLNode *subRoot) {
	subRoot-> lChild = RR_Rotation(subRoot->lChild);  
	return LL_Rotation(subRoot);
}
//平衡调整
AVLNode* Balancee(AVLNode* subRoot) {
	int bf = BalanceFactor(subRoot);
	if (bf > 1) {//左子树更高
	    //左孩子结点平衡因子>0说明新节点多在了左子树上,因此调用LL_Rotation
		if (BalanceFactor(subRoot->lChild) > 0) subRoot = LL_Rotation(subRoot);
		//左孩子结点平衡因子<0说明新节点多在了右子树上,因此调用LR_Rotation
		else subRoot = LR_Rotation(subRoot);	
	} else if (bf < -1) {//右子树更高
		//右孩子结点平衡因子>0说明新节点多在了左子树上,因此调用RL_Rotation
		if (BalanceFactor(subRoot->rChild) > 0) subRoot = RL_Rotation(subRoot);
		//右孩子结点平衡因子<0说明新节点多在了右子树上上,因此调用RR_Rotation
		else subRoot = RR_Rotation(subRoot);
	}
	//对分支结点进行平衡操作后可能会更新该分支节点,故将新的分支结点返回供原父结点更新孩子指针
	return subRoot;
}
//插入-递归
//对子树上进行插入操作后都需要平衡操作,可能会改变该子树的根节点,
//因此设置返回值记录完成操作后子树的根结点指针)
void Insert(AVLNode* &subRoot, const int k) {
	if (subRoot == NULL) {//根节点插入
	    subRoot = new AVLNode(k);
	} else if (k > subRoot->data) {//右子树插入
		Insert(subRoot->rChild, k);
		subRoot = Balancee(subRoot);
	} else if (k < subRoot->data) {//左子树插入
		Insert(subRoot->lChild, k);
		subRoot = Balancee(subRoot);
	}
}
//广度优先遍历
void BFS(AVLNode* root) {
    if (root == NULL) return;
    queue<AVLNode*> que;
    que.push(root);
    while (!que.empty()) {
        cout << que.front()->data << " ";
        if (que.front()->lChild != NULL) que.push(que.front()->lChild);
        if (que.front()->rChild != NULL) que.push(que.front()->rChild);
        que.pop();
    }
    cout << endl;
}

int main () {
    //LL:53624[1],RR:21435[6],RL:21546[3],LR:52613[4]
	AVLNode *r1,*r2,*r3,*r4; r1=r2=r3=r4=NULL;
	
	Insert(r1,5);Insert(r1,3);Insert(r1,6);Insert(r1,2);Insert(r1,4);Insert(r1,1);
	BFS(r1);/* 3 2 5 1 4 6 */
	
    Insert(r2,2);Insert(r2,1);Insert(r2,4);Insert(r2,3);Insert(r2,5);Insert(r2,6);
	BFS(r2);/* 4 2 5 1 3 6 */
	
	Insert(r3,2);Insert(r3,1);Insert(r3,5);Insert(r3,4);Insert(r3,6);Insert(r3,3);
	BFS(r3);/* 4 2 5 1 3 6 */
	
	Insert(r4,5);Insert(r4,2);Insert(r4,6);Insert(r4,1);Insert(r4,3);Insert(r4,4);
	BFS(r4);/* 3 2 5 1 4 6 */
	
	return 0;
}

(3)删除和平衡

//返回值为x的结点指针
AVLNode* Search(int x) {
	AVLNode *p = root;
	while (p) {
		if (p->data == x) break;
		else if (p->data < x) p = p->rChild;
		else p = p->lChild;
	}
	return p;
}
//返回子树最大值结点的指针
AVLNode* TreeMax(AVLNode* p) {
	if (!p) return NULL;
	while (p->rChild) p = p->rChild;
	return p;
}
//返回子树最小值结点的指针
AVLNode* TreeMin(AVLNode* p) {
	if (!p) return NULL;
	while (p->lChild) subTree = p->lChild;
	return p;
}


//删除和平衡
AVLNode* Remove(AVLNode* subRoot, int x) {
	if (!Search(x)) {
		cout << "不存在值为" << x << "的结点!" << endl;
		return root;
	}
	if (!root) return root;
		
	if (subRoot->data == x) {//情况1:要删除的就是该树的根节点
		if (subRoot->lChild && subRoot->rChild) {//情况1.1:该树的左右子树都存在
			if (BalanceFactor(subRoot)>0) {
				//左子树高于右子树,则根节点的值替换为其直接前驱的值,然后转化为删除
				//其直接前驱(其位于左子树上,也就意味着去降低左子树高度)
				AVLNode *tmp = TreeMax(subRoot->lChild); //直接前驱就是左子树的最大值
				subRoot->data = tmp->data;
				//递归调用Remove()删除subRoot的左子树上的前驱结点后,Remove()返回可能为
				//新的subRoot的左子树根节点供subRoot更新左孩子结点((Remove()会调用Balance()函数平衡其操作的树))
				subRoot->lChild = Remove(subRoot->lChild, tmp->data);
			} else {
				AVLNode *tmp = TreeMin(subRoot->rChild);
				subRoot->data = tmp->data;
				subRoot->rChild = Remove(subRoot->rChild, tmp->data);
			}
		} else {//情况1.2:只存在一颗子树或者都不存在
			//直接将根节点更新为其孩子结点(都不存在则为NULL)
			AVLNode * tmp = subRoot;
			subRoot = (subRoot->lChild) ? (subRoot->lChild) : (subRoot->rChild);
			delete tmp;
			tmp = NULL;
		}
	} else if (x < subRoot->data) { //情况2:要删除的节点位于左子树上
		//递归调用,在subRoot的左子树上进行删除操作,并返回新的左子树根节点供subRoot更新左孩子指针
		subRoot->lChild = Remove(subRoot->lChild, x);
		//在subRoot的左子树上完成删除操作后,可能导致该树不平衡,故需要进行平衡操作并更新当前根节点
		if (BalanceFactor(subRoot) < -1) subRoot = Balancee(root);
	} else {//情况3:要删除的节点位于右子树上
		subRoot->rChild = Remove(subRoot->rChild, x);
		if (BalanceFactor(subRoot) >1) subRoot = Balancee(subRoot);
	}
	//返回该树当前根节点供其父节点更新孩子节点
	return subRoot;
}

10、二叉树的序列化和反序列化(旷世) 

(1)序列化,借助string类型来拼接序列化的字符串。只需要前序遍历二叉树,当遇到根节点为空时,追加"#",并退出递归,否则追加二叉树的根节点值,接着追加逗号。接下来只需递归实现左子树和右子树的序列化。那么,序列化之后就得到了string类型的字符串。
2.反序列化,如果string为空,则直接返回退出。如果遇到"#",则为空节点,退出递归。否则,找到字符数组中的一个二叉树节点值,然后构造根节点,如果此时到达字符末尾,直接返回根节点,否则继续遍历。然后根结点的左右指针分别连接左子树的递归实现结果和右子树的递归实现结果。

#include<iostream>
#include<string>
#include<queue>
using namespace std;
struct BTNode {
	int data;
	BTNode *left;
	BTNode *right;
	BTNode(int _data=-1):data(_data),left(NULL),right(NULL) {}
};//分号
//序列化二叉树
void serialize(BTNode* root, string& s) {
    if(root == NULL) {s.push_back('#'); s.push_back('!'); return;}
    s += to_string(root->data); s.push_back('!');
    serialize(root->left, s);
    serialize(root->right, s);
}
//反序列化二叉树
BTNode* deserialize(string& s) {
    if (s.empty()) return NULL;
    if (s[0] == '#') {s = s.substr(2); return NULL;}
    BTNode* root = new BTNode(stoi(s));
    s = s.substr(s.find_first_of('!') + 1);
    root->left = deserialize(s);
    root->right = deserialize(s);
    return root;
}
int main() {
    BTNode* root = new BTNode(1);
    root->left = new BTNode(3);
    root->right = new BTNode(5);
    // //序列化,结果为 1!3!#!#!5!#!#!
    string s1; serialize(root, s1); cout<<s1<<endl;
    //反序列化, 结果为 根1左3右5
    string s2 = "1!3!#!#!5!#!#!";
    BTNode* node = deserialize(s2);
    cout<< node->data <<" "<< node->left->data <<" "<< node->right->data<<endl;
    return 0;
}
/* 
1!3!#!#!5!#!#!
1 3 5
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值