二叉树基本操作-个人总结

二叉树:
对于各节点值不重复建树(同时得到后序):(前序+中序建树)

TreeNode* build( vector<int>pre , vector<int>in ) {
	if( !pre.size() || !in.size() ) {
		return NULL ;
	}
	TreeNode* rt = new TreeNode(pre[0]);
	for( int i = 0 ; i < in.size() ; i++ ) {
		if( in[i] == pre[0] ) {
			vector<int>p1( pre.begin() + 1 , pre.begin() + i + 1 );
			vector<int>v1( in.begin() , in.begin() + i ) ;
			rt->l = build( p1 , v1 );
			vector<int>p2( pre.begin() + i + 1 , pre.end() );
			vector<int>v2( in.begin() + i + 1 , in.end() ) ;
			rt->r = build( p2 , v2 );
			//res.push_back(rt->val);
			//建树时得到后序序列
			break ;
		}
	}
	return rt ;
}
// 节省空间一点的版本
/**
 * 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* __build(vector<int>& preorder, vector<int>& inorder, int l_pre, int l_in, int r_in) {
        if(l_in > r_in) return nullptr;
        TreeNode* rt = new TreeNode(preorder[l_pre]);
        int i = mp[preorder[l_pre]];
        rt -> left = __build(preorder, inorder, l_pre+1, l_in, i-1);
        rt -> right = __build(preorder, inorder, l_pre+i+1-l_in, i+1, r_in);		// 这里要注意两个边界,尤其是前序的位置
        return rt;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        for(int i = 0; i < inorder.size(); ++i) {
            mp[inorder[i]] = i;
        }
        return __build(preorder, inorder, 0, 0, inorder.size()-1);
    }
private:
    unordered_map<int, int>mp;
};
// 迭代版本
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        if(!n) return nullptr;
        TreeNode* rt = new TreeNode(preorder[0]);
        stack<TreeNode*>s;
        s.push(rt);
        int in_idx = 0;
        for(int i = 1; i < n; ++i) {
            TreeNode* p = s.top();
            if(p -> val != inorder[in_idx]) {   // 利用前序数组构建左子树
                p -> left = new TreeNode(preorder[i]);
                s.push(p->left);
            } else {                            // 到了左下角,需要往上走并处理右子树
                while(!s.empty() && s.top() -> val == inorder[in_idx]) {
                    p = s.top();
                    s.pop();
                    ++in_idx;
                }
                p -> right = new TreeNode(preorder[i]);
                s.push(p->right);
            }
        }
        return rt;
    }
};

二叉树的深度

    int TreeDepth(TreeNode* rt){
        if( rt == NULL ) return 0 ; 
        return max( TreeDepth( rt -> left ) , TreeDepth( rt -> right ) ) + 1 ; 
    }

下面代码包含 根据前序建树递归版本非递归版前,中,后遍历
因为是考研的时候写的,结构体写的比较非人类 - -。栈等也都是模拟的- -。

#include <iostream>
#include <cstdio>
#define ElemType char
#define MaxSize 20 
using namespace std;
typedef struct BiTNode{
    ElemType data ;
    struct BiTNode  *lchild , *rchild ;
}BiTNode , *BiTree ;
typedef struct {
    BiTNode *data[MaxSize] ;
    int top ; 
}SqStack ; 

void InitStack( SqStack &s ){
    s.top = -1 ;
}

bool IsEmpty( SqStack s ){
    if( ~s.top ) return false ;
    return true ; 
}

void Push( SqStack &s , BiTNode *x ){
    s.data[++s.top] = x ; 
}

BiTree Pop( SqStack &s ){
    return s.data[s.top--] ;
}

BiTree GetTop( SqStack s ){
    return s.data[s.top] ;
}

void PreOrderTraverse_recur( BiTree b ){ // recursive
    printf("%c ", b -> data );
    if( b -> lchild ) PreOrderTraverse_recur( b -> lchild ) ;
    if( b -> rchild ) PreOrderTraverse_recur( b -> rchild ) ;
}

void InOrderTraverse_recur( BiTree b ){ // recursive
    if( b -> lchild ) InOrderTraverse_recur( b -> lchild ) ; 
    printf("%c ",b -> data );
    if( b -> rchild ) InOrderTraverse_recur( b -> rchild ) ;
}

void PostOrderTraverse_recur( BiTree b ){ // recursive
    if( b -> lchild ) PostOrderTraverse_recur( b -> lchild ) ; 
    if( b -> rchild ) PostOrderTraverse_recur( b -> rchild ) ;
    printf("%c ",b -> data );
}

void PreOrderTraverse( BiTree b ){
    SqStack s ; 
    InitStack( s ) ; 
    BiTNode *p = b ;
    while( p || !IsEmpty(s) ){
        while( p ){
            printf("%c ",p->data);
            Push( s , p ) ;
            p = p -> lchild ;
        }  
        if( !IsEmpty(s) ){
            p = Pop(s) ;
            p = p -> rchild ; 
        }
    }
}

void InOrderTraverse( BiTree b ){
    SqStack s ; InitStack( s ) ;
    BiTNode *p = b ;
    while( p || !IsEmpty(s) ){
        if( p ){
            Push( s , p ) ;
            p = p -> lchild ; 
        }else{
            p = Pop( s ) ;
            printf("%c ",p->data) ;
            p = p -> rchild ; 
        }
    }
}

void PostOrderTraverse( BiTree b ){
    SqStack s ; InitStack( s ) ;
    BiTNode *p = b ;
    BiTNode *r = NULL ; 
    while( p || !IsEmpty(s) ){
        if(p){
            Push( s , p ) ;
            p = p -> lchild ;
        }else{
            p = GetTop( s ) ; 
            if( p -> rchild && r != p -> rchild ) p = p -> rchild ;
            else{
                p = Pop( s ) ;
                printf("%c ",p->data) ;
                r = p ;
                p = NULL ; 
            }
        }
    }
}


char c ; 
void PreOrderBuild( BiTree &b ){
    scanf("%c",&c) ;
    if( c == '#' ) return ; 
    b = new BiTNode() ; 
    b -> data = c ;     
    PreOrderBuild( b -> lchild ) ;
    PreOrderBuild( b -> rchild ) ;
}

int main(){
    BiTree b ;
    PreOrderBuild( b ) ; 
    // non-recursive
    printf("PreOrderTraverse: \n");
    PreOrderTraverse( b ) ;puts("");
    printf("InOrderTraverse: \n");
    InOrderTraverse( b ) ;puts("") ;
    printf("PostOrderTraverse: \n");
    PostOrderTraverse( b ) ;puts("") ; 
    // recursive
    printf("PreOrderTraverse(recursive): \n");
    PreOrderTraverse_recur( b ) ;puts("");
    printf("InOrderTraverse(recursive): \n");
    InOrderTraverse_recur( b ) ;puts("") ;
    printf("PostOrderTraverse(recursive): \n");
    PostOrderTraverse_recur( b ) ; 
    return 0;
}
/*
ABC##DE#G##F###
PreOrderTraverse:
A B C D E G F
InOrderTraverse:
C B E G D F A
PostOrderTraverse:
C G E F D B A
PreOrderTraverse(recursive):
A B C D E G F
InOrderTraverse(recursive):
C B E G D F A
PostOrderTraverse(recursive):
C G E F D B A
*/

另外,

//给定先序只有重复值,不能根据先序中序唯一确定一颗二叉树,如2,2
/*
	2 			2
	 2   或    2	先序都为 2 , 2
*/

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

   vector<int> PrintFromTopToBottom(TreeNode* rt) {
    vector<int> res;
    if( rt == NULL ) return res;
	queue<TreeNode*>q;
	q.push( rt ) ;
	while( !q.empty() ){
		TreeNode* tmp = q.front() ; 
		q.pop() ; 
		res.push_back( tmp -> val ) ;
		if( tmp -> left ) q.push( tmp -> left ) ;
		if( tmp -> right ) q.push( tmp -> right ) ; 
	}
	return res ; 
   }

二叉树中和为某一值的所有路径

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};
    

    vector<vector<int> > res ; 
    vector<int> a ;
    void dfs( TreeNode* rt , int sum , int k ){
        if( sum == k ) {
            res.push_back(a) ; 
            return ; 
        }
        
        if( rt -> left ) {
            a.push_back( rt -> left -> val ) ;
            dfs( rt -> left , sum + rt -> left -> val , k ) ;
            a.pop_back( ) ;
        }
        if( rt -> right ) {
            a.push_back( rt -> left -> val ) ;
            dfs( rt -> right , sum + rt -> right -> val , k ) ;
            a.pop_back( ) ;
        }
    }
    vector<vector<int> > FindPath(TreeNode* rt,int k) {
        if( rt == NULL ) return res ; 
        a.push_back( rt -> val ) ;
        dfs( rt , rt -> val , k ) ; 
        return res ; 
    }

中序遍历二叉树的下一个节点:
中序遍历顺序是 左 根 右
若访问到指定节点nt
若nt有右子树,下一个节点就是右子树最左节点
若nt无右子树

  • 若nt的父节点为空,则下一个节点为空

  • nt父节点不为空

    • nt是父节点的左孩子,则下一个节点就是父节点
    • nt是父节点右孩子,下一个节点就是从nt向祖先节点Pparent遍历,第一个左孩子节点的父亲
      -
       1
     2
     	3    
     	遍历到3时。无右孩子,且为父节点的右孩子,下个节点就是1
    struct TreeLinkNode {
        int val;
        struct TreeLinkNode *left;
        struct TreeLinkNode *right;
        struct TreeLinkNode *next; //父节点
        TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        }
    };
    TreeLinkNode* GetNext(TreeLinkNode* nt){
    	TreeLinkNode* res ; 
        if( nt == NULL ) return NULL ; 
		if( nt -> right ){ //nt有右孩子
			nt = nt -> right ; 
			while( nt -> left ) nt = nt -> left ; 
			res = nt ; 
		}else{ //nt无右孩子
			if( nt -> next == NULL ) res = NULL ;  //nt无父亲节点
			else{//nt有父亲
				if( nt -> next -> left == nt ) res = nt -> next ;  //nt为父亲的左孩子
				else{ //nt为父亲的右孩子
					TreeLinkNode* p = nt ; 
					TreeLinkNode* pParent = p -> next ; 
					while( pParent && p == pParent -> right ){ //向上找是左孩子的节点
						p = pParent ;
						pParent = pParent -> next ; 
					}
					res = pParent ;//结果为左孩子节点的父亲
				}
			}
		} 
    	return res ; 
    }

检查二叉树是否是镜像(对称)

    bool checkMirror( TreeNode* l , TreeNode* r ){
       if( l == NULL && r == NULL ) return true ;
       if( l == NULL || r == NULL  ) return false ;
       
       if( l -> val == r -> val ) return checkMirror( l -> left , r -> right ) && checkMirror( l -> right , r -> left ) ;     
       return false ; 
    }
    bool isSymmetrical(TreeNode* rt){
        if( rt == NULL ) return true ;
        return checkMirror(rt->left ,rt->right) ; 
    }

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行

vector<vector<int> > Print(TreeNode* rt) {
    vector<vector<int> >res ; 
    if( rt == NULL ) return res ; 
    int c = 1 ; 
    queue<TreeNode*>q;
    q.push(rt) ;
    vector<int>t ;
    int lev = 0 ;
    while( !q.empty() ){
        int k = 0 ;
        while( c-- ){     
            TreeNode* tmp = q.front() ; q.pop() ;
            t.push_back(tmp->val) ; 
            if( tmp -> left ){
                q.push( tmp -> left ) ; k ++ ;
            }
            if( tmp -> right ){
                q.push( tmp -> right ) ; k ++ ;
            }
        }    
            res.push_back(t) ; 
            t.clear() ; 
            c = k ;
    }
    return res ; 
}

序列化,反序列化二叉树:
序列化:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点****值的结束(value!)
反序列化:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
string s = "" ; 
void preOrder( TreeNode* rt ){
    stringstream ss ;
    if( rt == NULL ) { s += '#' ; return ; }
    ss << ( rt -> val ) ; 
    string t ; ss >> t ;
    s += t ;
    s += "!" ; 
    ss.str("") ;
    preOrder( rt -> left ) ;
    preOrder( rt -> right ) ;
}
char* Serialize(TreeNode *rt) {
    preOrder(rt) ; 
    char t[10000] ;
    strcpy( t , s.c_str() ) ;  
    char* p = t ;
    return p ;
}
vector<int>sq ;
int tot = -1 ;
TreeNode* reBuild( TreeNode* rt ){
    tot ++ ; 
    if( sq[tot] == -1 ) rt = NULL ;
    else{
        rt = new TreeNode(sq[tot]) ;
        rt -> left = reBuild( rt -> left ) ; 
        rt -> right = reBuild( rt -> right ) ;     
    }
    return rt ; 
}

TreeNode* Deserialize(char *str) {
    int len = strlen(str) ; 
    string tmp = "" ; 
    for( int i = 0 ; i < len ; i++ ){
        if( str[i] == '!' ){
            sq.push_back( atoi( tmp.c_str() ) ); 
            tmp = "" ;    
        }else if( str[i] == '#' ){
            sq.push_back(-1) ;
        }else tmp += str[i] ; 
    }
    TreeNode* rt = NULL ; 
    rt = reBuild( rt ) ;
    return rt ; 
}

二叉树任意两节点距离(LCA算法)

#include <bits/stdc++.h>
using namespace std;
const int AX = 4e4 + 666 ;
struct Node{
	int to , w ; 
	Node( int to , int w ):to(to),w(w){}
};
vector<Node>v[AX];
vector<int>q[AX];
vector<int>id[AX];
int res[206] ; 
int dis[AX] ; 
int pre[AX] ; 
int vis[AX] ; 
int T , n , m ;
int find( int x ){
	return pre[x] == x ? x : pre[x] = find(pre[x]) ; 
}
void mix( int x , int y ){
	x = find(x) ;
	y = find(y) ; 
	if( x != y ){
		pre[x] = y ; 
	}
}
void Tarjan( int x , int sum ){
	dis[x] = sum ; 
	vis[x] = 1 ; 
	for( int i = 0 ; i < v[x].size() ; i++ ){
		int y = v[x][i].to ;
		if( vis[y] ) continue ; 
		Tarjan( y , sum + v[x][i].w ) ;
		mix( y , x );
	}
	for( int i = 0 ; i < q[x].size() ; i++ ){
		if( vis[q[x][i]] ){
			res[id[x][i]] = dis[x] + dis[q[x][i]] - 2 * dis[find(q[x][i])] ;
		}
	}
}
int main() {
	int x , y , w ; 
	scanf("%d",&T);
	while( T-- ) {
		scanf("%d%d",&n,&m);
		for( int i = 1 ; i <= n ; i++ ){
			vis[i] = 0 ; dis[i] = 0 ; pre[i] = i ; res[i] = 0 ; 
			v[i].clear(); q[i].clear(); id[i].clear() ; 
		}
		for( int i = 1 ; i <= n ; i++ ) {
			scanf("%d%d",&x,&y);
			if( x != -1 ) v[i].push_back(Node(x,1));
			if( y != -1 ) v[i].push_back(Node(y,1));
		}
		for( int i = 0 ; i < m ; i++ ){
			scanf("%d%d",&x,&y);
			q[x].push_back(y);
			q[y].push_back(x);
			id[x].push_back(i);
			id[y].push_back(i);
		}
		Tarjan( 1 , 0 );
		for( int i = 0 ; i < m ; i++ ){
			printf("%d\n",res[i]);
		}
	}
	return 0 ;
}

二叉搜索树:
中序递增
镜像的中序递减

一个个插入的建树:

#include <bits/stdc++.h>
using namespace std;
int n ;
vector<char>pre_v;
vector<char>in_v;
vector<char>res;
struct TreeNode {
	char val ;
	TreeNode *l ;
	TreeNode *r ;
	TreeNode( char val ) : val(val) , l(NULL), r(NULL) {}
};
TreeNode* build( TreeNode* rt , int x ) {
	if( !rt ) {
		rt = new TreeNode(x);
	}else if( x < rt -> val ) {
		rt -> l = build( rt -> l , x );
	}else if( x >= rt -> val ) {
		rt -> r = build( rt -> r , x );
	}
	return rt ;
}
void pre_order( TreeNode *rt ) {
	printf("%d ", rt -> val );
	if( rt -> l ) pre_order( rt-> l ) ;
	if( rt -> r ) pre_order( rt -> r ) ;
}

void in_order( TreeNode *rt ) {
	if( rt -> l ) in_order( rt -> l ) ;
	printf("%d ",rt -> val );
	if( rt -> r ) in_order( rt -> r ) ;
}
void post_order( TreeNode *rt ) {
	if( rt -> l ) post_order( rt -> l ) ;
	if( rt -> r ) post_order( rt -> r ) ;
	printf("%d ",rt -> val );
}


int main() {
	int n , x ;
	scanf("%d",&n);
	TreeNode* rt = NULL ;
	for( int i = 0 ; i < n ; i++ ) {
		scanf("%d",&x);
		rt = build(rt,x);
	}
	pre_order(rt);
	puts("");
	in_order(rt);
	puts("");
	post_order(rt);
	return 0 ;
}



检查是否是BST树:

bool check_min( TreeNode* rt ) {
	if( rt -> l == NULL && rt -> r == NULL ) return true ;
	if( rt -> l && rt -> r ) return ( check_min( rt -> l ) && check_min( rt -> r )
		                                  && rt -> val >= rt -> l -> val && rt -> val <= rt -> r -> val ) ;
	if( rt -> l && rt -> r == NULL ) return ( check_min( rt -> l ) && rt -> val >= rt -> l -> val );
	if( rt -> r && rt -> l == NULL ) return ( check_min( rt -> r ) && rt -> val <= rt -> r -> val );
}

根据前序检查是否为BST树:

bool check_min( int l , int r ){
	if( l > r ) return true ;
	int m = l + 1 ;
	int rt = pre[l] ;
	while( pre[m] < rt && m <= r ) m ++ ; //left_tree
	for( int i = m ; i <= r ; i++ ){
		if( pre[i] < rt ) return false ;
	}
	if( !check_min( l + 1 , m - 1 ) || !check_min( m , r ) ) return false ;
	res.push_back(rt);//得到后序
	return true;
}

二叉树镜像
(每个节点左右孩子互换

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};
void Mirror(TreeNode *rt) {
    if( rt == NULL ) return ;
	queue<TreeNode*>q ;
	q.push(rt) ;
	TreeNode* tmp ;
	TreeNode* t ;
	while( !q.empty() ){
		tmp = q.front() ; 
		q.pop() ; 
		t = tmp -> left ; 
		tmp -> left = tmp -> right;
		tmp -> right = t ;
		if( tmp -> left ) q.push(tmp -> left);
		if( tmp -> right ) q.push(tmp -> right);
	}
}

二叉搜索树的第k个结点
找出其中的第k小的结点

    vector<TreeNode*> res ; 
    void InOrder( TreeNode* rt ){
        if( rt == NULL ) return ;
        InOrder( rt -> left ) ; 
        res.push_back( rt ) ; 
        InOrder( rt -> right ) ; 
    }
    TreeNode* KthNode(TreeNode* rt, int k){
        if( rt == NULL || !k ) return NULL ; 
        InOrder( rt ) ; 
        if( k > (int)res.size() ) return NULL ; 
        return res[k-1] ; 
    }

平衡二叉树:
判断:

    int getHigh( TreeNode* rt ){
        if( rt == NULL ) return 0 ; 
        int lh = getHigh( rt -> left ) ;  
        int rh = getHigh( rt -> right ) ; 
        if( lh == -1 || rh == -1 || abs( lh - rh ) > 1 ) return -1 ;
        return max( lh ,rh ) + 1 ; 
    }
    
    bool IsBalanced_Solution( TreeNode* rt ){
        return ( getHigh( rt ) != -1 )  ;
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值