C语言数据结构--树与二叉树

介绍二叉树的定义使用,以及一些算法和力扣例题。

二叉树定义

Leetcode定义,习惯用这种:

Definition for a binary tree node.
struct TreeNode {
     int data;
     struct TreeNode *left;
     struct TreeNode *right;
};
// 力扣中是val不是data,之后不做说明

其他方式定义:

typedef struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
} BiNode, *BiTree;

二叉树创建

函数采用递归创建,这里传递的是定义的struct TreeNode *T的地址,也就是&(T),在输入$时认为是空结点。

//二叉树的建立  按照先序遍历建立
void createBiTree(struct TreeNode **T) {
    char s[10];
    scanf("%s", &s);
    if (strcmp(s, "$") == 0) {
        *T = NULL;
    } else {
        *T = (struct TreeNode *)malloc(sizeof(struct TreeNode));  //生成结点
        if (!(*T)) {
            printf("申请空间失败\n");
        }
        (*T)->data = atoi(s);
        createBiTree(&(*T)->left);
        createBiTree(&(*T)->right);
    }
}

二叉树遍历

//二叉树先序遍历。先访问根结点,先遍历左子树再遍历右子树
void preorderVisit(struct TreeNode *T) {
    if (T)  //先要进行判断,只有结点不为空才会遍历
    {
        printf("%d ", T->data);
        preorderVisit(T->left);
        preorderVisit(T->right);
    }
}

//二叉树中序遍历,先遍历左子树,再访问根结点,再遍历右子树
void middleVisit(struct TreeNode *T) {
    if (T)  //先要进行判断,只有结点不为空才会遍历
    {
        middleVisit(T->left);
        printf("%d ", T->data);
        middleVisit(T->right);
    }
}

//二叉树后序遍历,先遍历左子树,再遍历右子树,最后访问根节点
void postVisit(struct TreeNode *T) {
    if (T)  //先要进行判断,只有结点不为空才会遍历
    {
        postVisit(T->left);
        postVisit(T->right);
        printf("%d ", T->data);
    }
}

//二叉树的层序遍历,使用数组模拟队列
void bfsVisit(struct TreeNode *T) {
    if (T) {
        struct TreeNode *queue[MAXSIZE];
        int front = 0;
        int rear = 0;
        queue[rear++] = T;  //入队
        while (front < rear) {
            struct TreeNode *tmp = queue[front++];  //出队
            printf("%d ", tmp->data);
            if (tmp->left) {
                queue[rear++] = tmp->left;  //左孩入队
            }
            if (tmp->right) {
                queue[rear++] = tmp->right;  //右孩入队
            }
        }
    }
}

运行结果

int main() {
    printf("请输入二叉树,按照先序遍历,无字树用$号表示\n");

    struct TreeNode *T;
    createBiTree(&T);

    printf("先序遍历结果如下:\n");
    preorderVisit(T);
    printf("\n");

    printf("中序遍历结果如下:\n");
    middleVisit(T);
    printf("\n");

    printf("后序遍历结果如下:\n");
    postVisit(T);
    printf("\n");

    printf("层序遍历结果如下:\n");
    bfsVisit(T);
    printf("\n");
}

创建如图的二叉树:

     3
   /   \
  9     8
 / \   / 
2   3 6
     /
    5
   /
  4

编译运行:

请输入二叉树,按照先序遍历,无字树用$号表示
3 2 2 $ $ 3 $ $ 8 6 5 4 $ $ $ $ $
先序遍历结果如下:
3 2 2 3 8 6 5 4
中序遍历结果如下:
2 2 3 3 4 5 6 8
后序遍历结果如下:
2 3 2 4 5 6 8 3
层序遍历结果如下:
3 2 8 2 3 6 5 4

力扣二叉树题目汇总

101. 对称二叉树
使用递归法,依次判断左节点和右节点是否相等非空,继续递归其左根与右根、右根与左根:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool IsSym(struct TreeNode* a,struct TreeNode* b)
{
    if(!a && !b)
        return true;
    if( (!a && b) || (a && !b) )
        return false;
    return  a->val == b->val && IsSym(a->left, b->right) && IsSym(a->right, b->left);
}

bool isSymmetric(struct TreeNode* root){
    if(!root)
        return true;
    return IsSym(root->left, root->right);
}

面试题32 - I. 从上到下打印二叉树,二叉树层序遍历
参考前面介绍的层序遍历算法,主要按照题目意思需要增加计数和返回

#define MAXSIZE 2000

int* levelOrder(struct TreeNode* root, int* returnSize) {
	returnSize[0] = 0;
	if (root == NULL)
		return NULL;
	int* res = (int*)malloc(sizeof(int) * MAXSIZE);
	struct TreeNode* queue[MAXSIZE];
	int front = 0;
    int rear = 0;
	queue[rear++] = root;
	while (front < rear)
	{
		struct TreeNode* tmp = queue[front++];
		res[returnSize[0]++] = tmp->val;
		if (tmp->left)
			queue[rear++] = tmp->left;
		if (tmp->right)
			queue[rear++] = tmp->right;
	}
	return res;
}

面试题07. 重建二叉树
使用递归法,按照前序和中序的组成格式,一般一个树前序由根节点|左子树|右子树,中序由左子树|根节点|右子树
程序运行过程,以题目示例:

    3
   / \
  9  20
    /  \
   15   7
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

第一次运行:
node->val = 3;
num = 1(位置),all = 2(截断的长度)
node->left = buildTree([9,20,15,7],1,[9,3,15,20,7],1)
    下一层:
    num->val  = 9;
    num = 0,all = 1
    node->left = buildTree([20,15,7],0,[9,3,15,20,7],0)  返回NULL
    node->right = buildTree([20,15,7],0,[3,15,20,7],0)   返回NULL
node->right = buildTree([20,15,7],3,[15,20,7],3)
这个做下去显而易见

代码如下:

struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
    //空数组返回空指针,表示空树
    if(preorderSize==0) return NULL;
    int all,num=preorderSize;//标记先序数组第一个元素在中序数组位置
    struct TreeNode* node=malloc(sizeof(struct TreeNode));
    node->val=preorder[0];
    //匹配preorder[0]在inorder的下标
    while(num--) {
        if(inorder[num]==preorder[0]){
            break;
        } 
    }
    all=num+1;
    node->left=buildTree(preorder+1,num,inorder,num);
    node->right=buildTree(preorder+all,preorderSize-all,inorder+all,inorderSize-all);
    return node;
}