首页 > 其他分享 >数据结构之链式二叉树

数据结构之链式二叉树

时间:2025-01-14 13:00:07浏览次数:3  
标签:NULL return BTNode 二叉树 链式 数据结构 root 节点

前言:前面我们学习了树相关的概念及堆的实现,今天来看看二叉树的实现。

正式实现二叉树前,我们先了解一些基础知识。

对于二叉树基础知识不清楚的可以观看数据结构------树这篇文章,回顾一下知识,有助于理解二叉树。

二叉树的遍历方式都有哪些呢?

. 前序遍历按照根节点,左节点,右节点的顺序进行遍历

. 中序遍历按照左节点,根节点,右节点的顺序进行遍历

. 后序遍历按照左节点,右节点,根节点的顺序进行遍历

. 层序遍历顾名思义就是按照二叉树一层一层的顺序进行遍历

1. 二叉树的定义

typedef struct BinaryTreeNode
{
	BTDataType val;//存储当前节点的值
	struct BinaryTreeNode* left;//指向当前节点的左孩子
	struct BinaryTreeNode* right;//指向当前节点的右孩子
}BTNode;

2. 二叉树的接口

//前序遍历
void PreOreder(BTNode* root);

//中序遍历
void InOrder(BTNode* root);

//后序遍历
void PostOrder(BTNode* root);

//二叉树节点的个数
int BinaryTreeSize(BTNode* root);

//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root);

//二叉树的叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

//二叉树第k层节点的个数
int BinaryTreeKSize(BTNode* root, int k);

//查找二叉树值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

//二叉树的销毁
void BinaryTreeDestroy(BTNode** root);

//层序遍历
void LevelOrder(BTNode* root);

//判断是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

3. 二叉树的实现

3.1 前序遍历

//前序遍历
void PreOreder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->val);
	PreOreder(root->left);
	PreOreder(root->right);
}

如图所示
在这里插入图片描述


在这里插入图片描述

3.2 中序遍历

//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%c ", root->val);
	InOrder(root->right);
}

在这里插入图片描述

3.3 后序遍历

//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->val);
}

在这里插入图片描述

按照不同方式遍历的特点去递归调用就可以了,一定要加以画图才能更好的理解。

3.4 二叉树节点的个数

//二叉树节点的个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

当前节点不为空就说明有节点,记为1,每一棵二叉树都可以由根节点+左子树+右子树构成,然后再分别去统计左子树和右子树的节点个数,最后求和

3.5 二叉树的高度

//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDepth = 1 + BinaryTreeDepth(root->left);
	int rightDepth = 1 + BinaryTreeDepth(root->right);
	return leftDepth > rightDepth ? leftDepth : rightDepth;
}

当前节点不为空,高度+1,再分别去求左子树和右子树的高度,进行比较,大的便是二叉树的高度(深度)。之所以进行比较,是因为左子树和右子树的高度有可能不同,所以要选取大的数据作为二叉树的高度

3.6 二叉树的叶子节点个数

//二叉树的叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

叶子结点的特点是该节点的左右孩子都为空,该节点就为叶子结点。分别去统计左右子树的叶子结点进行求和

3.7 二叉树第K层节点的个数

//二叉树第k层节点的个数
int BinaryTreeKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	//k控制递归的次数,当前节点不为空时,返回1,否则返回0
	return BinaryTreeKSize(root->left, k - 1) + BinaryTreeKSize(root->right, k - 1);
}

当K为1时,说明已经递归到了第K层,此时只需要统计第K-1层左右孩子的个数就可以了

3.8 查找二叉树值为X的节点

//查找二叉树值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->val == x)
	{
		return root;
	}
	BTNode* leftfind = BinaryTreeFind(root->left, x);
	if (leftfind)
	{
		return leftfind;
	}
	BTNode* rightfind = BinaryTreeFind(root->right, x);
	if (rightfind)
	{
		return rightfind;
	}
	//未找到,返回NULL
	return NULL;
}

当前节点不为空就比较该节点的值是否为X,相等就返回该节点,否则就继续对左右子树进行遍历

3.9 二叉树的销毁

if (*root == NULL)
{
	return;
}
BinaryTreeDestroy(&(*root)->left);
BinaryTreeDestroy(&(*root)->right);
free(*root);
*root = NULL;

3.10 层序遍历

//层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			printf("%c ", front->val);
			if (front->left)
			{
				QueuePush(&q, front->left);
			}
			if (front->right)
			{
				QueuePush(&q, front->right);
			}
		}
	}
	QueueDestroy(&q);
}

在这里插入图片描述
层序遍历需要借助队列来实现。首先将二叉树的根节点入队列,判断队列是否为空,不为空就出队列,判断出队列的节点是否为空(空二叉树),再判断该节点左右孩子是否为空,不为空就将该节点左右孩子入队列

3.11 判断是否是完全二叉树

//判断是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL)
		{
			break;
		}
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

判断是否是完全二叉树也需要队列来实现。先将根节点入队列,判断队列是否为空,不为空出队列,判断该节点是否为空,为空就跳出循环,否则,将该节点的左右孩子入队列。跳出循环之后继续判断队列剩下的节点是否全部为空,为空说明是完全二叉树,反之,不是完全二叉树

4. 链式二叉树完整代码

. Tree.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType val;//存储当前节点的值
	struct BinaryTreeNode* left;//指向当前节点的左孩子
	struct BinaryTreeNode* right;//指向当前节点的右孩子
}BTNode;

//前序遍历
void PreOreder(BTNode* root);

//中序遍历
void InOrder(BTNode* root);

//后序遍历
void PostOrder(BTNode* root);

//二叉树节点的个数
int BinaryTreeSize(BTNode* root);

//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root);

//二叉树的叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

//二叉树第k层节点的个数
int BinaryTreeKSize(BTNode* root, int k);

//查找二叉树值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

//二叉树的销毁
void BinaryTreeDestroy(BTNode** root);

//层序遍历
void LevelOrder(BTNode* root);

//判断是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

. Tree.c

#define _CRT_SECURE_NO_WARNINGS

#include"Tree.h"
#include"Queue.h"
//前序遍历
void PreOreder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->val);
	PreOreder(root->left);
	PreOreder(root->right);
}

//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%c ", root->val);
	InOrder(root->right);
}

//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->val);
}

//二叉树节点的个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDepth = 1 + BinaryTreeDepth(root->left);
	int rightDepth = 1 + BinaryTreeDepth(root->right);
	return leftDepth > rightDepth ? leftDepth : rightDepth;

	//return 1 + (BinaryTreeDepth(root->left) > BinaryTreeDepth(root->right) ? 
		//BinaryTreeDepth(root->left) : BinaryTreeDepth(root->right));
}

//二叉树的叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

//二叉树第k层节点的个数
int BinaryTreeKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	//k控制递归的次数,当前节点不为空时,返回1,否则返回0
	return BinaryTreeKSize(root->left, k - 1) + BinaryTreeKSize(root->right, k - 1);
}

//查找二叉树值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->val == x)
	{
		return root;
	}
	BTNode* leftfind = BinaryTreeFind(root->left, x);
	if (leftfind)
	{
		return leftfind;
	}
	BTNode* rightfind = BinaryTreeFind(root->right, x);
	if (rightfind)
	{
		return rightfind;
	}
	//未找到,返回NULL
	return NULL;
}

//二叉树的销毁
void BinaryTreeDestroy(BTNode** root)
{
	删除的是叶子结点
	///*if (*root == NULL)
	//{
	//	return;
	//}
	//if ((*root)->left == NULL && (*root)->right == NULL)
	//{
	//	free(*root);
	//	*root = NULL;
	//	return;
	//}
	//BinaryTreeDestroy(&(*root)->left);
	//BinaryTreeDestroy(&(*root)->right);*/


	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestroy(&(*root)->left);
	BinaryTreeDestroy(&(*root)->right);
	free(*root);
	*root = NULL;
}

//层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			printf("%c ", front->val);
			if (front->left)
			{
				QueuePush(&q, front->left);
			}
			if (front->right)
			{
				QueuePush(&q, front->right);
			}
		}
	}
	QueueDestroy(&q);
}

//判断是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front == NULL)
		{
			break;
		}
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

. test.c

#define _CRT_SECURE_NO_WARNINGS

#include"Tree.h"

BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("BuyNode():malloc fail");
		exit(-1);
	}
	newnode->val = x;
	newnode->left = newnode->right = NULL;
	return newnode;
}

BTNode* CreateTree()
{
	//手动创建一棵二叉树
	BTNode* n1 = BuyNode('A');
	BTNode* n2 = BuyNode('B');
	BTNode* n3 = BuyNode('C');
	BTNode* n4 = BuyNode('D');
	BTNode* n5 = BuyNode('E');
	BTNode* n6 = BuyNode('F');
	n1->left = n2;
	n1->right = n3;
	n2->left = n4;
	n3->left = n5;
	n3->right = n6;
	return n1;
}
void Test()
{
	BTNode* root = CreateTree();
	//PreOreder(root);
	//InOrder(root);
	//PostOrder(root);
	int size = BinaryTreeSize(root);
	printf("%d\n", size);
	int depth = BinaryTreeDepth(root);
	printf("%d\n", depth);
	int leafsize = BinaryTreeLeafSize(root);
	printf("%d\n", leafsize);
	int ksize = BinaryTreeKSize(root, 3);
	printf("%d\n", ksize);
	if (BinaryTreeFind(root, 'E'))
	{
		printf("找到了\n");
	}
	else
	{
		printf("未找到\n");
	}
	LevelOrder(root);
	LevelOrder(NULL);
	if (BinaryTreeComplete(root))
	{
		printf("完全二叉树\n");
	}
	else
	{
		printf("非完全二叉树\n");
	}
	BinaryTreeDestroy(&root);

}
int main()
{
	Test();
	return 0;
}

这里并没有写队列的代码实现,看不懂的小伙伴请移步初阶数据结构之队列的实现

标签:NULL,return,BTNode,二叉树,链式,数据结构,root,节点
From: https://blog.csdn.net/2402_84532723/article/details/144791934

相关文章

  • 【轻松掌握数据结构与算法】哈希(Hashing)
    什么是哈希?哈希是一种将任意长度的数据转换为固定长度的数据的技术。这个固定长度的数据通常被称为哈希值或哈希码。哈希函数是实现这一转换的关键,它接受任意长度的输入,并产生一个固定长度的输出。为什么使用哈希?哈希的主要用途之一是快速查找数据。通过哈希函数,我们可以将......
  • 代码随想录:最大二叉树
    白送/***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),left(nullptr),right(nullptr){}*TreeNode(intx):val(x),left(nullptr),right(nullptr){}......
  • 代码随想录:从中序与后序遍历序列构造二叉树
    /**Definitionforabinarytreenode.structTreeNode{intval;TreeNode*left;TreeNode*right;TreeNode():val(0),left(nullptr),right(nullptr){}TreeNode(intx):val(x),left(nullptr),right(nullptr){}TreeNode(intx,TreeNo......
  • Java-数据结构-栈与队列(常考面试题与单调栈)
    在上一篇的学习中,我们学习了栈和队列的基本知识,以及它们对应都有哪些方法,在什么应用场景下如何使用,并且还对它们进行了模拟实现,而其实对于栈和队列的相关知识还远不止于此,而今天我们就对栈与队列进行复盘,认识更多使用它们的场景,夯实代码功底吧~一、常考面试题-思维以下习题在......
  • Java算法 数据结构 栈 队列 优先队列 比较器
    目录栈Stack性质构造方法代码示例队列Queue性质构造方法代码示例优先队列PriorityQueue性质构造方法代码示例比较器1.Comparator接口的方法2.常见的内置比较器1.自然排序比较器(naturalOrder())2.逆序排序比较器(reverseOrder())3.nullsFirst()......
  • 数据结构(霍夫曼树)
    1.Huffman编码1.1问题起源假设在数据通信中,有一字串"ABABBCBBA"需要传送,一般会将这些字符进行编码,然后按编码后的二进制位进行传输,例如这些字母的ASCII码取值为:A(65):01000001B(66):01000010C(67):01000011因此最“简单”的方式,就是将上述字串直接使用字符......
  • 数据结构:栈(Stack)和队列(Queue)—面试题(二)
    1.用队列实现栈。习题链接https://leetcode.cn/problems/implement-stack-using-queues/description/描述:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。实现 MyStack 类:voidpush(intx) 将元素x压入栈顶。int......
  • 数据结构入门
    数据结构数据结构分为顺序表,链表,栈,队列,堆,树,图顺序表顺序表的物理结构和逻辑结构都是连续的去建立一个顺序表,我们需要先去了解底层是什么。在脑海中很容易就会联想到数组,所以创建一个顺序表,首先要有一个数组。但是仅仅有数组是不够的,我们需要在其中对数据进行处理,那么其有......
  • 代码随想录:完全二叉树的节点个数
    拿到一个节点,先判断是不是等边三角形,若是直接返回2^n-1,位运算写在专题中/***Definitionforabinarytreenode.*structTreeNode{*intval;*TreeNode*left;*TreeNode*right;*TreeNode():val(0),left(nullptr),right(nullptr){}*......
  • 认识Pandas,以及pandas的数据结构Series和DataFrame
    以下是关于pandas数据结构部分的详细讲解和案例:SeriesSeries是pandas中的一种一维数组结构,可以存储任意类型的数据(整数、字符串、浮点数、Python对象等),并且每个数据点都有一个对应的索引标签。创建Series案例:创建一个包含水果数量的Series对象。代码:importpandasa......