数据结构笔记(6)二叉树的实现

本文深入探讨了二叉树的概念,包括其定义、特殊类型如完全二叉树和平衡二叉树,以及二叉树的性质。详细介绍了二叉树的前序、中序、后序遍历和层序遍历,并展示了如何用C++实现这些遍历。此外,还讨论了二叉树的深度、宽度、节点计数以及二度、一度、零度节点的计算方法。最后,讲解了翻转二叉树、判断完全二叉树、平衡二叉树、对称二叉树和单值二叉树的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

二叉树定义

二叉树图解

特殊的二叉树

二叉树的性质

二叉树的基本代码实现

二叉数的定义

二叉树的输入(创建)

二叉树的遍历

二叉树的深度优先遍历

二叉树的广度优先遍历

二叉树的基本功能函数的实现

返回宽度和深度

深度

宽度

返回节点个数

返回二度节点

返回一度节点

返回叶子节点(0度)

返回空节点(NULL)

二叉树基本特点函数的实现

翻转二叉树

二叉树性质的判断

完全二叉树

平衡二叉树

对称二叉树

单值二叉树


树的介绍

二叉树定义

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个节点最多只能有两棵子树,且有左右之分。

二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节点。

二叉树图解

特殊的二叉树

完全二叉树:

一棵深度为k的有n个结点的 二叉树 ,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与 满二叉树 中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。.

满二叉树:

一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。. 也就是说,如果一个二叉树的层数为K,且结点总数是 (2^k) -1 ,则它就是满二叉树。

二叉搜索树:

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的值; 若它的右子树不空,则右子树上所有结点的值均大于它的值

二叉平衡树(AVL):

平衡树(Balance Tree,BT) 指的是,任意节点的子树的高度差都小于等于1。常见的符合平衡树的有,B树(多路平衡搜索树)、AVL树(二叉平衡搜索树)等。

B树,B+树:

一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树。它或者是空树,或者是满足下列性质的树:根结点至少有两个子女;每个非根节点所包含的关键字个数 j 满足:[m/2] - 1 <= j <= m - 1;除根结点以外的所有结点(不包括叶子结点)的度数正好是关键字总数加1,故内部子树个数 k 满足:[m/2] <= k <= m ;所有的叶子结点都位于同一层。

红黑树:

红黑树是每个结点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求: 1.结点是红色或黑色;2.根结点是黑色;3. 所有叶子都是黑色(叶子是NIL结点);4. 每个红色结点的两个子结点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色结点);5. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。  

二叉树的性质

(1):一颗非空二叉树的第n层最多有2^(n-1)个节点

(2):若一颗非空二叉树的深度为h,那么它最多能有2^h-1个节点

(3):具有N个节点的完全二叉树,它的深度h=ceil(㏒₂(N+1))ceil表示向上取整,例如ceil(2.23)=ceil(2.64)=ceil(3)=3

★(4):一颗二叉树,2度节点和叶子节点(度为0)满足以下关系:D₀=D₂+1 也就是说叶子节点个数始终等于二度节点个数加一

★(5):一颗二叉树,若他的节点个数是2n个,那么他的叶子节点个数为n

二叉树的基本代码实现

二叉数的定义

二叉树通常采用孩子表示法,因此定义的代码为:

//定义二叉树
typedef struct BTNode {
	char data;//数据域
	BTNode* left;//指向左孩子节点
	BTNode* right;//指向右孩子节点
}BinaryTree;
/*该结构体有两个名字
分别翻译为节点(BTNode),二叉树(BinaryTree)加以区分
*/

二叉树的输入(创建)

由于二叉树是一对多结构,我们无法得知某某数据,它具体是谁的孩子节点,因此使得它不能像链表这样循环输入,而只能递归回溯输入。

所以涉及到回溯算法

★★★二叉树包含大量的回溯算法

回溯算法初步介绍

回溯算法,又称为“试探法”。解决问题时,每进行一步,都是抱着试试看的态度,如果发现当前选择并不是最好的,或者这么走下去肯定达不到目标,立刻做回退操作重新选择。这种走不通就回退再走的方法就是回溯算法。

二叉树创建代码:

//创建二叉树
void  BTCreate(BinaryTree* &root) {
	BTNode *q; //创建新节点
	q=new BTNode;//初始化节点,相当于malloc函数
	cin>>q->data;//输入数据
	if(q->data=='#') {//判断是否为'#"
		root=q=NULL; //若是,则设置虚拟节点q,并接到二叉树上
		return; //返回上一个节点
	}
    root=q; //若否,则将节点q接在二叉数上
	BTCreate(root->left); //进入左孩子
	BTCreate(root->right); //进入右孩子
	return; //返回上一个节点
}

二叉树创建图解

  

以上就是二叉树:ABC##D###的创建过程。

主要还是回溯算法,当创建了空节点的时候,就回溯返回上一个节点,不再递归分治。 

二叉树的遍历

二叉树的深度优先遍历

前序遍历,又叫先根遍历。遍历顺序:根 - > 左孩子 - >右孩子。

//前序遍历
void BTProOrder(BinaryTree* &root) {
    if(root==NULL) return;
    cout<<root->data<<" ";
    BTProOrder(root->left);
    BTProOrder(root->right);
}

中序遍历,又叫中根遍历。遍历顺序:左孩子 -> 根 -> 右孩子

//中序遍历
void BTInOrder(BinaryTree* &root) {
    if(root==NULL) return;
    BTInOrder(root->left);
    cout<<root->data<<" ";
    BTPostOrder(root->right);
}

后序遍历,又叫后根遍历。遍历顺序:左孩子 -> 右孩子 -> 根

//后序遍历
void BTPostOrder(BinaryTree* &root) {
    if(root==NULL) return;
    BTPostOrder(root->left);
    BTPostOrder(root->right);
    cout<<root->data<<" ";
}

二叉树的广度优先遍历

层序遍历。顾名思义,就是按照树的层次,从第1层到第n层,从上到下,从左到右进行遍历输出。

像这样,就是层序遍历。

//层序遍历
void BTLevelOrder(BinaryTree* &root) {
    queue<BinaryTree*>Q;
    Q.push(root);
    BTNode *q;
    while(!Q.empty()) {
        cout<<Q.front()->data;
        q=Q.front();
        Q.pop();
        if(q->left!=NULL) Q.push(q->left);
        if(q->right!=NULL) Q.push(q->right);
    }
}

二叉树的基本功能函数的实现

返回宽度和深度

深度

返回深度介绍 

int Height(BinaryTree* &root) {
    if(root==NULL) return 0;
    else return max(Height(root->left),Height(root->right))+1;//左子树或者右子树的最大值
}//max(a,b):返回a,b的最大值

宽度

返回宽度介绍 

int a[10005];//数组a表示储存第key层有几个节点
//key表示第几层,刚开始key为1,也就是第一层
//ans表示最终答案
void Wide(BinaryTree* &root,int key,int &ans) {
    if(root==NULL) return;
    else {
        a[key]++;
        ans=max(ans,a[key]);
        Wide(root->left,key+1,ans);
        Wide(root->right,key+1,ans);
    }
}

返回节点个数

返回二度节点

int node_two(BinaryTree* &root) {
    if(root==NULL) return 0;
    //同时搜索左右孩子节点
    //当左右孩子节点都不为空,说明是2度节点,值加一
    if(root->left!=NULL&&root->right!=NULL) return node_two(root->left)+node_two(root->right)+1;
    //否则直接搜索
    else return node_two(root->left)+node_two(root->right);
}

返回一度节点

int node_one(BinaryTree* &root) {
    if(root==NULL) return 0;
    //同时搜素左右孩子节点
    //当左右孩子节点有一个不为空,一个为空,说明是1度节点,值加一
    if(root->left!=NULL&&root->right==NULL || root->right!=NULL&&root->left==NULL) return node_one(root->left)+node_one(root->right)+1;
    //否则直接搜索
    else return node_one(root->left)+node_one(root->right);
}

返回叶子节点(0度)

int node_zero(BinaryTree* &root) {
    if(root==NULL) return 0;
    //同时搜素左右孩子节点
    //当左右孩子节点都为空,说明是0度节点,返回1
    if(root->left==NULL && root->right==NULL) return 1;
    //否则直接搜索
    else return node_zero(root->left)+node_zero(root->right);
}

返回空节点(NULL)

int node_NULL(BinaryTree* &root) {
    //当该节点为空,返回1
    if(root=NULL) return 1;
    //否则搜索左右孩子
    else return node_NULL(root->left)+node_NULL(root->right);
}

二叉树基本特点函数的实现

翻转二叉树

翻转二叉树可以先镜面先序遍历(根->右孩子->左孩子),并储存。然后再依次先序创建之前储存的镜面先序遍历

//创建翻转二叉树
char node[10005];
int sum2=0;
void create(BinaryTree* &root) {
    BTNode *q;
    q=new BTNode;
    q->data=node[sum2++];
    if(q->data=='#') {
        root=q=NULL;
        return;
    }
    root=q;
    create(root->left);
    create(root->right);
}
//镜面先序遍历
int sum1=0;
void sy_BTProOrder(BinaryTree* &root) {
    if(root==NULL) {
        node[sum1++]='#';
        return;
    }
    node[sum1++]=root->data;
    sy_BTProOrder(root->right);
    sy_BTProOrder(root->left); 
}

二叉树性质的判断

完全二叉树

判断是否为完全二叉树,根据定义,和宽度优先遍历(层序遍历)有点类似

bool isCompleteTree(BinaryTree* &root) {
    queue<BinaryTree*>Q;
    Q.push(root);  
    BTNode *q;
    while(!Q.empty()) {
        if(Q.front()==NULL) break;
        q=Q.front();
        Q.pop();
        Q.push(q->left);
        Q.push(q->right);
    }
    while(!Q.empty()) {
        if(Q.front()!=NULL) return false;
        Q.pop();
    }
    return true;
}

平衡二叉树

根据定义,判断左右子树深度的绝对值之差,若不大于1,并且左右子树也为平衡二叉树,则该树为平衡二叉树。

//求二叉树深度
int depth(BinaryTree* &root) {
    if(root==NULL) return 0;
    else return max(depth(root->left),depth(root->right))+1;
}
//判断是否为平衡二叉树
bool isBalanced(BinaryTree* &root) {
    if(root==NULL) return true;
    int leftDepth=depth(root->left);
    int rightDepth=depth(root->right);
    if(abs(leftDepth-rightDepth)>1) return false;
    //判断左右子树是否也为平衡二叉树
    return isBalanced(root->left) && isBalanced(root->right);
}

对称二叉树

就像照镜子一样,从根开始。整两个遍历轴,一个往左遍历,一个往右遍历,形成镜面对称。

若其中有不同,那么结束遍历,返回false。

//两个遍历轴,遍历函数
bool symmetry(BinaryTree* &rootL,BinaryTree* &rootR) {
    if(rootL==NULL&&rootR==NULL) return true;
    if(rootL==NULL||rootR==NULL) return false;
    if(rootL->data!=rootR->data) return false;
    else return (rootL->left,rootR->right) && (rootL->right,rootR->left);
}
//主判断函数
bool isSymmetryTree(BinaryTree* &root) {
    if(root==NULL) return true;
    return symmetry(root->left,root->right);
}

单值二叉树

单值二叉树是指所有节点的data都一样

bool isUnivalTree(BinaryTree* &root) {
    if(root==NULL) return true;
    if(root->data != root->left->data) return false;
    if(root->data != root->right->data) return false;
    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青衿白首志

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值