二叉树的基本操作

时间:2021-11-04 17:31:30


tree.h
#pragma once 
typedef char TreeNodeType; 

typedef struct TreeNode { 
TreeNodeType data; 
struct TreeNode* lchild; 
struct TreeNode* rchild; 
} TreeNode; 

void TreeInit(TreeNode** root); //初始化二叉树

void PreOrder(TreeNode* root); //递归先序遍历

void InOrder(TreeNode* root); 递归中序遍历

void PostOrder(TreeNode* root); 递归后序遍历

void LevelOrder(TreeNode* root); //层序遍历

TreeNode* _TreeCreate(TreeNodeType array[], size_t *index,size_t size, TreeNodeType null_node); 

 void TreeDestroy(TreeNode* root); 

 TreeNode* TreeClone(TreeNode* root); //二叉树的克隆

 size_t TreeSize(TreeNode* root); //求节点个数

 size_t TreeLeafSize(TreeNode* root); //求叶子节点个数

 size_t TreeKLevelSize(TreeNode* root, int K); //第K层节点个数

 size_t TreeHeight(TreeNode* root); //二叉树的高度

 TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find); //二叉树的查找

 reeNode* LChild(TreeNode* node); //查找当前节点的左子树

 TreeNode* RChild(TreeNode* node); //查找当前节点的右子树

 TreeNode* Parent(TreeNode* root, TreeNode* node); //查找当前节点的父节点

 void PreOrderByLoop(TreeNode* root); //非递归先序遍历

 void InOrderByLoop(TreeNode* root); //非递归中序遍历

 void PostOrderByLoop(TreeNode* root); //非递归后序遍历

 void TreeMirror(TreeNode* root); //镜像二叉树

 int IsCompleteTree(TreeNode* root);//判读是否为完全二叉树
tree.c
#include"seqstack.h"
#include<stdio.h>
#include"tree.h"
#include"linkqueue.h"
#include<stdlib.h>

void TreeInit(TreeNode** root)
{
    if(root == NULL)
    {
        return;
    }
    *root = NULL;
}
void PreOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    printf("%c ",root->data);
    PreOrder(root->lchild);
    PreOrder(root->rchild);
}

void InOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    InOrder(root->lchild);
    printf("%c ",root->data);
    InOrder(root->rchild);
}

void PostOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    PostOrder(root->lchild);
    PostOrder(root->rchild);
    printf("%c ",root->data);
    
}

void LevelOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    LinkQueue queue;
    LinkQueueInit(&queue);
    LinkQueuePush(&queue,root);
    while(1)
    {
        LinkQueueType top;
        int ret = LinkQueueFront(&queue,&top);
        if(ret == 0)
        {
            //取队首元素失败(队列为空)
            break;
        }
        printf("%c ",top->data);
        LinkQueuePop(&queue);
        if(top->lchild != NULL)
        {
            LinkQueuePush(&queue,top->lchild);
        }
        if(top->rchild != NULL)
        {
            LinkQueuePush(&queue,top->rchild);
        }
    }
}

TreeNode* CreateNode(TreeNodeType value)
{
    TreeNode* New_node = (TreeNode*)malloc(sizeof(TreeNode));
    New_node->data = value;
    New_node->lchild = NULL;
    New_node->rchild = NULL;
    return New_node;
}

void DestroyTreeNode(TreeNode* node)
{
    free(node);
}

TreeNode* _TreeCreate(TreeNodeType array[],size_t *index,size_t size,TreeNodeType null_node)
{
    if(index == NULL)
    {
        return NULL;//error
    }
    if(*index >= size)
    {
        return NULL;//越界
    }
    if(array[*index] == null_node)
    {
        return NULL;//NULL
    }
    TreeNode* root =  CreateNode(array[*index]); 
    ++(*index);
    root->lchild = _TreeCreate(array,index,size,null_node);
    ++(*index);
    root->rchild = _TreeCreate(array,index,size,null_node);
    return root;
}

TreeNode* CreateTree(TreeNodeType array[],size_t size,TreeNodeType null_node)
{
    size_t index = 0;
    TreeNode* root = _TreeCreate(array,&index,size,null_node);
    return root;
}

void TreeDestroy(TreeNode* root)
{
    //方法一
    if(root == NULL)
    {
        return;
    }
    TreeDestroy(root->lchild);
    TreeDestroy(root->rchild);
    DestroyTreeNode(root);

    //方法二
 //   TreeNode* lchild = root->lchild;
 //   TreeNode* rchild = root->lchild;
 //   DestroyTreeNode(root);
 //   TreeDestroy(lchild);
 //   TreeDestroy(rchild);
}

TreeNode* TreeClone(TreeNode* root)
{
    if(root == NULL)
    {
        return NULL;
    }
    //按先序遍历方式
    TreeNode* New_node = CreateNode(root->data);
    printf("%c ",root->data);
    New_node->lchild = TreeClone(root->lchild);
    New_node->rchild = TreeClone(root->rchild);
    return New_node;
}

//节点个数:方法一
size_t TreeSize(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    return 1 + TreeSize(root->lchild) + TreeSize(root->rchild);
}

//节点个数:方法二
void _TreeSize(TreeNode* root,size_t *size)
{
    if(root == NULL || size == NULL)
    {
        return ;
    }
    ++(*size);
    _TreeSize(root->lchild,size);
    _TreeSize(root->rchild,size);
}

//求叶子节点个数(左右子树都为空)
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)
    {
        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;
    }
    if(root->lchild == NULL && root->rchild == NULL)
    {
        return 1;
    }
    size_t lheight = TreeHeight(root->lchild);
    size_t rheight = TreeHeight(root->rchild);
    return 1 + (lheight > rheight ? lheight:rheight);
}


//查找节点(给定一个值,求对应节点的指针)
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* rresult = TreeFind(root->rchild,to_find);
    return lresult != NULL ? lresult:rresult;
}

//求当前节点的左子树
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->lchild == node)
    {
        return root;
    }
    TreeNode* lresult = Parent(root->lchild,node);
    TreeNode* rresult = Parent(root->rchild,node);
    return lresult != NULL ? lresult:rresult;
}
//非递归遍历
//
//先序遍历
//1.先将根节点入栈
//2.循环开始
//a.取栈顶元素为当前元素
//b.出栈
//c.把当前元素的右子树入栈
//d.把当前元素的左子树入栈
void PreOrderByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }

    SeqStack stack;
    SeqstackInit(&stack);
    SeqstackPush(&stack,root);
    TreeNode* cur = NULL;
    while(SeqstackFront(&stack,&cur))
    {
        SeqstackPop(&stack);
        printf("%c ",cur->data);
        if(cur->rchild != NULL)
        {
            SeqstackPush(&stack,cur->rchild);
        }
        if(cur->lchild != NULL)
        {
            SeqstackPush(&stack,cur->lchild);
        }
    }
    printf("\n");
}

//中序遍历
void InOrderByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    //1.定义cur指向根节点
    //2.循环判定cur,若不为null,将cur入栈,并且cur->lchild
    //3.如果cur=null,取栈顶元素,访问、出栈
    //4.让cur指向栈顶元素的右子树,重复
    SeqStack stack;
    SeqstackInit(&stack);
    TreeNode* cur = root;
    while(1)
    {
        while(cur != NULL)
        {
            SeqstackPush(&stack,cur);
            cur = cur->lchild;
        }
        TreeNode* top = NULL;
        int ret = SeqstackFront(&stack,&top);
        if(ret == 0)
        {
            printf("\n");
            return;
        }
        printf("%c ",top->data);
        SeqstackPop(&stack);
        cur = top->rchild;
    }
}

//后序遍历
//和中序遍历的区别:取到的栈顶元素不能立即访问,因为不能确定当前节点的右子树是否访问过
void PostOrderByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    //对于栈顶元素能不能访问,需要满足以下2个条件之一:
    //1.当前元素没有右子树
    //2.当前元素的右子树是否被访问过了(是否为下一个元素)
    //
    //此时思路为:
    //1.定义一个指针cur指向root
    //2.循环判定cur是否为空,如果不为空,cur入栈,cur = cur->lchild;
    //3.cur = NULL 循环取栈顶元素。
    //4.对栈顶元素进行判断
    //a. 如果栈顶元素的右子树和访问上一个元素是同一个元素
    //b.栈顶元素的右子树为空
    //此时才能取栈顶元素,同时出栈
    TreeNode* cur = root;
    SeqStack stack;
    SeqstackInit(&stack);
    TreeNode* pre = NULL;
    while(1)
    {
        while(cur != NULL)
        {
            SeqstackPush(&stack,cur);
            cur = cur->lchild;
        }
        TreeNode* top = NULL;
        int ret = SeqstackFront(&stack,&top);
        if(ret == 0)
        {
            printf("\n");
            return;
        }
        if(top->rchild == NULL || top->rchild == pre)
        {
            printf("%c ",top->data);
            SeqstackPop(&stack);
            pre = top;
        }
        else
        {
            cur = top->rchild;
        }
    }
}

//镜像递归
void Swap(TreeNode** a,TreeNode** b)
{
    TreeNode* tmp = *a;
    *a = *b;
    *b = tmp;
    return;
}

void TreeMirror(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    Swap(&root->lchild,&root->rchild);
    TreeMirror(root->lchild);
    TreeMirror(root->rchild);
}

//镜像非递归
void TreeMirrorByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    LinkQueue queue;
    LinkQueueInit(&queue);
    LinkQueuePush(&queue,root);
    TreeNode* cur = NULL;
    while(LinkQueueFront(&queue,&cur))
    {
        LinkQueuePop(&queue);
        if(cur->lchild != NULL)
        {
            LinkQueuePush(&queue,cur->lchild);
        }
        if(cur->rchild != NULL)
        {
            LinkQueuePush(&queue,cur->rchild);
        }
    }
    printf("\n");
    return;
}

//判断是否为完全二叉树
//条件:层序遍历
//可分为两个阶段
//一、任何一个节点同时具有左右子树,一旦发现哪个子树不是同时具备
//a.当前节点只有右子树,一定不是完全二叉树
//b.如果当前节点只有左子树,进入第二阶段。
//c.当前节点没有子树,也进入阶段二。
//二、当遍历结束后,所有条件都满足,则为完全二叉树,不满足则不是。
int IsCompleteTree(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    LinkQueue queue;
    LinkQueueInit(&queue);
    LinkQueuePush(&queue,root);
    TreeNode* cur = NULL;
    int if_start_step_to_flag = 0;
    while(LinkQueueFront(&queue,&cur))
    {
        LinkQueuePop(&queue);
        if(if_start_step_to_flag = 0)
        {
            if(cur->lchild != NULL && cur->rchild == NULL)
            {
                //同时具备右子树
                LinkQueuePush(&queue,cur->lchild);
                LinkQueuePush(&queue,cur->rchild);
            }
            else if(cur->lchild == NULL && cur->rchild != NULL)
            {
                //只有右子树,没有左子树,一定不是完全二叉树
                return 0;
            }
            else if(cur->lchild != NULL && cur->rchild == NULL)
            {
                if_start_step_to_flag = 1;
            }
            else
            {
                if(cur->lchild == NULL && cur->rchild == NULL)
                {
                    ;
                }
            }
        }
        else
        {
            return 0;
        }
    }
}