链式二叉树

链式二叉树

  • 链式二叉树结构
  • 二叉树的遍历
    • 二叉树前序遍历
    • 二叉树中续遍历
    • 二叉树后续遍历
    • 二叉树层序遍历
  • 二叉树节点个数和高度等
    • 二叉树节点个数
    • 二叉树叶子节点个数
    • 二叉树第k层节点个数
    • 单值二叉树
    • 对称二叉树
    • 相同的二叉树
    • 二叉树的前序遍历
    • 二叉树的中序遍历
    • 二叉树的后序遍历
    • 另一棵树的子树
    • 二叉树的创建和销毁
    • 判断二叉树是否是完全二叉树
    • 二叉树的销毁

链式二叉树结构

链式二叉树其结构包括两个部分,一个是数据域还有指针域(指针域有两个,一个指针保存其左子树地址,另一个指针保存其右子树)。二叉树总是由根,左子树和右子树组成,因而叉树是递归定义的。二叉树是一种特殊的树形数据结构,它的每个结点最多有两个子结点,分别称为左子树结点和右子树结点。二叉树可以是空的,也就是不包含任何结点;或者是由根结点、左子树和右子树三部分组成。

链式二叉树结构定义:

typedef int BTDataType;//二叉树节点存储类型
typedef struct BinaryTreeNode
{BTDataType data;//该节点的值struct BinaryTreeNode* left;//左子树节点地址struct BinaryTreeNode* right;//右子树节点地址
}BTNode;

二叉树的遍历

二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为前序遍历(先根遍历)、中序遍历(中根遍历)和后序遍历(后根遍历)。二叉树的遍历包含前序遍历,中序遍历和后序遍历以及层序遍历。
为了实现二叉树的各种遍历我们采用手动构建一颗二叉树。其代码如下:

BTNode* createbinarytree()
{BTNode* root1 = (BTNode*)malloc(sizeof(BTDataType));BTNode* root2 = (BTNode*)malloc(sizeof(BTDataType));BTNode* root3 = (BTNode*)malloc(sizeof(BTDataType));BTNode* root4 = (BTNode*)malloc(sizeof(BTDataType));BTNode* root5 = (BTNode*)malloc(sizeof(BTDataType));BTNode* root6 = (BTNode*)malloc(sizeof(BTDataType));BTNode* root7 = (BTNode*)malloc(sizeof(BTDataType));root1->data = 1;root2->data = 3;root3->data = 5;root4->data = 2;root5->data = 4;root6->data = 6;root7->data = 8;root1->left = root2;root1->right = root3;root2->left = root4;root2->right = root5;root3->left = root6;root3->right = root7;root4->left = NULL;root4->right = NULL;root5->left = NULL;root5->right = NULL;root6->left = NULL;root6->right = NULL;root7->left = NULL;root7->right = NULL;return root1;
}

构建的二叉树其逻辑结构如下:
在这里插入图片描述

二叉树前序遍历

二叉树前序遍历(又称先序遍历)的规则是根节点,左子树,右子树。进行遍历的时候不断将其划分成根,左子树,右子树。所以根据这个遍历顺序我们采用递归的方式。

二叉树前序遍历代码如下:

void preordertraversal(BTNode*root)
{if (root == NULL)//当根为NULL返回{printf("N ");return;}printf("%d ", root->data);//先访问根节点preordertraversal(root->left);//访问左子树preordertraversal(root->right);//访问右子树
}

二叉树中续遍历

二叉树中序遍历的规则是左子树,根节点,右子树。进行遍历的时候不断将其划分成左子树,根,右子树。所以根据这个遍历顺序我们采用递归的方式。

二叉树中序遍历代码如下:

//中序遍历
void inordertraversal(BTNode* root)
{if (root == NULL)//当根为NULL返回{printf("N ");return;}inordertraversal(root->left);//访问左子树printf("%d ", root->data);//访问根节点inordertraversal(root->right);//访问右子树
}

二叉树后续遍历

二叉树后序遍历的规则是左子树,右子树和根节点。进行遍历的时候不断将其划分成左子树,右子树,根。所以根据这个遍历顺序我们采用递归的方式

二叉树后序遍历代码如下:

//后续遍历
void postordertraversal(BTNode* root)
{if (root == NULL)//当根为NULL返回{printf("N ");return;}postordertraversal(root->left);//访问左子树postordertraversal(root->right);//访问右子树printf("%d ", root->data);//访问根节点
}

二叉树层序遍历

二叉树层序遍历:设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。二叉树的层序遍历需要借助队列,队列中存储的是节点的地址,当该节点访问之后进行出队列同时将该节点的左子树和右子树的地址入队列(该节点出队列同时带该节点的左右节点,若是空就不入队列)。层序遍历顺序的示意图如下所示:
在这里插入图片描述

队列代码(queue.h)

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
//#include"vld.h"
typedef int BTDataType;//二叉树节点存储类型
typedef struct BinaryTreeNode
{BTDataType data;//该节点的值struct BinaryTreeNode* left;//左子树节点地址struct BinaryTreeNode* right;//右子树节点地址
}BTNode;
typedef BTNode* queuedatatype;//定义队列中的节点结构
typedef struct queuenode
{queuedatatype data;//存放数据struct queuenode* next;//存放写一个节点的地址
}queuenode;//定义队列结构
typedef struct queue
{queuenode* qhead;//队列的头节点queuenode* qtail;//队列尾节点int size;//当前队列中所存放的数据个数
}queue;//队列初始化
void queueinit(queue* pq);//入队列
void queuepush(queue* pq, queuedatatype data);//取队头数据
queuedatatype queuefront(queue* pq);//取队尾数据
queuedatatype queueback(queue* pq);//删除队头数据
void queuepop(queue* pq);//队列为空返回true
bool queueempty(queue* pq);//返回队列中的数据个数
int queuesize(queue* pq);//队列销毁
void queuedestroy(queue* pq);

队列代码(queue.c)

#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"//队列初始化
void queueinit(queue* pq)
{assert(pq);pq->qhead = NULL;//队头置NULLpq->qtail = NULL;//队尾置NULLpq->size = 0;//初始时队列中的元素个数为0
}//入队列
void queuepush(queue* pq, queuedatatype data)
{assert(pq);//不管队列是空还是有数据都需要开一个节点的空间queuenode* newnode = (queuenode*)malloc(sizeof(queuenode));if (newnode == NULL)//开辟失败{perror("malloc");//开辟空间失败打印提示信息return;}//将数据存放在新节点中的data中并将新节点的next置空newnode->data = data;newnode->next = NULL;if (pq->qhead == NULL)//队列为空{pq->qhead = pq->qtail = newnode;}else//队列不为空{pq->qtail->next = newnode;//将当前尾节点的next指向下一个pq->qtail = newnode;//尾节点指向新节点}pq->size++;//队列入一个数据,size+1
}//取队头数据
queuedatatype queuefront(queue* pq)
{assert(pq);assert(pq->size > 0);//当前队列中还有数据,没有数据就报错return pq->qhead->data;//有数据就直接返回队头数据
}//取队尾数据
queuedatatype queueback(queue* pq)
{assert(pq);assert(pq->size > 0);//当前队列中是否还有数据,没有数据就报错return pq->qtail->data;//有数据就直接返回队尾数据
}//删除队头数据
void queuepop(queue* pq)
{assert(pq);assert(pq->size > 0);//当前队列中是否还有数据,没有数据就报错queuenode* del = pq->qhead;//将要删除的节点的地址存下来if (pq->qhead == pq->qtail)//此时只有一个节点{pq->qhead = pq->qtail = NULL;//只有一个节点就将指向队头和队尾的指针都置空}else//此时有多个节点{pq->qhead = pq->qhead->next;//让队头指针指向下一个节点}pq->size--;free(del);//释放节点
}//队列为空返回true
bool queueempty(queue* pq)
{assert(pq);//如果size为0就表示队列为空就返回true否则返回falsereturn pq->size == 0;
}//返回队列中的数据个数
int queuesize(queue* pq)
{assert(pq);return pq->size;//直接返回size
}//队列销毁
void queuedestroy(queue* pq)
{assert(pq);queuenode* del = pq->qhead;while (del)//通过链表的遍历,依次释放节点{queuenode* next = del->next;//保存下一个节点free(del);//释放当前节点del = next;//让del指向下一个节点}pq->qhead = NULL;//队头指针置空pq->qtail = NULL;//队尾指针置空pq->size = 0;//队列中元素个数置0
}

层序遍历代码实现如下:

//层序遍历
void levelordertraversal(BTNode* root)
{if (root == NULL){return;}queue q;//创建一个队列queueinit(&q);//队列初始化queuepush(&q, root);while (!queueempty(&q))//队列不为空就继续{BTNode* root = queuefront(&q);queuepop(&q);printf("%d ", root->data);if (root->left)queuepush(&q, root->left);if (root->right)queuepush(&q, root->right);}queuedestroy(&q);//销毁队列
}

二叉树节点个数和高度等

这部分主要介绍求二叉树节点个数,叶子结点个数,第k层节点个数和查找值为x 的节点。

二叉树节点个数

求二叉树的节点个数主要思路是该节点加上该节点的左子树节点个数和右子树节点个数。所以我们采用递归的方式来实现。其代码实现如下:

// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;//当节点为空就返回0//左子树节点个数+右子树节点个数+1return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

二叉树叶子节点个数

求二叉树叶子节点个数的思路是其主要思路也是递归,要求该二叉树中叶子节点的个数那就求该二叉树中左右子树中叶子节点的个数。我们采用递归的方式,代码实现如下:

// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL)//当前节点为NULL就返回0return 0;if (root->left == NULL && root->right == NULL)//如果该节点为叶子节点就返回1return 1;//如果该节点不为叶子节点就求其左子树的叶子结点个数与其右子树的叶子结点个数之和return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

二叉树第k层节点个数

求二叉树第k层节点的个数的思路是要求第k层节点的个数那就求该节点的左右子树的第k-1层节点,所以对于求第k层节点个数的个数我们采用递归的方式,其代码实现如下:

// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL)//如果该接地那为NULL就返回0return 0;if (k == 1)//k==1表示该节点是第k层的节点,返回1return 1;//返回第k-1层的左子树节点与第k-1层的右子树节点之和return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

单值二叉树

单值二叉树Leetcode
判断一棵树是否是单值二叉树也是用递归的思路,需要判断根节点与其左节点和右节点是否与根节点的值相同(当根节点为NULL返回true),如果相同就递归其左子树和右子树。如果左节点或右节点与根节点的值不相等就返回false。代码实现如下:

//单值二叉树
bool isUnivalTree(struct TreeNode* root)
{if (root == NULL)//当前节点如果为NULL就返回truereturn true;if (root->left == NULL && root->right == NULL)//左右节点都为NULL返回truereturn true;//如果左节点不为空且左节点的值不等于本节点的值就返回falseif (root->left != NULL&&root->val!=root->left->val){return false;}//如果右节点不为空且右节点的值不等于本节点的值就返回falseif (root->right != NULL && root->val != root->right->val){return false;}//如果本节点和其左节点和右节点都是单值,那就递归其左子树和右子树return isUnivalTree(root->left) && isUnivalTree(root->right);
}

对称二叉树

对称二叉树Leetcode
要判断一棵树是否是对称二叉树同样需要递归。对称二叉树需要一个子函数来进行处理,该子函数需要两个节点的地址(分别是根节点的左节点和右节点),通过这个子函数进行递归。其代码的实现如下:

//对称二叉树
//子函数递归
bool _isSymmetric(struct TreeNode* root1, struct TreeNode* root2)
{if (root1 == NULL && root2 == NULL)//左右节点都为NULL返回truereturn true;if (root1 == NULL || root2 == NULL)//此时表示有一个节点不为NULL这表示不对称返回falsereturn false;if (root1->val != root2->val)//左右节点的值不相等表示不对称返回truereturn false;//到这里就表示左右节点相等,对左子树和右子树进行递归return _isSymmetric(root1->left, root2->right) && _isSymmetric(root1->right, root2->left);
}
bool isSymmetric(struct TreeNode* root)
{if (root == NULL)//如果树的根节点为NULL返回truereturn true;//调用子函数return _isSymmetric(root->left, root->right);
}

相同的二叉树

相同的二叉树Leetcode
要判断两颗二叉树树是否是相同的二叉树,首先需判断其根节点是否是相同的,然后递归判断其左节点和右节点。其代码实现如下:

//相同的二叉树
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{//两棵树均为NULL表示两棵树是相同的,返回trueif (p == NULL && q == NULL)return true;//只要有一颗树不为空就表示两颗数不同返回falseif (p == NULL || q == NULL)return false;//此时表示两颗数都存在,如果节点值不同就返回falseif (p->val != q->val)return false;//此时表示两个节点的值相同,进行判断其子树,递归return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

二叉树的前序遍历

二叉树前序遍历Leetcode
二叉树的前序遍历,其思想也是递归。但需要注意的是需要将二叉树的前序遍历的值依次存放在数组中,这就需要动态开辟一个数组(这个数组开辟的大小首先需要计算这颗二叉树节点的个数),遍历的过程中需要用一个下标变量,这个下标变量将遍历的值依次存放到数组中。由于下标需要在一次递归调用函数完成之后+1操作(形参是实参的拷贝,要想改变实参需要传地址),所以我们采用传地址的方式。计算树的节点个数 (tresssize 函数),通过递归的方式计算二叉树的节点总数。如果当前节点为 NULL,即表示到达了树的边界,函数返回0。对于每个非空节点,函数将计算其左子树和右子树的节点数,并将它们相加,再加上当前节点本身(即1)。这样,通过递归调用,最终能够得到整棵树的节点总数。使用 tresssize 函数计算树的节点总数,这个数值将被用来分配存储结果的数组。动态分配一个数组来存储前序遍历的结果。如果内存分配失败,则返回 NULL。使用一个辅助函数 _preorderTraversal 来递归地进行前序遍历。这个辅助函数接受当前节点、结果数组以及一个指针 i(用于跟踪结果数组的当前索引位置)。前序遍历的顺序是:首先访问根节点,然后递归访问左子树,最后递归访问右子树。在访问每个节点时,将节点的值添加到结果数组中,并更新索引 i。
完成遍历后,返回存储了遍历结果的数组。其代码的实现如下:

//计算树的节点个数
int tresssize(struct TreeNode* root)
{if(root==NULL)//如果节点为NULL返回0return 0;//如果节点return tresssize(root->left)+tresssize(root->right)+1;
}
void _preorderTraversal(struct TreeNode* root,int*ret,int*pi)
{if(root==NULL){return;}ret[(*pi)++]=root->val;_preorderTraversal(root->left,ret,pi);_preorderTraversal(root->right,ret,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{if (root == NULL){*returnSize = 0;return NULL;}*returnSize = tresssize(root);//计算二叉树的节点个数int* ret = (int*)malloc(sizeof(int) * (*returnSize));if (ret == NULL) {*returnSize = 0;return NULL;}int i = 0;_preorderTraversal(root, ret, &i);return ret;
}

二叉树的中序遍历

二叉树的中序遍历Leetcode
二叉树的中序遍历和前序遍历的思路类似的,需要注意的就是遍历节点的先后次序。其代码实现如下

int tresssize(struct TreeNode* root)
{if(root==NULL)//如果节点为NULL返回0return 0;//如果节点return tresssize(root->left)+tresssize(root->right)+1;
}
void _inorderTraversal(struct TreeNode* root,int*ret,int*pi)
{if(root==NULL){return;}_inorderTraversal(root->left,ret,pi);ret[(*pi)++]=root->val;_inorderTraversal(root->right,ret,pi);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) 
{if (root == NULL){*returnSize = 0;return NULL;}*returnSize = tresssize(root);//计算二叉树的节点个数int* ret = (int*)malloc(sizeof(int) * (*returnSize));if (ret == NULL) {*returnSize = 0;return NULL;}int i = 0;_inorderTraversal(root, ret, &i);return ret;
}

二叉树的后序遍历

二叉树的后序遍历实现的思路与上面的前序和中序遍历一致,需要注意的就是遍历节点的先后次序
二叉树的后序遍历Leetcode

int tresssize(struct TreeNode* root)
{if(root==NULL)//如果节点为NULL返回0return 0;//如果节点return tresssize(root->left)+tresssize(root->right)+1;
}
void _postorderTraversal(struct TreeNode* root,int*ret,int*pi)
{if(root==NULL){return;}_postorderTraversal(root->left,ret,pi);_postorderTraversal(root->right,ret,pi);ret[(*pi)++]=root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) 
{if (root == NULL){*returnSize = 0;return NULL;}*returnSize = tresssize(root);//计算二叉树的节点个数int* ret = (int*)malloc(sizeof(int) * (*returnSize));if (ret == NULL) {*returnSize = 0;return NULL;}int i = 0;_postorderTraversal(root, ret, &i);return ret;
}

另一棵树的子树

另一颗树的子树Leetcode
判断一棵树是否是另一颗树的子树,其思路也是递归。
isSameTree 函数检查两棵树是否相同。它首先检查如果两个树的根节点都是 NULL,则返回 true(表示两个空树显然相同)。如果其中一个为空而另一个不为空,则返回 false。如果两个节点的值不相同,也返回 false。只有当当前两个节点的值相同,并且它们的左右子树也分别相同的时候,才返回 true。
isSubtree 函数用来检查 subRoot 是否是 root 的一个子树。它首先检查 root 是否为空,如果为空则返回 false(空树不能包含任何子树)。然后,如果当前 root 的值与 subRoot 的值相同,并且它们是相同的树,就返回 true。如果不是,就递归地检查 root 的左子树和右子树是否包含 subRoot

//是否是相同的树
bool isSametree(struct TreeNode* root, struct TreeNode* subRoot)
{if(root==NULL&&subRoot==NULL){return true;}if(root==NULL||subRoot==NULL)//两棵树有一个不为空就表示不是同一棵树{return false;}if(root->val!=subRoot->val){return false;}return isSametree(root->left,subRoot->left)&&isSametree(root->right,subRoot->right);
}
//判断subRoot是否是root的子树
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{if(root==NULL)//如果遍历了所以节点还不匹配那就返回false表示subRoot不是root的子树return false;//如果节点的值与subRoot节点的值相等并且是同一棵树就返回trueif(root->val==subRoot->val&&isSametree(root,subRoot)){return true;}//如果上面的没返回那就递归其左右子树return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}

二叉树的创建和销毁

二叉树的构建和遍历Leetcode
createbinarytree函数通过递归的方式从一个字符串数组中创建一个二叉树。字符串数组中的字符代表节点的值,#字符代表空节点。函数首先检查当前字符是否为#,如果是,表示当前位置应该是一个空节点,因此返回NULL并递增索引pi。如果当前字符不是#,则创建一个新的树节点,并将当前字符赋值给节点的val属性,同时递增索引pi。接着,函数递归调用自身来创建左子树和右子树。这些递归调用分别将创建好的子树赋值给当前节点的left和right指针。最后,函数返回创建好的树节点。
中序遍历 (inordertraversal 函数)这个函数对二叉树进行中序遍历,遍历顺序是:先遍历左子树,然后访问根节点,最后遍历右子树。
函数首先检查当前节点是否为空,如果为空,则返回;否则,先递归遍历左子树,然后输出当前节点的值,最后递归遍历右子树。
其代码实现如下:

#include <stdio.h>
#include<stdlib.h>
#include<string.h>typedef struct treenode 
{char val;struct treenode* left;struct treenode* right;
} treenode;
treenode* createbinarytree(char* arr, int* pi) 
{if (arr[*pi] == '#')//当前是否是空节点,不能arr[(*pi)++],否则出现越界问题{(*pi)++;//注意*pi在这个里面++return NULL;//返回NULL}treenode* tmp = (treenode*)malloc(sizeof(treenode));tmp->val = arr[(*pi)++];tmp->left = createbinarytree(arr, pi);//将左子树节点给tmp->lefttmp->right = createbinarytree(arr, pi);//将右子树节点给tmp->leftreturn tmp;//返回tmp
}
void inordertraversal(treenode* root) 
{if (root == NULL) {return;}inordertraversal(root->left);printf("%c ", root->val);inordertraversal(root->right);
}
int main() 
{char str[100] = {0};scanf("%s",str);int size = strlen(str); //计算节点个数包括空节点int i = 0;treenode* root = createbinarytree(str, &i);inordertraversal(root);return 0;
}

判断二叉树是否是完全二叉树

是否是完全二叉树Leetcode
要判断一棵树是否是完全二叉树需要使用到队列。父节点出队列后要将这个父节点对应的子节点进入队列,当队列出到空节点时判断当前队列是否还有不为空的节点,如果有不为空的节点就表示不是完全二叉树,如果队列中都是空间点那就表示该二叉树是完全二叉树。首先需要实现一个队列然后通过类似层序遍历的方法出入队列。代码实现如下:

#include<assert.h>
typedef struct queuenode
{struct TreeNode* val;struct queuenode*next;
}queuenode;
typedef struct queue
{queuenode*qhead;queuenode*qtail;int size;
}queue;
void queueinit(queue*pq)
{pq->qhead=pq->qtail=NULL;pq->size=0;
}
void queuepush(queue*pq,struct TreeNode* val)
{queuenode*newnode=(queuenode*)malloc(sizeof(queuenode));newnode->val=val;newnode->next=NULL;if(pq->qhead==NULL){pq->qhead=pq->qtail=newnode;}else {pq->qtail->next=newnode;pq->qtail=newnode;}pq->size++;
}
struct TreeNode* queuefront(queue*pq)
{return pq->qhead->val;
}
void queuepop(queue*pq)
{assert(pq->size>0);queuenode*next=pq->qhead->next;free(pq->qhead);if(pq->qhead==pq->qtail){pq->qhead=pq->qtail=next;}else {pq->qhead=next;}pq->size--;    
}
void queuedestory(queue*pq)
{queuenode*del=pq->qhead;while(del){queuenode*next=del->next;free(del);del=next;}pq->qhead=pq->qtail=NULL;pq->size=0;
}
int queuesize(queue*pq)
{return pq->size;
}
bool isCompleteTree(struct TreeNode* root) 
{//创建一个队列queue qu;queueinit(&qu);//入队列queuepush(&qu,root);while(queuesize(&qu)>0){struct TreeNode*tmp=queuefront(&qu);queuepop(&qu);if(tmp==NULL){break;//队列出到空就退出循环}//如下一层的节点queuepush(&qu,tmp->left);queuepush(&qu,tmp->right);}//看队列中是否还有不为NULL节点,如果有则表示不是完全二叉树while(queuesize(&qu)>0){struct TreeNode*tmp=queuefront(&qu);queuepop(&qu);if(tmp!=NULL){queuedestory(&qu);return false;}}queuedestory(&qu);return true;
}

二叉树的销毁

对于二叉树的销毁,我们依然采用递归的思路,但二叉树的销毁采用的后序进行递归的(先销毁左子树再销毁右子树最后在销毁根节点)。二叉树的销毁代码实现如下:

//二叉树的销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL)//如果root为NULL就直接返回return;BinaryTreeDestory(&(*root)->left);//释放左子树BinaryTreeDestory(&(*root)->right);//释放右子树free(*root);//释放根节点*root == NULL;//将根节点置空
}

总结:本文主要介绍了二叉树的前序,中序,后序以及层序遍历。还介绍了一些关于二叉树部分的基础oj题,如单值二叉树,是否是同一棵树,是否是对称二叉树,二叉树的构建,是否是完全二叉树等(大部分题其核心都是通过递归的方式来实现的,少数题需要借助到队列)。感谢大家的观看,如有错误不足之处欢迎大家批评指正!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/31798.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloud 基于Nacos和Eureka 实现双注册双订阅

一、使用场景/原因 过渡期迁移: 当系统从一个服务注册中心迁移到另一个时&#xff0c;例如从 Eureka 迁移到 Nacos&#xff0c;可以在过渡期内同时使用两个注册中心&#xff0c;确保服务平稳迁移&#xff0c;逐步过渡&#xff0c;避免一次性切换带来的风险。 兼容性考虑: 不同的…

ASP.NET Core 6.0 使用 Log4Net 和 Nlog日志中间件

前言 两年前,浅浅的学过 .NET 6,为啥要记录下来,大概是为了以后搭架子留下引线,还有抛砖引玉。 1. 环境准备 下载 建议使用 Visual Studio 2022 开发版 官网的下载地址:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具借助 Visual Studio 设计,具有自动完成…

支付宝推出NFC(近场通信)碰一碰支付功能

近日&#xff0c;支付宝推出NFC&#xff08;近场通信&#xff09;碰一碰支付功能&#xff0c;支持iPhone、安卓手机。NFC支付早已不是新事物&#xff0c;从二维码支付重回NFC支付&#xff0c;支付宝能撬动市场吗&#xff1f; 根据网友反馈&#xff0c;目前支付宝正在上海静安大…

海外社媒网站抓取经验总结:如何更高效实现网页抓取?

有效的网络抓取需要采取战略方法来克服挑战并确保最佳数据提取。让我们深入研究一些关键实践&#xff0c;这些实践将使您能够掌握复杂的网络抓取。 一、了解 Web 抓取检测 在深入探讨最佳实践之前&#xff0c;让我们先了解一下网站如何识别和抵御网络爬虫。了解您在这一过程中…

2-12 基于CV模型卡尔曼滤波、CT模型卡尔曼滤波、IMM模型滤波的目标跟踪

基于CV模型卡尔曼滤波、CT模型卡尔曼滤波、IMM模型滤波的目标跟踪。输出跟踪轨迹及其误差。程序已调通&#xff0c;可直接运行。 2-12 CV模型卡尔曼滤波 CT模型卡尔曼滤波 - 小红书 (xiaohongshu.com)

千年古城的味蕾传奇-平凉锅盔

在甘肃平凉这片古老而神秘的土地上&#xff0c;有一种美食历经岁月的洗礼&#xff0c;依然散发着独特的魅力&#xff0c;那便是平凉锅盔。平凉锅盔&#xff0c;那可是甘肃平凉的一张美食名片。它外表金黄&#xff0c;厚实饱满&#xff0c;就像一轮散发着诱人香气的金黄月亮。甘…

【过度的乐观和自信,得治】为什么数据类项目交付失败的不少?

引言&#xff1a;数据类项目包含数据治理和数据分析类项目&#xff0c;这些是数字化转型中数据能力打造&#xff0c;是基础性的工作。这类项目通常涉及Iaas、Paas和Saas层产品和服务&#xff0c;越靠近业务客户的Saas层交付服务客户满意度低&#xff0c;项目失败的不少&#xf…

白驹过隙,沧海桑田

01. 机缘 今天是我加入CSDN的第2620天&#xff0c;是我成为创作者的第1024天。2021 年 08 月 25 日我在这里分享了人生中第一篇技术文章 springboot 签名验证。 现在在回看这篇文章还能感觉到当时的青涩和技术的薄弱&#xff0c;后面每一篇文章的输出可能都是在不断的学习和进…

Comfy UI使用最新SD3模型,并解决报错‘NoneType‘ object has no attribute ‘tokenize‘【实测可行】

解决Comfy UI使用最新SD3模型报错’NoneType’ object has no attribute ‘tokenize’ 前几天SD3发布了&#xff0c;所以想着尝尝鲜&#xff0c;便去下载了SD3来玩一玩。使用的是Comfy UI而不是Stable Diffusion UI&#xff0c;这是一个比SD UI更加灵活的UI界面&#xff0c;使用…

多头Attention MultiheadAttention 怎么用?详细解释

import torch import torch.nn as nn# 定义多头注意力层 embed_dim 512 # 输入嵌入维度 num_heads 8 # 注意力头的数量 multihead_attn nn.MultiheadAttention(embed_dim, num_heads)# 创建一些示例数据 batch_size 10 # 批次大小 seq_len 20 # 序列长度 query torch…

视频监控平台功能介绍:内部设备管理(rtsp、sdk、onvif、ehome/ISUP、主动注册协议等)

一、功能概述 AS-V1000视频平台是一套集成了用户设备权限管理、视音频监控、大容量存储、电子地图的系统平台软件。它结合了现代视频技术、网络通讯技术、计算机控制技术、流媒体传输技术的综合解决方案&#xff0c;为用户提供了强大的、灵活的组网和应用能力。 AS-V1000管理端…

关于接口测试——自动化框架的设计与实现

一、自动化测试框架 在大部分测试人员眼中只要沾上“框架”&#xff0c;就感觉非常神秘&#xff0c;非常遥远。大家之所以觉得复杂&#xff0c;是因为落地运用起来很复杂&#xff1b;每个公司&#xff0c;每个业务及产品线的业务流程都不一样&#xff0c;所以就导致了“自动化…

CSS属性选择器具有不区分大小写的模式

今天&#xff0c;我偶然发现了 caniuse.com 项目的一期&#xff0c;其中提到了新的和即将推出的 CSS Level 4 选择器。 这个列表很长&#xff0c;并且有许多新的选择器正在开发中。一个新的选择器标志引起了我的注意&#xff1b;属性选择器将变成一个 i 标志&#xff0c;这使得…

pod设置资源请求和限制

设置资源请求和限制 实验目标&#xff1a; 学习如何为 Pod 设置资源请求和限制&#xff0c;以优化集群资源分配。 实验步骤&#xff1a; 创建一个 Deployment&#xff0c;并设置 CPU 和内存的资源请求和限制。使用 kubectl describe 命令查看资源分配情况。观察资源限制对 P…

智能汽车 UI 风格独具魅力

智能汽车 UI 风格独具魅力

揭秘无局放电源:定义、工作原理及其在工业设备中的重要性

当代社会对电源安全性&#xff0c;精密性要求越来也高&#xff0c;对电源设备的需求也越来越高。无局放电源作为电源设备中的一种&#xff0c;由于其独特的优点&#xff0c;越来越受到各行各业的关注。目前&#xff0c;无局放电源在全球范围内得到了广泛应用&#xff0c;尤其是…

OS复习笔记ch11-4

磁盘调度 磁盘的物理结构 经典的温彻斯特盘 其中的几个概念&#xff1a; 盘面&#xff1a;可以看成是一个操场的平面&#xff0c;不同的盘面通过中间的轴串在一起磁道&#xff1a;磁道可以看成是操场的跑道&#xff0c;我们知道操场上有外道和内道&#xff0c;最内道中间往…

论文解读:Pandora: 朝着结合自然语言动作与视频状态的通用世界模型发展

论文《Pandora: 朝着结合自然语言动作与视频状态的通用世界模型发展》探索了构建一个高度集成的AI系统&#xff0c;旨在理解自然语言指令并在视频所代表的视觉环境中执行相应操作&#xff0c;从而推进对复杂动态场景的建模与预测能力。以下是该论文的关键点和贡献的详细解读&am…

针对河南大学数据结构傻逼学堂在线的自动化脚本

首先展示一下我们的答案 {1: [对象], 2: [关系]} {1: [非数值计算], 2: [操作]} {1: [线性表]} [D] [B] [B] [C] [C] {1: [操作]} {1: [数据关系, 数据对象上关系的集合]} {1: [性质相同]} {1: [物理结构]} {1: [存储结构, 操作表示]} [C] [B] [D] [B] [D] [true] [false] [fa…