二叉树:
对于各节点值不重复建树(同时得到后序):(前序+中序建树)
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 ) ;
}