前言
二叉树具有递归的性质 因此我们做题时要往递归的大方向 进行思考。
一.遍历
1.前序遍历
力扣链接
先遍历根,再遍历左子树,最后遍历右子树 此题关键:传入i的地址,而不是i的临时拷贝 原因:每一层的 i 都要建立栈帧 ,因此递归之后的i值,每一层都是独立的i,不会互相影响 。
int BTSize ( struct TreeNode * root)
{
if ( root == NULL )
{
return 0 ;
}
return BTSize ( root-> right) + BTSize ( root-> left) + 1 ;
}
void BTPreOrder ( struct TreeNode * root, int * arr, int * pi)
{
if ( root == NULL )
{
return ;
}
arr[ * pi] = root-> val;
( * pi) ++ ;
BTPreOrder ( root-> left, arr, pi) ;
BTPreOrder ( root-> right, arr, pi) ;
}
int * preorderTraversal ( struct TreeNode * root, int * returnSize)
{
* returnSize = BTSize ( root) ;
int * arr= ( int * ) malloc ( sizeof ( int ) * ( * returnSize) ) ;
if ( arr== NULL )
{
perror ( "malloc fail" ) ;
exit ( - 1 ) ;
}
int i = 0 ;
BTPreOrder ( root, arr, & i) ;
return arr;
}
2.中序遍历
力扣链接
int BTSize ( struct TreeNode * root)
{
if ( root == NULL )
{
return 0 ;
}
return BTSize ( root-> right) + BTSize ( root-> left) + 1 ;
}
void BTInOrder ( struct TreeNode * root, int * i, int * arr)
{
if ( root == NULL )
{
return ;
}
BTInOrder ( root-> left, i, arr) ;
arr[ * i] = root-> val;
( * i) ++ ;
BTInOrder ( root-> right, i, arr) ;
}
int * inorderTraversal ( struct TreeNode * root, int * returnSize)
{
* returnSize = BTSize ( root) ;
int * arr= ( int * ) malloc ( sizeof ( int ) * ( * returnSize) ) ;
int i = 0 ;
BTInOrder ( root, & i, arr) ;
return arr;
}
3.后序遍历
力扣链接
先遍历左子树,再遍历右子树,最后再遍历根 关键:同上
int BTSize ( struct TreeNode * root)
{
if ( root == NULL )
{
return 0 ;
}
return BTSize ( root-> right) + BTSize ( root-> left) + 1 ;
}
void BTPostOrder ( struct TreeNode * root, int * i, int * arr)
{
if ( root == NULL )
{
return ;
}
BTPostOrder ( root-> left, i, arr) ;
BTPostOrder ( root-> right, i, arr) ;
arr[ * i] = root-> val;
( * i) ++ ;
}
int * postorderTraversal ( struct TreeNode * root, int * returnSize)
{
* returnSize= BTSize ( root) ;
int * arr= ( int * ) malloc ( ( * returnSize) * sizeof ( int ) ) ;
if ( arr== NULL )
{
perror ( "malloc fail" ) ;
exit ( - 1 ) ;
}
int i = 0 ;
BTPostOrder ( root, & i, arr) ;
return arr;
}
4.层序遍历
借助对列先进先出 的结构 出根节点将其左孩子和右孩子入栈 直到对列为空结束 !
typedef struct BTNode * QLNDateType;
typedef struct QListNode
{
QLNDateType val;
struct QListNode * next;
} QListNode;
typedef struct Queue
{
QListNode* Top;
QListNode* Tail;
} Queue;
void QueuePushBack ( Queue* q, QLNDateType x)
{
QListNode* NewNode = ( QListNode* ) malloc ( sizeof ( QListNode) ) ;
if ( NewNode == NULL )
{
perror ( "malloc fail" ) ;
exit ( - 1 ) ;
}
NewNode-> next = NULL ;
NewNode-> val = x;
if ( q-> Top == NULL )
{
q-> Tail = NewNode;
q-> Top = NewNode;
return ;
}
else
{
q-> Tail-> next = NewNode;
q-> Tail = NewNode;
}
}
int QueueEmpty ( Queue q)
{
return q. Top == NULL ;
}
void QueueDestory ( Queue* q)
{
QListNode* cur = q-> Top;
q-> Top = NULL ;
q-> Tail = NULL ;
while ( cur)
{
QListNode* next = cur-> next;
free ( cur) ;
cur = next;
}
}
void BTLevelOrder ( BTNode* root)
{
Queue qlist;
QueueInit ( & qlist) ;
if ( root != NULL )
{
QueuePushBack ( & qlist, root) ;
}
while ( ! QueueEmpty ( qlist) )
{
BTNode* front = QueueTop ( qlist) ;
QueuePopFront ( & qlist) ;
if ( front != NULL )
{
printf ( "%d " , front-> val) ;
QueuePushBack ( & qlist, front-> left) ;
QueuePushBack ( & qlist, front-> right) ;
}
}
QueueDestory ( & qlist) ;
}
二.提高
1.单值二叉树
力扣链接
比较根节点与左右节点 注意:我们要的是结果! 因此:当右节点的值不等于根节点的值时,就返回false!左节点同理! 如果节点为空说明:左右子树与根节点相同,或者只有一个节点(题目条件)。
bool isUnivalTree ( struct TreeNode * root)
{
if ( root== NULL )
{
return true;
}
if ( root-> left!= NULL && root-> val!= root-> left-> val)
{
return false;
}
if ( root-> right!= NULL && root-> val!= root-> right-> val)
{
return false;
}
return isUnivalTree ( root-> left) && isUnivalTree ( root-> right) ;
}
2.二叉树翻转
力扣链接
struct TreeNode * invertTree ( struct TreeNode * root)
{
if ( root== NULL )
{
return NULL ;
}
invertTree ( root-> left) ;
invertTree ( root-> right) ;
struct TreeNode * tmp = root-> right;
root-> right = root-> left;
root-> left = tmp;
return root;
}
3.判断二叉树树相同
力扣链接
判断二叉树是否相同需看左子树和右子树是否相同 注意:我们要的是结果! 因此:当左右节点的值不相同时,我们返回false即可 注意:同为空说明为真,一个为空说明为假,都不为空说明有待判断
bool isSameTree ( struct TreeNode * p, struct TreeNode * q)
{
if ( p== NULL && q== NULL )
{
return true;
}
if ( p== NULL || q== NULL )
{
return false;
}
if ( p-> val!= q-> val)
{
return false;
}
return isSameTree ( p-> left, q-> left) && isSameTree ( p-> right, q-> right) ;
}
4.判断二叉树对称
力扣链接
思路:二叉树对称只需判断一棵树的左子树与另一棵的右子树是否相同与一棵树的右子树与左子树是否相同 注意:我们要的是结果! 因此:当左右节点的值不相同时,我们返回false即可
bool is_same_tree ( struct TreeNode * root1, struct TreeNode * root2)
{
if ( root1 == NULL && root2 == NULL )
{
return true;
}
if ( root1 == NULL || root2 == NULL )
{
return false;
}
if ( root1-> val != root2-> val)
{
return false;
}
return is_same_tree ( root1-> left, root2-> right) &&
is_same_tree ( root1-> right, root2-> left) ;
}
bool isSymmetric ( struct TreeNode * root)
{
return is_same_tree ( root-> left, root-> right) ;
}
5.另一棵树的子树
力扣链接
思路:先比较整棵树是否相同,再比较其左子树是否相同,最后比较右子树是否相同 ,如果相同返回true ,如果都
不相同返回false!
bool is_same_tree ( struct TreeNode * root1, struct TreeNode * root2)
{
if ( root1 == NULL && root2 == NULL )
{
return true;
}
if ( root1 == NULL || root2 == NULL )
{
return false;
}
if ( root1-> val != root2-> val)
{
return false;
}
return is_same_tree ( root1-> right, root2-> right) &&
is_same_tree ( root1-> left, root2-> left) ;
}
bool isSubtree ( struct TreeNode * root, struct TreeNode * subRoot)
{
if ( root== NULL )
{
return false;
}
bool ret = is_same_tree ( root, subRoot) ;
if ( ret)
return true;
bool left = isSubtree ( root-> left, subRoot) ;
if ( left)
return true;
bool right = isSubtree ( root-> right, subRoot) ;
if ( right)
return true;
return false;
}
5.判断完全二叉树
借助层序遍历的思路,当出到空时,如果后面有不为空的,则其不是完全二叉树,反之是完全二叉树。
typedef struct BTNode * QLNDateType;
typedef struct QListNode
{
QLNDateType val;
struct QListNode * next;
} QListNode;
typedef struct Queue
{
QListNode* Top;
QListNode* Tail;
} Queue;
void QueuePushBack ( Queue* q, QLNDateType x)
{
QListNode* NewNode = ( QListNode* ) malloc ( sizeof ( QListNode) ) ;
if ( NewNode == NULL )
{
perror ( "malloc fail" ) ;
exit ( - 1 ) ;
}
NewNode-> next = NULL ;
NewNode-> val = x;
if ( q-> Top == NULL )
{
q-> Tail = NewNode;
q-> Top = NewNode;
return ;
}
else
{
q-> Tail-> next = NewNode;
q-> Tail = NewNode;
}
}
int QueueEmpty ( Queue q)
{
return q. Top == NULL ;
}
void QueueDestory ( Queue* q)
{
QListNode* cur = q-> Top;
q-> Top = NULL ;
q-> Tail = NULL ;
while ( cur)
{
QListNode* next = cur-> next;
free ( cur) ;
cur = next;
}
}
bool BinaryTreeComplete ( BTNode* root)
{
Queue qlist;
QueueInit ( & qlist) ;
if ( root != NULL )
{
QueuePushBack ( & qlist, root) ;
}
while ( ! QueueEmpty ( qlist) )
{
BTNode* front = QueueTop ( qlist) ;
QueuePopFront ( & qlist) ;
if ( front != NULL )
{
QueuePushBack ( & qlist, front-> left) ;
QueuePushBack ( & qlist, front-> right) ;
}
else
{
break ;
}
}
while ( ! QueueEmpty ( qlist) )
{
BTNode* front = QueueTop ( qlist) ;
QueuePopFront ( & qlist) ;
if ( front != NULL )
{
QueueDestory ( & qlist) ;
return false;
}
}
QueueDestory ( & qlist) ;
return true;
}
6.二叉树的构建与遍历
牛客链接
在外面传入下标的指针 当识别到#时,二叉树的结点设置为空,但是数组还要往后识别,这时的下标要加1 不必考虑数组是否读完,因为数组的元素是足够刚好建立一棵二叉树的 根的左节点指针等于其子树创建的节点之后的返回值,右节点同理。 返回创建的根节点(也是4的返回值)
# include <stdio.h>
# include <stdlib.h>
typedef char BTNodeDataType;
typedef struct BTNode
{
BTNodeDataType val;
struct BTNode * left;
struct BTNode * right;
} BTNode;
BTNode* BTCreat ( BTNodeDataType* a, int * pi)
{
if ( a[ * pi] == '#' )
{
( * pi) ++ ;
return NULL ;
}
BTNode* NewNode = ( BTNode* ) malloc ( sizeof ( BTNode) ) ;
if ( NewNode == NULL )
{
perror ( "malloc fail" ) ;
exit ( - 1 ) ;
}
NewNode-> val = a[ ( * pi) ++ ] ;
NewNode-> left = BTCreat ( a, pi) ;
NewNode-> right = BTCreat ( a, pi) ;
return NewNode;
}
void BTInOrder ( BTNode* root)
{
if ( root == NULL )
{
return ;
}
BTInOrder ( root-> left) ;
printf ( "%c " , root-> val) ;
BTInOrder ( root-> right) ;
}
int main ( )
{
char arr[ 150 ] = { 0 } ;
scanf ( "%s" , arr) ;
int i = 0 ;
BTNode* root = BTCreat ( arr, & i) ;
BTInOrder ( root) ;
return 0 ;
}
7.二叉树的最大深度
力扣链接
最大深度:左子树的深度与右子树深度的较大值,再加上根节点的高度1. 细节:左子树的深度与右子树深度的值应当保留下来,这样可以少递归很多次!
int maxDepth ( struct TreeNode * root)
{
if ( root== NULL )
{
return 0 ;
}
int left = maxDepth ( root-> left) ;
int right = maxDepth ( root-> right) ;
return left > right? left+ 1 : right+ 1 ;
}