本文主要是介绍数据结构____二叉树初阶,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一:二叉树的基本概念和性质
1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树
二叉树的性质:
1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.
2. 若规定根结点的层数为1,则深度为h的二叉树的最大结点数是 .
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 = +1
4. 若规定根结点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2
为底,n+1为对数)
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对
于序号为i的结点有:
1. 若i>0,i位置结点的双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点
2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子
二:二叉树一些接口的实现:
函数声明和头文件包含:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "Queue.h"typedef char BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;// 申请节点
BTNode* BuyNode(BTDataType x);
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode* root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 求二叉树的高度
int BinaryHeight(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);
对应接口实现:
层序遍历的时候需要调用队列来实现。
#define _CRT_SECURE_NO_WARNINGS 1#include "BTree.h"// 申请节点
BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}else{newnode->data = x;newnode->left = NULL;newnode->right = NULL;return newnode;}
}// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("N ");}else{printf("%d ", root->data);BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);}
}// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("N ");}else{BinaryTreeInOrder(root->left);printf("%d ", root->data);BinaryTreeInOrder(root->right);}
}// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("N ");}else{BinaryTreePostOrder(root->left);BinaryTreePostOrder(root->right);printf("%d ", root->data);}
}// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{// 如果遍历到数组的 一个位置 当前位置为空if (a[*pi] == '#' || *pi >= n){(*pi)++;return NULL;}BTNode* cur = BuyNode(a[*pi]);cur->data = a[*pi];(*pi)++;cur->left = BinaryTreeCreate(a, n, pi);cur->right = BinaryTreeCreate(a, n, pi);return cur;
}// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{// 采用后序遍历if (root == NULL){return;}BinaryTreeDestory((root)->left);BinaryTreeDestory((root)->right);free(root);root = NULL;
}// 层序遍历// 上一层带下一层
void BinaryTreeLevelOrder(BTNode* root)
{if (root == NULL){printf("NULL");return;}Queue qu;QueueInit(&qu);// 如果树不是空树,先将第一个根节点入队列if (root != NULL){QueuePush(&qu, root);}// 如果队列不为空,则将队列的中的队头数据取出,并pop掉,如果做右子树不为空,就将左右子树也入队列while(!QueueEmpty(&qu)){// 取队头元素,根节点BTNode* front = QueueFront(&qu);printf("%d ", front->data);if(front->left)QueuePush(&qu, front->left);if(front->right)QueuePush(&qu, front->right);QueuePop(&qu);}QueueDestroy(&qu);
}// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{// 如果改树根节点不为空,则改树的节点个数等于左子树加右子树加1if (root == NULL){return 0;}else{return (BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1);}
}// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{// 如果是空树if (root == NULL)return 0;if (root->left == NULL && root->right == NULL){return 1;}//int left = BinaryTreeLeafSize(root->left);//int right = BinaryTreeLeafSize(root->right);//return left + right;return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);}// 求二叉树的高度
int BinaryHeight(BTNode* root)
{// 求出左子树的高度和右子树的高度比较,大的那个加上根(+1);if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}// 求出叶子节点的个数之后还要加上自己(根)才是最后的高度,左右子树都一样。int left = BinaryHeight(root->left)+1; int right = BinaryHeight(root->right)+1;return left > right ? left : right;// 为什么这下面的代码和上面的结果不一样?//int left = BinaryHeight(root->left); //int right = BinaryHeight(root->right);//return (left > right ? left : right + 1);
}// 二叉树第k层节点个数
/*
求解第K层的节点个数,就是求解第K-1层左右节点的个数
*/
int BinaryTreeLevelKSize(BTNode* root, int k)
{// 不管是多大的问题,都先要考虑特殊情况if (root == 0)return 0;// 使用K来当递归的出口if (k == 1){return 1;}// 转换成子问题return BinaryTreeLevelKSize(root->right, k - 1)+ BinaryTreeLevelKSize(root->left, k - 1);
}// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}// 这里找到了的值应该存起来,然后返回给上一层的函数调用// 自己写的这个代码如果右子树也为空的话就返回的是空了,但是也没关系,返回是空后面也可以,// 这个代码应该就是那个网图的那种情况//BTNode* Find = BinaryTreeFind(root->left, x);//if (Find != NULL)//{// return Find;//}//else//{// return Find = BinaryTreeFind(root->right, x);//}BTNode* ret1 = BinaryTreeFind(root->left, x);if (ret1){return ret1;}BTNode* ret2 = BinaryTreeFind(root->right, x);if (ret2){return ret2;}return NULL;
}// 判断二叉树是否是完全二叉树bool BinaryTreeComplete(BTNode* root)
{// 如果是空树的情况下if (root == NULL){// printf("NULL");return false;}Queue qu;QueueInit(&qu);// 如果树不是空树,先将第一个根节点入队列if (root != NULL){QueuePush(&qu, root);}// 如果队列不为空,则将队列中的队头数据取出,并pop掉,如果做右子树不为空,就将左右子树也入队列while (!QueueEmpty(&qu)){// 取队头元素,根节点BTNode* front = QueueFront(&qu);QueuePop(&qu);if (front == NULL){break;}// 这里不需要判断左右孩子为空再入队列,因为只有将空节点也入队列后面不断出队列的时候才能找到非空QueuePush(&qu, front->left);QueuePush(&qu, front->right);}while (!QueueEmpty(&qu)){// 取队头元素,根节点BTNode* front = QueueFront(&qu);QueuePop(&qu);if (front != NULL){return false;}}QueueDestroy(&qu);return true;
}
测试函数:
#define _CRT_SECURE_NO_WARNINGS 1
#include "BTree.h"//void testarrtree()
//{
// char a[] = "ABD##E#H##CF##G##";
//
// int n = sizeof(a) / sizeof(a[0]);
// int i = 0;
//
// BTNode* tree_root = BinaryTreeCreate(a, n, &i);
//
// BinaryTreePrevOrder(tree_root);
//}// 自己手搓的树
BTNode* CreatTree()
{BTNode* root = BuyNode(0);// BTNode* root = NULL;BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);BTNode* node8 = BuyNode(8);BTNode* node9 = BuyNode(9);//BTNode* node10 = BuyNode(10);root->left = node1;root->right = node2;node1->left = node3;node1->right = node4;node2->left = node5;node2->right = node6;node3->left = node7;node3->right = node8;node4->left = node9;//node8->right = node10;return root;
}void testTree()
{// 创建一棵树BTNode* treeroot = CreatTree();// 前序遍历// BinaryTreePrevOrder(treeroot);// 中序遍历// BinaryTreeInOrder(treeroot);// 后序遍历// BinaryTreePostOrder(treeroot);// 测试树“ABD##E#H##CF##G##”;// char a[] = "ABD##E#H##CF##G##";// int n = sizeof(a) / sizeof(a[0]);// int pi = 0;// BTNode* root = BinaryTreeCreate(a, n, &pi);// BinaryTreePrevOrder(root);二叉树的销毁//BinaryTreeDestory(treeroot);//treeroot = NULL;前序遍历// BinaryTreePrevOrder(treeroot);// 求节点个数//printf("%d", BinaryTreeSize(treeroot));// 求叶子节点个数// printf("%d\n", BinaryTreeLeafSize(treeroot));// 求树的高度// printf("%d\n", BinaryHeight(treeroot));// 求第K层节点的个数// printf("%d\n", BinaryTreeLevelKSize(treeroot, 5));//BTNode* Node = BinaryTreeFind(treeroot, 4);//printf("%d\n", Node->data);// 层序遍历// BinaryTreeLevelOrder(treeroot);// 判断是否是完全二叉树printf("%d\n", BinaryTreeComplete(treeroot));
}int main()
{// testTree();// testarrtree();testTree();return 0;
}
三:二叉树的基础OJ练习:
1:965. 单值二叉树 - 力扣(LeetCode)
2:100. 相同的树 - 力扣(LeetCode)
3:101. 对称二叉树 - 力扣(LeetCode)
4:144. 二叉树的前序遍历 - 力扣(LeetCode)
5:94. 二叉树的中序遍历 - 力扣(LeetCode)
6:145. 二叉树的后序遍历 - 力扣(LeetCode)
7:572. 另一棵树的子树 - 力扣(LeetCode)
8:二叉树遍历_牛客题霸_牛客网 (nowcoder.com)
这篇关于数据结构____二叉树初阶的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!