请完成一个函数,输入一个二叉树,该函数输出它的镜像。
- 原题地址
原题
或直接转到:
https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/
今天没有继续刷题,要是强行解题也是可以,不够想到本科的数据结构忘得差不多我就回去重新复习了一遍二叉树关于C语言代码的一些教学。
二叉树的思想灵活运用了结构体与指针,让数据成为灵活的个体,这里就先缕清一些关于二叉树的初始化代码和必须学会的方法。
二叉树的初始化
#include<stdio.h>
#include<stdlib.h>
typedef struct node{//这个是节点
int data;
struct node* left;//两条线
struct node* right;
}Node;
typedef struct{//这个是“数据结构”
Node* root;
}Tree;
void insert(Tree* tree, int value){//二叉搜索树的构建
Node* node =(Node*)malloc(sizeof(Node));
node -> data = value;
node -> left = NULL;
node -> right = NULL;
/*空树的构建*/
if(tree->root == NULL){//若树为空,则让新创建的节点成为树根
tree->root = node;
}
else{//进行排序与比较
Node* temp = tree->root;
while(temp!=NULL){
if(value<temp->data){
if(temp->left==NULL){
temp->left=node;
return;
}
else{
temp=temp->left;
}
}
else{
if(temp->right==NULL){
temp->right=node;
return;
}
else{
temp=temp->right;
}
}
}
}
}
- 二叉树数据结构需要的最基本单位就是结点和线,这是最直观的感受。结点有多种,这里直接使用左右子节点的编写方法。每个结点中有三变量:“一个数据变量,用来存储数据。两个指向其他两个结点的指针”。只有结点确实可以实现二叉树的功能,不过要想将这个数据结构整体化还要给结点们组成的数据结构起个名,即BinaryTree。要明确,结点是node结构体本身,而结构体内的指针是线。
- 纵使Tree这一数据结构为node们提供了坚实的基础。我们也要自己给二叉树进行初始化。初始化的过程,可以大抵看做向一个空着的二叉树内填充(插入)结点,而结点与结点之间的关系由内部的指针决定。
- insert函数中,传入了二叉树的树根地址,与node内需要存储的data_value,要拼接肯定要先拥有拼接的东西,即结点。实例化结点,在内存中开辟空间存储node,左右指针NULL,value与实参值一样。目前为止新建的结点和Tree没有关系,只是创建了一个空包含value的Node。
- 下面的if-else才是关键,空树(根指针指向NULL)直接将新创建的node指针传入,当做树根就可以了,不过这个只适用于第一步。else中就需要对结点进行排序比较,因为必须要遵从“排序二叉树”的规则。这时就判断根节点和传入结点value值的大小关系,要是小于的话就看有无左孩子,没有的话直接按进去。有的话就让temp为左孩子,接着进行下一次判断【由于while】。由于排序二叉树左孩子一定比父结点小,这次比较要是能在对应位置找到空子结点直接按进去,总会有尽头。要是比根节点大就看有没有右孩子,没有的话就下次用右孩子为temp循环。
- 为了适应循环结构,让电脑来对二叉树进行初始化,排序二叉树应运而生。“中间大于左树,中间小于右树”。
先序遍历二叉树
void preorder(Node* node){//先序遍历排序二叉树
if(node !=NULL){
printf("%d\n",node->data);
preorder(node->left);
preorder(node->right);
}
}
- 这个递归思想就比较明显,直接拿来根结点value输出,每一次都先递归左孩子。而根据递归的规律,到最后一个左孩子被递归完毕,最先输出的是最后一个左孩子的好兄弟,咱先别管他有没有,原理是这样的。之后再回到倒数第二个递归。
- 而关于中序和后序,只需要将printf函数放在两个preorder中间或者后面就可以了,自己体会,思想和上面一样。
得到二叉树的高度
int get_height(Node* node){//得到二叉树的高度
if(node==NULL){
return 0;
}
else{
int left_h = get_height(node->left);
int right_h = get_height(node->right);
int max = left_h;
if(right_h > max){
max = right_h;
}
return max+1;
}
}
- 同样也运用了递归思想,这个比上一个难理解一些。无指向结点的深度为0这是显然的。每一次递归都会找到max-1,因此上一次返回的就是max+1,直到最后一个的深度是0+1,而二叉树最低的也是第一层。每一次递归return的max就+1,直到最后一次结束,所有的递归都算到一起,就是深度。这个算法是将所有的结点深度都遍历,找到最深的,显然谁留到最后谁就最深。这个我还要仔细思考,说到底还是递归的用法没有熟练。
得到二叉树的最大值
int get_maximum(Node* node){//得到二叉树的最大值
if(node==NULL){
return -1;
}
else{
int m1=get_maximum(node -> left);
int m2=get_maximum(node -> right);
int m3=node->data;
int max=m1;
if(m2>max){
max=m2;
}
if(m3>max){
max=m3;
}
}
}
不得不说这是妙蛙种子进了米奇妙妙屋。这递归用的也太对劲了,首先递归的尽头即结点指针到NULL。从根节点开始向下分叉,最后一层是-1,因为是NULL。-1和显然比任何非负数都小,即可以在比较中一直从根向上取到最大值。最大值可能是任何非NULL指针指向的结构体所包含的data。我们写的是函数的第一层,也是递推的最后一关,两个变量m1、m2正好对应两个分叉,这是二叉树的基本属性。妙啊。
从今天开始,每天都写二叉树的初始化,函数随缘,此贴打卡。