二叉树的概念
二叉树是树的一种,一棵二叉树是节点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵分别称为左子树和右子树的二叉树组成。
二叉树的特点
- 每个结点最多有两棵子树,即二叉树不存在度大于2的结点
- 二叉树的子树有左右之分,其子树的次序不可颠倒
二叉树的可由上述的5种形式组合而成
满二叉树和完全二叉树
满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子结点都在同一层
完全二叉树:如果一棵具有N个结点的二叉树结构和满二叉树的前N个结点的结构相同,称为完全二叉树
二叉树的性质
二叉树的操作
二叉树的遍历
二叉树的遍历分为四种:前序,中序,后序,层序
前序遍历:每次遍历的时候先访问根结点然后在访问根节点的左孩子结点,再访问右孩子结点,当二叉树为空时,访问结束。
中序遍历:每次遍历先访问根结点的左孩子结点,再访问根结点,最后访问右孩子结点。
后序遍历:每次遍历先访问根结点的左孩子结点,然后右孩子结点,最后访问根结点
层序遍历:每次遍历从根结点开始,从上往下,从左往右依次访问
二叉树相关练习和面试题
代码实现:
//bin_tree.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "SqQueue.h"
#include "SqStack.h"
typedef char TreeNodeType;
typedef struct TreeNode {
TreeNodeType data;
struct TreeNode* lchild;
struct TreeNode* rchild;
} TreeNode;
void TreeInit(TreeNode** proot);//初始化
void PreOrder(TreeNode* root); //前序遍历(递归)
void InOrder(TreeNode* root); //中序遍历(递归)
void PostOrder(TreeNode* root); //后序遍历(递归)
void LevelOrder(TreeNode* root); //层序遍历
//根据先序遍历结果构造一颗树(带有空节点标记)
TreeNode* TreeCreate(TreeNodeType array[], size_t size, TreeNodeType null_node);
void TreeDestroy(TreeNode** proot);//二叉树的销毁
TreeNode* TreeClone(TreeNode* root);//二叉树的克隆
//求树的节点个数
size_t TreeSize(TreeNode* root);
//求树的叶子节点个数
size_t TreeSize(TreeNode* root);
//求树的叶子节点个数
size_t TreeLeafSize(TreeNode* root);
//求一颗树K层节点的个数
size_t TreeKLevelSize(TreeNode* root, int K);
//求树的高度
size_t TreeHeight(TreeNode* root);
//查找(时间复杂度O(n))
TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find);
//先序遍历但不允许递归(递归实质上是操作系统自动给它维护一个栈,不允许递归,也就是我们手动维护这个栈)
void PreOrderByLoop(TreeNode* root);
//中序遍历不允许递归
void InOrderByLoop(TreeNode* root);
//后序遍历不允许递归
void PostOrderByLoop(TreeNode* root);
//二叉树镜像
void TreeMirror(TreeNode* root);
//判断完全二叉树
int IsCompleteTree(TreeNode* root);
//给前序和中序结果创建二叉树
TreeNode* TreeReBuild(TreeNodeType pre_order[], TreeNodeType in_order[], size_t size);
//bin_tree.c
#include "bin_tree.h"
TreeNode* CreatTreeNode(TreeNodeType value){
TreeNode* new_node = (TreeNode*)malloc(sizeof(TreeNodeType));
new_node -> data = value;
new_node -> lchild = NULL;
new_node -> rchild = NULL;
return new_node;
}
void DestroyTreeNode(TreeNode* ptr){
free(ptr);
}
void TreeInit(TreeNode** proot){
if(*proot == NULL){
return;
}
*proot = NULL;
return;
}
void PreOrder(TreeNode* root){
if(root == NULL){
printf("# ");
return;
}
printf("%c ", root -> data);
PreOrder(root -> lchild);
PreOrder(root -> rchild);
return;
}
void InOrder(TreeNode* root){
if(root == NULL){
printf("# ");
return;
}
InOrder(root -> lchild);
printf("%c ", root -> data);
InOrder(root -> rchild);
return;
}
void PostOrder(TreeNode* root){
if(root == NULL){
printf("# ");
return;
}
PostOrder(root -> lchild);
PostOrder(root -> rchild);
printf("%c ", root -> data);
return;
}
void LevelOrder(TreeNode* root){
if(root == NULL){
printf("# ");
return;
}
SqQueue queue;
SqQueueInit(&queue);
SqQueuePush(&queue, root);
TreeNode* cur = NULL;
while(SqQueueFront(&queue, &cur)){
printf("%c ", cur -> data);
SqQueuePop(&queue);
if(cur -> lchild != NULL){
SqQueuePush(&queue, cur -> lchild);
}
if(cur -> rchild != NULL){
SqQueuePush(&queue, cur -> rchild);
}
}
}
TreeNode* _TreeCreate(TreeNodeType array[], size_t size, size_t* index, TreeNodeType null_node){
if(index == NULL){
return NULL;
}
if(*index >= size){
return NULL;
}
if(array[*index] == null_node){
return NULL;
}
TreeNode* new_node = CreatTreeNode(array[*index]);
++(*index);
new_node -> lchild = _TreeCreate(array, size, index, null_node);
++(*index);
new_node -> rchild = _TreeCreate(array, size, index, null_node);
return new_node;
}
TreeNode* TreeCreate(TreeNodeType array[], size_t size, TreeNodeType null_node){
//当前读到了数组中的第几个元素
size_t index = 0;
return _TreeCreate(array, size, &index, null_node);
}
void TreeDestroy(TreeNode** proot){
if(proot == NULL){
return;
}
if(*proot == NULL){
return;
}
TreeNode* to_delete = *proot;
TreeDestroy(&to_delete -> lchild);
TreeDestroy(&to_delete -> rchild);
DestroyTreeNode(to_delete);
*proot = NULL;
}
TreeNode* TreeClone(TreeNode* root){
if(root == NULL){
return NULL;
}
TreeNode* new_node = CreatTreeNode(root -> data);
new_node -> lchild = TreeClone(root -> lchild);
new_node -> rchild = TreeClone(root -> rchild);
return new_node;
}
//void _TreeSize(TreeNode* root, size_t size){
// if(root == NULL || size == NULL){
// return;
// }
// //访问当前元素,每次访问到一个元素,就++size
// ++(*size);
// _TreeSize(root -> lchild, size);
// _TreeSize(root -> rchild, size);
//}
//求树的节点个数
size_t TreeSize(TreeNode* root){
if(root == NULL){
return 0;
}
//size_t size = 0;
//_TreeSize(root, &size);
return 1 + TreeSize(root -> lchild) + TreeSize(root -> rchild);
}
//求树的叶子节点个数
size_t TreeSize(TreeNode* root){
if(root == NULL){
return 0;
}
//size_t size = 0;
//_TreeSize(root, &size);
return 1 + TreeSize(root -> lchild) + TreeSize(root -> rchild);
}
//求树的叶子节点个数
size_t TreeLeafSize(TreeNode* root){
if(root == NULL){
return 0;
}
if(root -> lchild == NULL && root -> rchild == NULL){
return 1;
}
return TreeLeafSize(root -> lchild) + TreeLeafSize(root -> rchild);
}
//求一颗树K层节点的个数
size_t TreeKLevelSize(TreeNode* root, int K){
if(root == NULL || K < 1){
return 0;
}
if(K == 1){
return 1;
}
return TreeKLevelSize(root -> lchild, K - 1) + TreeKLevelSize(root -> rchild, K - 1);
}
//求树的高度
size_t TreeHeight(TreeNode* root){
if(root == NULL){
return 0;
}
size_t lheight = TreeHeight(root -> lchild);
size_t rheight = TreeHeight(root -> rchild);
return lheight > rheight ? lheight + 1 : rheight + 1;
}
}
//查找(时间复杂度O(n))
TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find){
if(root == NULL){
return NULL;
}
if(root -> data == to_find){
return root;
}
TreeNode* lresult = TreeFind(root -> lchild, to_find);
TreeNode* rrestlt = TreeFind(root -> rchild, to_find);
return lresult != NULL ? lresult : rrestlt;
}
//求给出节点的左孩子节点
TreeNode* LChild(TreeNode* node){
if(node == NULL){
return NULL;
}
return node -> lchild;
}
//求给出节点的右孩子节点
TreeNode* RChild(TreeNode* node){
if(node == NULL){
return NULL;
}
return node -> rchild;
}
//求给出节点的父节点
TreeNode* Parent(TreeNode* root, TreeNode* node){
if(root == NULL || node == NULL){
return NULL;
}
if(root -> lchild == node || root -> rchild == node){
return root;
}
TreeNode* lresult = Parent(root -> lchild, node);
TreeNode* rresult = Parent(root -> rchild, node);
return lresult != NULL ? lresult : rresult;
}
//先序遍历但不允许递归(递归实质上是操作系统自动给它维护一个栈,不允许递归,也就是我们手动维护这个栈)
void PreOrderByLoop(TreeNode* root){
if(root == NULL){
return ;
}
SqStack stack;
InitSqStack(&stack);
SqStackPush(&stack, root);
while(1){//先让root右节点入栈,再让左节点入栈
TreeNode* top = NULL;
SqStackTop(&stack, &top);
if(top == NULL){
//遍历完成
break;
}
//访问当前栈顶元素
printf("%c ", top -> data);
SqStackPop(&stack);
//把当前元素右子树和左子树分别入栈
if(top -> rchild != NULL){
SqStackPush(&stack, top -> rchild);
}
if(top -> lchild != NULL){
SqStackPush(&stack, top -> lchild);
}
}
printf("\n");
}
void InOrderByLoop(TreeNode* root){
if(root == NULL){
return;
}
SqStack stack;
InitSqStack(&stack);
//1、从根节点出发,尝试找到当前树的最左侧节点,每次经过一个节点,就把这个节点入栈
//2、取栈顶元素访问,并将该元素出栈
//3、处理当前元素的右子树,回到循环开始,再去找右子树的最左侧节点
TreeNode* cur = root;
while(1){
while(cur != NULL){
SqStackPush(&stack, cur);
cur = cur -> lchild;
}
TreeNode* top = NULL;
SqStackTop(&stack, &top);
if(top == NULL){
break;
}
printf("%c ", top -> data);
SqStackPop(&stack);
cur = top -> rchild;
}
printf("\n");
return ;
}
void PostOrderByLoop(TreeNode* root){
if(root == NULL){
return;
}
SqStack stack;
InitSqStack(&stack);
TreeNode* cur =root;
TreeNode* pre = NULL;
while(1){
while(cur != NULL){
SqStackPush(&stack, cur);
cur = cur -> lchild;
}
TreeNode* top = NULL;
SqStackTop(&stack, &top);
if(top == NULL ){
break;
}
//取出栈顶元素之后,满足以下两个条件之一,才能访问top
//1、top的右子树为空
//2、top的右子树访问过了
//否则, 就需要循环处理top的右子树
if(top -> rchild == NULL || top -> rchild == pre){
printf("%c ", top -> data);
SqStackPop(&stack);
pre = top;
}else{
cur = top -> rchild;
}
}
printf("\n");
return;
}
void TreeMirror(TreeNode* root){
if(root == NULL){
return;
}
TreeNode* tmp = root -> lchild;
root -> lchild = root -> rchild;
root -> rchild = tmp;
TreeMirror(root -> lchild);
TreeMirror(root -> rchild);
return;
}
int IsCompleteTree(TreeNode* root){
if(root == NULL){
return 1;
}
SqQueue queue;
SqQueueInit(&queue);
SqQueuePush(&queue, root);
int check_two_child_null_flag = 0;
while(1){
TreeNode* cur = NULL;
SqQueueFront(&queue, &cur);
if(cur == NULL){
break;//遍历结束
}
//访问当前节点
if(check_two_child_null_flag == 0){//第一阶段的判定
if(cur -> lchild != NULL && cur -> rchild != NULL){
SqQueuePush(&queue, cur -> lchild);
SqQueuePush(&queue, cur -> rchild);
}else if(cur -> lchild == NULL && cur -> rchild != NULL){
return 0;
}else if(cur -> lchild != NULL && cur -> rchild == NULL){
check_two_child_null_flag = 1;
}else if(cur -> lchild == NULL && cur -> rchild == NULL){
check_two_child_null_flag = 1;
}
}else{//第二阶段判定
if(cur -> lchild == NULL && cur -> rchild == NULL){
//两个都为空,说明目前为止,还满足完全二叉树的条件,可以继续遍历
}else{
return 0;
}
}
SqQueuePop(&queue);
}
return 1;
}
size_t Find(TreeNodeType array[], size_t left, size_t right, TreeNodeType to_find){
size_t i = left;
for(; i < right; ++i){
if(array[i] == to_find){
return i;
}
}
return (size_t)-1;
}
TreeNode* _TreeReBuild(TreeNodeType pre_order[], size_t pre_order_size, size_t* pre_order_index, TreeNodeType in_order[], size_t in_order_left, size_t in_order_right){
if(in_order_left >= in_order_right){
return NULL;//无效区间,当前子树的中序遍历结果就是空的,此时说明这可子树就是空
}
if(pre_order_index == NULL || *pre_order_index >= pre_order_size){
return NULL;//非法输入 || 遍历结束
}
TreeNode* new_node = CreatTreeNode(pre_order[*pre_order_index]);//根据先序遍历结果取出当前值,基于这个值构建一个节点,new_node相当于当前子树的节点
//查找下当前节点在中序序列中的位置
size_t cur_root_in_order_index = Find(in_order, in_order_left, in_order_right, new_node -> data);
++(*pre_order_index);
//左子树区间[in_order_left, cur_root_in_order_index)
new_node -> lchild = _TreeReBuild(pre_order, pre_order_size, pre_order_index, in_order, in_order_left, cur_root_in_order_index);
//右子树区间[cur_root_in_order_index+1, in_order_right)
new_node -> rchild = _TreeReBuild(pre_order, pre_order_size, pre_order_index, in_order, cur_root_in_order_index, in_order_right);
return new_node;
}
TreeNode* TreeReBuild(TreeNodeType pre_order[], TreeNodeType in_order[], size_t size){
size_t pre_order_index = 0;
//[in_order_left, in_order_right)
size_t in_order_left = 0;
size_t in_order_right = size;
return _TreeReBuild(pre_order, size, &pre_order_index, in_order, in_order_left, in_order_right);
}
#if 1
/
//TEST//
///
#define TESTHEADER printf("\n===============%s=============\n",__FUNCTION__);
void TestInit(){
TreeNode* root;
TreeInit(&root);
}
void TestPreOrder(){
TESTHEADER;
TreeNode* root;
TreeInit(&root);
TreeNode* a = CreatTreeNode('a');
TreeNode* b = CreatTreeNode('b');
TreeNode* c = CreatTreeNode('c');
TreeNode* d = CreatTreeNode('d');
TreeNode* e = CreatTreeNode('e');
TreeNode* f = CreatTreeNode('f');
TreeNode* g = CreatTreeNode('g');
a -> lchild = b;
a -> rchild = c;
b -> lchild = d;
b -> rchild = e;
e -> lchild = g;
c -> rchild = f;
root = a;
printf("先序遍历结果:\n");
PreOrder(root);
printf("\n");
}
void TestInOrder(){
TESTHEADER;
TreeNode* root;
TreeInit(&root);
TreeNode* a = CreatTreeNode('a');
TreeNode* b = CreatTreeNode('b');
TreeNode* c = CreatTreeNode('c');
TreeNode* d = CreatTreeNode('d');
TreeNode* e = CreatTreeNode('e');
TreeNode* f = CreatTreeNode('f');
TreeNode* g = CreatTreeNode('g');
a -> lchild = b;
a -> rchild = c;
b -> lchild = d;
b -> rchild = e;
e -> lchild = g;
c -> rchild = f;
root = a;
printf("中序遍历结果:\n");
InOrder(root);
printf("\n");
}
void TestPostOrder(){
TESTHEADER;
TreeNode* root;
TreeInit(&root);
TreeNode* a = CreatTreeNode('a');
TreeNode* b = CreatTreeNode('b');
TreeNode* c = CreatTreeNode('c');
TreeNode* d = CreatTreeNode('d');
TreeNode* e = CreatTreeNode('e');
TreeNode* f = CreatTreeNode('f');
TreeNode* g = CreatTreeNode('g');
a -> lchild = b;
a -> rchild = c;
b -> lchild = d;
b -> rchild = e;
e -> lchild = g;
c -> rchild = f;
root = a;
printf("后·序遍历结果:\n");
PostOrder(root);
printf("\n");
}
void TestLevelOrder(){
TESTHEADER;
TreeNode* root;
TreeInit(&root);
TreeNode* a = CreatTreeNode('a');
TreeNode* b = CreatTreeNode('b');
TreeNode* c = CreatTreeNode('c');
TreeNode* d = CreatTreeNode('d');
TreeNode* e = CreatTreeNode('e');
TreeNode* f = CreatTreeNode('f');
TreeNode* g = CreatTreeNode('g');
a -> lchild = b;
a -> rchild = c;
b -> lchild = d;
b -> rchild = e;
e -> lchild = g;
c -> rchild = f;
root = a;
printf("层序遍历结果:\n");
LevelOrder(root);
printf("\n");
}
void TestCreat(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
printf("先序遍历结果");
PreOrder(root);
printf("\n");
printf("中序遍历结果");
InOrder(root);
printf("\n");
}
void TestDesttroy(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
TreeDestroy(&root);
printf("root expected NULL, actual %p\n", root);
}
void TestSize(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
printf("size expect 7, actual %lu\n", TreeSize(root));
printf("leafsize expect 3, actual %lu\n", TreeLeafSize(root));
printf("height expect 4, actual %lu\n", TreeHeight(root));
}
void TestFind(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
TreeNode* to_find = TreeFind(root, 'g');
printf("find expect g, actual %c\n", to_find -> data);
}
void TestPreOrderByLoop(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
PreOrderByLoop(root);
}
void TestInOrderByLoop(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
InOrderByLoop(root);
}
void TestPostOrderByLoop(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
PostOrderByLoop(root);
}
void TestMirror(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
TreeMirror(root);
printf("先序遍历结果");
PreOrder(root);
printf("\n");
printf("中序遍历结果");
InOrder(root);
printf("\n");
}
void TestIsComplete(){
TESTHEADER;
TreeNodeType array[] = "abd##eg###c#f#";
TreeNode* root = TreeCreate(array, strlen(array), '#');
int ret = IsCompleteTree(root);
printf("ret expect 0, actual %d\n", ret);
}
void TestReBuild(){
TESTHEADER;
TreeNodeType pre_order[] = "abdecf";
TreeNodeType in_order[] = "dbeafc";
TreeNode* root;
TreeInit(&root);
size_t size = strlen(pre_order);
root = TreeReBuild(pre_order, in_order, size);
PreOrder(root);
printf("\n");
// InOrder(root);
// printf("\n");
}
int main(){
TestPreOrder();
TestInOrder();
TestPostOrder();
TestLevelOrder();
TestCreat();
TestDesttroy();
TestSize();
TestFind();
TestPreOrderByLoop();
TestInOrderByLoop();
TestPostOrderByLoop();
TestMirror();
TestIsComplete();
TestReBuild();
}
#endif