数据结构与算法---二叉树(精讲版)

哈喽!各位老铁们,不得不说咱们又叕见面了,今天我们要学习的是二叉树的链式结构。

一.二叉树的链式结构

1.概念:所谓二叉树的链式结构,即使用链表来实现二叉树,在二叉树的链式结构中,每个节点都有三个域组成,一个是数据域,用来保存数据,另外两个域分别是是指向该节点左右孩子的指针域,分别保存有左右孩子的地址。
2.分类:二叉树的链式结构可分为二叉链和三叉链。
在这里插入图片描述

二.二叉树链式结构的实现

1.代码声明

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

//定义二叉树的结构
typedef  char  BTDatatype;
typedef struct BinaryTreeNode
{
	BTDatatype data; 
	struct BinaryTreeNode* leftChild; //指向左孩子
	struct BinaryTreeNode* rightChild; //指向右孩子
}BTNode;

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

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

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

//层序遍历---借助队列来实现
void leverOrder(BTNode* root);

//判断完全二叉树
bool BinarytreeComplete(BTNode* root);

//求二叉树的节点个数
//方法5可行:
int BTreeSize(BTNode* root);

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

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

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

//查找二叉树节点中值为x的节点
BTNode* BTreeFind(BTNode* root, BTDatatype x);

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

//求二叉树的节点个数
//方法1和2不行:
//int BTreeSize(BTNode* root);

//求二叉树的节点个数
//方法3不行:
//int BTreeSize(BTNode* root,int size);

//求二叉树的节点个数
//方法4可行但太麻烦:
//int BTreeSize(BTNode* root, int* size);

2.代码实现

#define _CRT_SECURE_NO_WARNINGS  1
#include "BinaryTree.h"
#include "Queue.h"

//前序遍历
void preOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", root->data);
	preOrder(root->leftChild);
	preOrder(root->rightChild);
}

//中序遍历
void inOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	inOrder(root->leftChild);
	printf("%c ", root->data);
	inOrder(root->rightChild);
}

//后序遍历
void postOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	postOrder(root->leftChild);
	postOrder(root->rightChild);
	printf("%c ", root->data);
}

//层序遍历
void leverOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q,root);
	while (!QueueEmpty(&q))
	{
		BTNode* top = QueueHead(&q); //取队头
		printf("%c ", top->data);  
		QueuePop(&q);  //出队头
		if (top->leftChild)
		{
			QueuePush(&q, top->leftChild);
		}
		if (top->rightChild)
		{
			QueuePush(&q, top->rightChild);
		}
	}
	QueueDestroy(&q);
}

//判断完全二叉树
bool BinarytreeComplete(BTNode* root)
{
	Queue q1;
	QueueInit(&q1);
	QueuePush(&q1, root);
	while (!QueueEmpty(&q1))
	{
		BTNode* top = QueueHead(&q1); //取队头
		QueuePop(&q1);  //出队头
		if (top == NULL)
		{
			break;
		}
		QueuePush(&q1, top->leftChild);
		QueuePush(&q1, top->rightChild);
	}
	while (!QueueEmpty(&q1))
	{
		BTNode* top = QueueHead(&q1);
		QueuePop(&q1);
		if (top != NULL)
		{
			QueueDestroy(&q1);
			return false;
		}

	}
	QueueDestroy(&q1);
	return true;
}
//求二叉树的节点个数
//方法5:
int BTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BTreeSize(root->leftChild) + BTreeSize(root->rightChild);
}

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

//求二叉树第k层节点的个数
int BTreeKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BTreeKSize(root->leftChild, k - 1) + BTreeKSize(root->rightChild, k - 1); 
}

//求二叉树的深度(高度)
int BTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 +
		(BTreeDepth(root->leftChild) > BTreeDepth(root->rightChild) ? BTreeDepth(root->leftChild)
			: BTreeDepth(root->rightChild));
}

//查找二叉树节点中值为x的节点
BTNode* BTreeFind(BTNode* root, BTDatatype x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	if (BTreeFind(root->leftChild,x))
	{
		return BTreeFind(root->leftChild, x);
	}
	if (BTreeFind(root->rightChild,x))
	{
		return BTreeFind(root->rightChild, x);
	}
	return NULL;
}

//二叉树销毁
void BTreeDestroy(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BTreeDestroy(&((*root)->leftChild));
	BTreeDestroy(&((*root)->rightChild));
	free(*root);
	*root = NULL;
}

//求二叉树的节点个数
//方法1不行:
//int BTreeSize(BTNode* root)
//{
//	int size = 0;
//	if (root == NULL)
//	{
//		return 0;
//	}
//	size++;
//	BTreeSize(root->leftChild);
//	BTreeSize(root->rightChild);
//
//	return size;
//}

//求二叉树的节点个数
//方法2不行:
//int size = 0;
//int BTreeSize(BTNode* root)
//{
//	if (root == NULL)
//	{
//		return 0;
//	}
//	size++;
//	BTreeSize(root->leftChild);
//	BTreeSize(root->rightChild);
//
//	return size;
//}

//求二叉树的节点个数
//方法3不行:
//int BTreeSize(BTNode* root,int size)
//{
//	if (root == NULL)
//	{
//		return 0;
//	}
//	size++;
//	BTreeSize(root->leftChild,size);
//	BTreeSize(root->rightChild,size);
//
//	return size;
//}

//求二叉树的节点个数
//方法4可行但太麻烦:
//int BTreeSize(BTNode* root, int* size)
//{
//	if (root == NULL)
//	{
//		return 0;
//	}
//	(*size)++;
//	BTreeSize(root->leftChild, size);
//	BTreeSize(root->rightChild, size);
//
//	return *size;
//}


由于在二叉树的层序遍历和判断完全二叉树等方法中要使用队列相关的结构,故还要加上队列的相关代码。
3.队列声明

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//typedef int QDatatype;
//前置声明---不需包头文件
//typedef struct BTNode* QDatatype;//实现层序遍历
typedef struct BinaryTreeNode* QDatatype;//实现层序遍历,两者都行
//定义队列节点结构
typedef struct QueueNode
{
	QDatatype data;
	struct QueueNode* next; //指向下一个队列节点的指针
}QueueNode;
//定义队列结构
typedef struct Queue
{
	struct QueueNode* phead;  //指向队头
	struct QueueNode* ptail;  //指向队尾
	//int size; //队列有效数据个数
}Queue;

//初始化队列
void QueueInit(Queue* pq);

//队列销毁
void QueueDestroy(Queue* pq);

//队列打印
void QueuePrint(Queue* pq);

//入队
void QueuePush(Queue* pq, QDatatype x);

//出队
void QueuePop(Queue* pq);

//队列判空
bool QueueEmpty(Queue* pq);

//获取队头元素
QDatatype QueueHead(Queue* pq);

//获取队尾元素
QDatatype QueueTail(Queue* pq);

//获取队列元素个数
int QueueSize(Queue* pq);

4.队列实现

#define _CRT_SECURE_NO_WARNINGS  1
#include "Queue.h"

//初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	//pq->size = 0;
}

//队列打印
void QueuePrint(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		printf("%d ", pcur->data);
		pcur = pcur->next;
	}
}

//入队---队尾
void QueuePush(Queue* pq, QDatatype x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!\n");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	//pq->size++;
}

//队列判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL;
}

//出队---队头
void QueuePop(Queue* pq)
{
	assert(!QueueEmpty(pq));
	if (pq->phead == pq->ptail)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	//pq->size--;
}

//获取队头元素
QDatatype QueueHead(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

//获取队尾元素
QDatatype QueueTail(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

//获取队列元素个数---O(N)了
int QueueSize(Queue* pq)
{
	assert(pq);
	//方法1.适用于不会频繁调用获取队列元素个数的场景
	QueueNode* pcur = pq->phead;
	int size = 0;
	while (pcur)
	{
		size++;
		pcur = pcur->next;
	}
	return size;
	//方法2.在队列结构里定义一个size来计数,适用于频繁调用获取队列元素个数的场景
	//return pq->size;
}

//队列销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
	//pq->size = 0;
}

看到了这里,相信大家对二叉树这种数据结构一定有了更深层次的了解了,若大家想一起学习,那就点个关注吧,咱们后会有期!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值