二叉树的实现(详解,数据结构)

目录

一,二叉树需要实现的功能

二,下面是各功能详解

0.思想:

1.创建二叉树结点:

2.通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

3.二叉树销毁:

4.前序遍历:

5.中序遍历:

6.后序遍历:

7.层序遍历:

1.先实现队列的基本功能:

2.基于队列实现层序:

8.计算各类结点数量:

1.计算二叉树结点数量:

2.计算叶子结点数量:

3.计算K层结点数量:

9.二叉树查找值为X的结点:

10.判断二叉树是否为完全二叉树:


一,二叉树需要实现的功能

// 通过前序遍历的数组"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);
// 二叉树第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);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

二,下面是各功能详解

0.思想:

下面很多功能都涉及分治的思想(分治法是算法常用的解题方法之一,是将一个大的问题拆分为若干小的问题。)

1.创建二叉树结点:

//重命名存储变量类型,方便更改
typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

2.通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi) {
	if (*pi >= n || a[*pi] == '#') {
		(*pi)++;
		return NULL;
	}
	BTNode* Node = (BTNode*)malloc(sizeof(BTNode));
	if (Node == NULL) {
		perror("BinaryTreeCreate::malloc");
		exit(0);
	}
	Node->_data = a[*pi];
	(*pi)++;
	Node->_left = BinaryTreeCreate(a, n, pi);
	Node->_right = BinaryTreeCreate(a, n, pi);
	return Node;
}

按照以上所给数组描述,我们创建出的二叉树:

3.二叉树销毁:

二叉树的存储类似链表,可以由前面的结点找到后面的结点,因此二叉树的销毁也是由后向前销毁会方便很多,所以我们采取后序来销毁二叉树

// 二叉树销毁
void BinaryTreeDestory(BTNode** root) {
	if (*root == NULL) {
		return;
	}
	BinaryTreeDestory(&(*root)->_left);
	BinaryTreeDestory(&(*root)->_right);
	free(*root);
	*root = NULL;
}

4.前序遍历:

i、先访问根结点;

ii、再前序遍历左子树;

iii、最后前序遍历右子树;

算法实现:

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root) {
	if (root != NULL) {
		printf("%c ", root->_data);
		BinaryTreePrevOrder(root->_left);
		BinaryTreePrevOrder(root->_right);
	}
}

5.中序遍历:

i、中序遍历左子树;

ii、访问根结点;

iii、中序遍历右子树

算法实现:

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root) {
	if (root != NULL) {
		BinaryTreeInOrder(root->_left);
		printf("%c ", root->_data);
		BinaryTreeInOrder(root->_right);
	}
}

6.后序遍历:

i、后序遍历左子树

ii、后序遍历右子树

iii、访问根结点

算法实现:

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root) {
	if (root != NULL) {
		BinaryTreePostOrder(root->_left);
		BinaryTreePostOrder(root->_right);
		printf("%c ", root->_data);
	}
}

7.层序遍历:

设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

思路:层序遍历需要用到队列的知识,就是先将根结点入队,判断队列是否为空,循环将队首元素出队的同时队首元素子节结点入队

算法实现:

1.先实现队列的基本功能:
typedef BTNode QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{
	struct QListNode* _next;
	QDataType* _data;
}QNode;
// 队列的结构 
typedef struct Queue
{
	QNode* _front;
	QNode* _rear;
}Queue;
// 初始化队列 
void QueueInit(Queue* q) {
	assert(q);
	q->_front = NULL;
	q->_rear = NULL;
}
int QueueEmpty(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType* data) {
	assert(q);
	QNode* tmp = (QNode*)malloc(sizeof(QNode));
	if (tmp == NULL) {
		perror("QueuePush:malloc");
		return;
	}
	tmp->_data = data;
	tmp->_next = NULL;
	if (QueueEmpty(q)) {
		q->_front = tmp;
		q->_rear = tmp;
	}
	q->_rear->_next = tmp;
	q->_rear = tmp;
}
// 队头出队列 
void QueuePop(Queue* q) {
	if (QueueEmpty(q)) {
		printf("Pop: Queue is empty\n"); // 更清晰的错误信息  
		exit(0);
	}
	q->_front = q->_front->_next;
	//free(tmp);
}
// 获取队列头部元素 
QDataType* QueueFront(Queue* q) {
	return q->_front->_data;
}
// 获取队列队尾元素 
QDataType* QueueBack(Queue* q) {
	return q->_rear->_data;
}
// 获取队列中有效元素个数 
int QueueSize(Queue* q) {
	QNode* cur = q->_front;
	int size = 0;
	while (cur) {
		size++;
		cur = cur->_next;
	}
	return size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q) {
	assert(q);
	if (q->_front == NULL) {
		return 1;
	}
	return 0;
}
// 销毁队列 
void QueueDestroy(Queue* q) {
	assert(q);
	while (!QueueEmpty(q)) {
		QueuePop(q);
	}
}
2.基于队列实现层序:
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root) {
	Queue* queue = (Queue*)malloc(sizeof(Queue));
	BTNode* front;
	QueueInit(queue);
	if (root) {
		QueuePush(queue, root);
	}
	while (!QueueEmpty(queue)) {
		front = QueueFront(queue);
		if (front->_left)
		{
			QueuePush(queue, front->_left);
		}
		if (front->_right)
		{
			QueuePush(queue, front->_right);
		}
		printf("%c ",front->_data);
		QueuePop(queue);
	}
	printf("\n");
	QueueDestroy(queue);
}

8.计算各类结点数量:

1.计算二叉树结点数量:
// 二叉树节点个数
int BinaryTreeSize(BTNode* root) {
	if (root == NULL) {
		return 0;
	}
	else {
		return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;
	}
}
2.计算叶子结点数量:
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root) {
	if (root == NULL) {
		return 0;
	}
	if (root->_left == NULL && root->_right == NULL) {
		return 1;
	}
	else {
		return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
	}
}
3.计算K层结点数量:
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k) {
	if (root == NULL) {
		return 0;
	}
	if (k == 1) {
		return 1;
	}
	return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}

9.二叉树查找值为X的结点:

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x) {
	if (root==NULL) {
		return NULL;
	}
	if (root->_data == x) {
		return root;
	}
	BTNode* r1 = BinaryTreeFind(root->_left, x);
	if (r1 != NULL) {
		return r1;
	}
	return BinaryTreeFind(root->_right, x);
}

10.判断二叉树是否为完全二叉树

根据完全二叉树的定义,具有n个结点的完全二叉树与满二叉树中编号从1~n的结点一一对应。
算法思想:采用层次遍历算法,将所有结点加入队列(包括空结点)。遇到空结点时,查看其后是否有非空结点。若有,则二叉树不是完全二叉树。

判断二叉树是否为完全二叉树是二叉树层序遍历的基本用途之一,也要借助队列来实现;

算法实现:

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root) {
	Queue queue;
	QueueInit(&queue);
	if (root) {
		QueuePush(&queue, root);
	}
	while (!QueueEmpty(&queue)) {
		BTNode* front = QueueFront(&queue);
		QueuePop(&queue);
		if (front == NULL) {
			break;
		}
		QueuePush(&queue, front->_left);
		QueuePush(&queue, front->_right);
	}
	while (!QueueEmpty(&queue)) {
		BTNode* front = QueueFront(&queue);
		QueuePop(&queue);
		if (front) {
			QueueDestroy(&queue);
			return 0;
		}
	}
	QueueDestroy(&queue);
	return 1;
}
相关推荐
别NULL3 小时前
机试题——疯长的草
数据结构·c++·算法
ZSYP-S4 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
唐叔在学习4 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA5 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
武昌库里写JAVA7 小时前
浅谈怎样系统的准备前端面试
数据结构·vue.js·spring boot·算法·课程设计
S-X-S8 小时前
代码随想录刷题-数组
数据结构·算法
l138494274518 小时前
每日一题(4)
java·数据结构·算法
kyrie_sakura8 小时前
c++数据结构算法复习基础--13--基数算法
数据结构·c++·算法
XWXnb68 小时前
数据结构:顺序表
数据结构·算法
橘颂TA8 小时前
【C++】数据结构 顺序表的实现(详解)
开发语言·数据结构·c++·算法