数据结构____二叉树初阶

2024-09-04 10:12

本文主要是介绍数据结构____二叉树初阶,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一:二叉树的基本概念和性质

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)

这篇关于数据结构____二叉树初阶的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135728

相关文章

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre

Python 内置的一些数据结构

文章目录 1. 列表 (List)2. 元组 (Tuple)3. 字典 (Dictionary)4. 集合 (Set)5. 字符串 (String) Python 提供了几种内置的数据结构来存储和操作数据,每种都有其独特的特点和用途。下面是一些常用的数据结构及其简要说明: 1. 列表 (List) 列表是一种可变的有序集合,可以存放任意类型的数据。列表中的元素可以通过索

浙大数据结构:04-树7 二叉搜索树的操作集

这道题答案都在PPT上,所以先学会再写的话并不难。 1、BinTree Insert( BinTree BST, ElementType X ) 递归实现,小就进左子树,大就进右子树。 为空就新建结点插入。 BinTree Insert( BinTree BST, ElementType X ){if(!BST){BST=(BinTree)malloc(sizeof(struct TNo

【数据结构入门】排序算法之交换排序与归并排序

前言         在前一篇博客,我们学习了排序算法中的插入排序和选择排序,接下来我们将继续探索交换排序与归并排序,这两个排序都是重头戏,让我们接着往下看。  一、交换排序 1.1 冒泡排序 冒泡排序是一种简单的排序算法。 1.1.1 基本思想 它的基本思想是通过相邻元素的比较和交换,让较大的元素逐渐向右移动,从而将最大的元素移动到最右边。 动画演示: 1.1.2 具体步