在几乎所有的二叉树操作中,尤其是在递归操作里,我们会发现其实质上是把每一个节点都当作是一棵树来处理,按照应有的规则去操作这棵树,保证在操作这一棵树不出现问题,那么所有的操作也将会跟着进行。特别要注意以下两个问题:
(1)递归的出口。
(2)递归结束需要改变值就传二级指针。
定义如下:
typedef char BDataType;
typedef struct BTNode
{
BDataType data;
struct BTNode* Lchild;
struct BTNode* Rchild;
}BTNode;
创建节点:
BTNode *BuyBTNode(BDataType data)
{
BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
if(NULL == newNode)
{
assert(0);
return NULL;
}
newNode->Lchild = NULL;
newNode->Rchile = NULL;
newNode->data = data;
return newNode;
}
1. 创建二叉树。(前序创建)
(1) 若序列索引小于序列长度并且当前索引元素为有效元素。
(2) 创建根节点。
(3) 创建根节点的左子树。
(4) 创建根节点的右子树。
//因为每次递归结束需要改变root所指内容,所以传二级指针。index同理。
void CreateBinTree(BTNode **root,char *str,int size,int *index)
{
assert(root);
assert(index);
if(*index < size && str[*index] != '#')
{
*root = BuyBTNode(str[*index]);
++(*index);
CreateBinTree(&(*root)->Lchild,str,size,index);
++(*index);
CreatrBinTree(&(*root)->Rchild,str,size,index);
}
}
2. 前序遍历递归实现。
(1)遍历根节点。
(2)遍历根节点的左子树。
(3)遍历根节点的右子树。
void PreOrder(BTNode *root)
{
if(root)
{
printf("%c ",root->data);
PreOrder(root->Lchild);
PreOrder(root->Rchild);
}
}
3. 中序遍历递归实现。
(1)遍历根节点的左子树。
(2)遍历根节点。
(3)遍历根节点的右子树。
void InOrder(BTNode *root)
{
if(root)
{
InOrder(root->Lchild);
printf("%c ",root->data);
InOrder(root->Rchild);
}
}
4. 后序遍历递归实现。
(1)遍历根节点的左子树。
(2)遍历根节点的右子树。
(3)遍历根节点。
void PostOrder(BTNode *root)
{
if(root)
{
PostOrder(root->Lchild);
PostOrder(root->Rchild);
printf("%c ",root->data);
}
}
5. 复制二叉树。
操作类似二叉树前序遍历。
(1)拷贝根节点。
(2)拷贝根节点的左子树。
(3)拷贝根节点的右子树。
BTNode *CopyBinTree(BTNode *root)
{
BTNode *newRoot = NULL;
if(root)
{
newRoot = BuyBTNode(root->data);
if(root->Lchild)
newRoot->Lchild = CopyBinTree(root->Lchild);
if(root->Rchild)
newRoot->Rchild = CopyBinTree(root->Rchild);
}
return newRoot;
}
6. 求二叉树中节点的个数。
(1)左右子树中节点的个数。
int GetBTNodeCount(BTNode *root)
{
if(NULL == root)
{
return 0;
}
return GetBTNodeCount(root->Lchild)+GetBTNodeCount(root->Rchild)+1;
}
7. 求二叉树中叶子节点的个数。
叶子节点:既没有左孩子,也没有右孩子。
(1)左右子树中叶子节点的个数。
int GetLeafNodeCount(BTNode *root)
{
if(NULL == root)
{
return 0;
}
if(NULL == root->Lchild && NULL == root->Rchild)
{
return 1;
}
return GetLeafNodeCount(root->Lchild)+GetLeafNodeCount(root->Rchild);
}
8. 求二叉树中第K层节点的个数。
(1)求左右字数中第K-1层节点的个数。
int GetKLevelNodeCount(BTNode *root,int K)
{
if(NULL == root)
{
return 0;
}
if(K == 1)
{
return 1;
}
return GetKLevelNodeCount(root->Lchild,K-1)+GetKLevelNodeCount(root->Rchild,K-1);
}
9. 求二叉树的高度。
(1)求二叉树中左右子树较高树的高度。
int GetBinTreeHeight(BTNode *root)
{
if(NULL == root)
{
return 0;
}
int LeftHeight = 0;
int RightHeight = 0;
LeftHeight = GetBinTreeHeight(root->Lchild);
RightHeight = GetBinTreeHeight(root->Rchild);
return LeftHeight>RightHeight?LeftHeight+1:RightHeight+1;
}
10. 销毁二叉树
(1)销毁根节点的左子树。
(2)销毁根节点的右子树。
(3)销毁根节点。
void DestroyBinTree(BTNode **root)
{
assert(*root);
if(NULL == *root)
{
return;
}
DestroyBinTree(&(*root)->Lchild);
DestroyBinTree(&(*root)->Rchild);
free(*root);
*root = NULL;
}
11. 求二叉树的左孩子节点。
BTNode *LeftNode(BTNode *root)
{
if(NULL == root)
{
return NULL;
}
return root->Lchild;
}
12. 求二叉树的右孩子节点。
BTNode *LeftNode(BTNode *root)
{
if(NULL == root)
{
return NULL;
}
return root->Rchild;
}
13. 求二叉树中最远的节点之间的距离。
(1)计算当前结点的深度以及以当前结点为根的子树的最大距离。
int Max_distance(BTNode *root, int *m)
{
if (NULL == root)
{
return 0;
}
int* max = m;
int LeftDepth = Max_distance(root->Lchild, max);
int RightDepth = Max_distance(root->Rchild, max);
if (*max < LeftDepth + RightDepth)
{
*max = LeftDepth + RightDepth;
}
return LeftDepth>RightDepth ? LeftDepth + 1 : RightDepth + 1;
}
(2)计算二叉树中最远节点距离。
int Maxdistance(BTNode *root)
{
if (NULL == root)
{
return 0;
}
int max = 0;
Max_distance(root, &max);
return max;
}
14. 判断一个节点是否在二叉树中。
(1)判断是否为根节点。若不是,则转到(2)。
(2)判断是否为左子树中的节点。
(3)判断是否为右子树中的节点。
int IsBTNodeInBinTree(BTNode *root,BTNode *Node)
{
if((NULL== root)||(NULL == Node))
return 0;
if(Node == root)
return 1;
if(IsBTNodeInBinTree(root->Lchild,Node))
return 1;
return IsBTNodeInBinTree(root->Rchild,Node);
}
15. 求一个节点的最近的祖先节点。
(1)从根节点开始判断。
(2)如果根节点的左孩子或者右孩子为该节点,那么返回根节点。
(3)更新根节点为其左孩子。转到(1)。
(4)更新根节点为其右孩子。转到(1)。
BTNode* GetBTNodeParent(BTNode *root,BTNode *Node)
{
if((NULL == root)||(NULL == Node)||(root == Node)
return 0;
if((Node == root->Lchild) || (Node == root->Rchild))
return root;
BTNode *parent = NULL;
if(parent = GetBTNodeParent(root->Lchild,Node))
return parent;
return GetBTNodeParent(root->Rchild,Node);
}
16. 求二叉树的镜像。
(1)交换根节点的左右孩子。
(2)交换左子树的左右孩子。
(3)交换右子树的左右孩子。
void MirrorBinTree(BTNode *root)
{
if(root)
{
Swap(&root->Lchild,&root->Rchild);
MirrorBinTree(BTNode *root->Lchild);
MirrorBinTree(BTNode *root->Rchild);
}
}
17. 层序遍历。
将根节点放到队列中。
(1) 取队头元素。
(2) 访问该元素。
(3) 如果该节点的左子树存在,入队列。
(4) 如果该节点的右子树存在,入队列。
(5) 将对头元素出队列。
(6) 判断队列是否为空,若空,则结束,否则转到(1)。
void LevelOrder(BTNode *root)
{
if(NULL == root)
return;
Queue q;
QueueInit(&q);
QueuePush(&q,root);
while(!QueueEmpty(&q))
{
BTNode *cur = QueueFront(&q);
printf("%c ",cur->data);
if(cur->Lchild)
QueuePush(&q,cur->Lchild);
if(cur->Rchild)
QueuePush(&q,cur->Rchild);
QueuePop(&q);
}
}
18. 判断是否为完全二叉树。
将根节点放到队列中。
(1)取队头元素。
(2)如果根节点既有左孩子,也有右孩子,则均入队列。
(3)如果根节点只有左孩子,没有右孩子,则为完全二叉树。
(4)如果根节点只有右孩子,没有左孩子,则不是完全二叉树。
(5)如果根节点没有左孩子,没有右孩子,则为完全二叉树。
(6)出队列,并判断是否为空队列。为空跳出,不为空则转到(1)。
int IsCompleteBinTree(BTNode *root)
{
if(NULL == root)
return 0;
int IsFlag = 0;
Queue q;
QueueInit(&q);
QueuePush(&q,root);
while(!QueueEmpty(&q))
{
BTNode *cur = QueueFront(&q);
if(IsFlag)
{
if(cur-Lchild || cur->Rchild)
return 0;
}
else
{
if(cur->Lchild && cur->Rchild)
{
QueuePush(&q,cur->Lchild);
QueuePush(&q,cur->Rchild);
}
else if(cur->Lchild)
{
QueuePush(&q,cur->Lchild);
IsFlag = 1;
}
else if(cur->Rchild)
{
return 0;
}
else
{
IsFlag = 1;
}
}
QueuePop(&q);
}
return 1;
}
19. 前序遍历非递归实现。
因为前序遍历的顺序是根–>左–>右,所以通过栈实现的时候,压入根节点之后需要压入的是有孩子节点,而不是左孩子节点。
(1) 遍历以cur为根的二叉树的根节点。同时出栈栈顶元素。若栈为空,则跳出,否则进行下一步。
(2) 如果有右孩子,将其压入栈中。
(3) 如果有左孩子,将其压入栈中。
void PreOrderNor1(BTNode *root)
{
if(NULL == root)
return;
Stack s;
StackInit(&s);
StackPush(&s,root);
while(!StackEmpty(&s))
{
BTNode *cur = StackTop(&s);
printf("%c ",cur->data);
StackPop(&s);
if(cur->Rchild)
StackPush(&s,cur->Rchild);
if(cur->Lchild)
StackPush(&s,cur->Lchild);
}
}
void PreOrderNor2(BTNode *root)
{
if(NULL == root)
return;
Stack s;
StackInit(&s);
StackPush(&s,root);
while(!StackEmpty(&s))
{
BTNode *cur = StackTop(&s);
StackPop(&s);
while(cur)
{
printf("%c ",cur->data);
if(cur->Rchild)
StackPush(&s,cur->Rchild);
cur = cur->Lchild;
}
}
}
20. 中序遍历非递归实现。
(1) 找以cur为根的二叉树最左侧的节点,并保存所经路径中的节点。(保存通过压栈来实现)
(2) 遍历以cur为根的二叉树的根节点。
(3) 遍历以cur为根的二叉树的右孩子。如果右子树存在,转到(1),否则回退。(回退操作通过取栈顶实现)
void InOrderNor(BTNode *root)
{
if(NULL == root)
return;
Stack s;
StackInit(&s);
BTNode *cur = root;
while(cur || !StackEmpty(&s))
{
while(cur)
{
StackPush(&s,cur);
cur = cur->Lchild;
}
cur = StackTop(&s);
printf("%c ",cur->data);
StackPop(&s);
cur = cur->Rchild;
}
}
21. 后序遍历非递归实现。
(1) 找以cur为根的二叉树最左侧的节点,并保存所经路径中的节点。(保存通过压栈来实现)
(2) 判断当前栈顶元素是否有右孩子,如果没有,遍历当前节点,否则更新cur为其右孩子节点。
void PostOrderNor(BTNode *root)
{
if(NULL == root)
return;
Stack s;
StackInit(&s);
BTNode* visitNode = NULL;
BTNode* cur = root;
while(cur || !StackEmpty(&s))
{
while(cur)
{
StackPush(&s,cur);
cur = cur->Lchild;
}
cur = StackTop(&s);
if(NULL == cur->Rchild || visitNode == cur->Rchild)
{
printf("%c ",cur->data);
StackPop(&s);
visitNode = cur;
cur = NULL;
}
else
{
cur = cur->Rchild;
}
}
}
可能有些知识点掌握不到位,还请各位读者在评论区多给意见!!!