前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【数据结构】二叉树链式结构

【数据结构】二叉树链式结构

作者头像
用户10925563
发布2024-06-04 13:14:56
650
发布2024-06-04 13:14:56
举报
文章被收录于专栏:c/c++&&linux

1.前置说明

我们手动构建一棵二叉树:

注意:上述代码并不是创建二叉树的方式

从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的

2.二叉树的遍历

2.1 前序、中序以及后序遍历

学习二叉树结构,最简单的方式就是遍历

所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题

遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础

其实可以这样理解:

  • 前序遍历:根->左子树->右子树
  • 中序遍历:左子树->根->右子树
  • 后序遍历:左子树->右子树->根

以下面这个二叉树为例:

  • 前序遍历:1->2->3->4->5->6
  • 中序遍历:3->2->1->5->4->6
  • 后序遍历:3->2->5->6->4->1

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树

NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历

遍历的实现需要用到递归

2.2 前序遍历

代码实现是这样的:

2.3 中序遍历

2.4 后序遍历

2.5 层序遍历

层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。

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

我们可以利用队列先进先出的特点来实现:

  • 定义一个q队列
  • 如果root不为空,则将root入队列
  • 用front来保存队头数据,将队头数据pop,打印队头数据;然后遍历下一层:如果左孩子不为空,左孩子入队列;右孩子不为空,右孩子入队列;当队列不为空则继续遍历下一层,直到队列为空退出循环

关于这块的指针问题,我们画图解释一下

我们修改val也为BTNode*类型

2.5.1 分层打印

我们可以定义一个levelsize保存每一层的数据个数,控制一层一层打印

队列的size就是下一层的数据个数

效果是这样的

3.节点个数

3.1 二叉树的节点个数

3.1 叶子节点个数

4. 求树的高度

  1. 如果为空 返回0
  2. 不为空 左子树和右子树高度更高的那个+1

5.求第k层的节点个数

  1. 如果为空 返回0
  2. 如果不为空 且k=1 返回1
  3. 如果不为空 且k>1 返回左子树的k-1层+右子树的k-1层

5. 查找值为x的节点

6. 构建一棵链式二叉树

假设给一个前序遍历的数组,将其构建成一棵二叉树

7. 判断完全二叉树

完全二叉树的节点都是连续的,所以不可能出现一个NULL节点的后面存在非空节点的情况,我们用层序遍历的思路,入队列的时候不管是不是NULL节点都入队列,出队列的时候如果遇到NULL节点,则停止出队列,判断后面是否还有非空节点,我们用while循环来控制,如果队列不为空则出队列,如果队头数据有不为空的情况,则返回false

8. 销毁二叉树

销毁我们为了防止形成野指针,从下往上,从左往右,即后序遍历依次销毁

9.实现代码

9.1 Queue

9.1.1 Queue.h
代码语言:javascript
复制
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
//创建
typedef struct BTNode* QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;
//把队列的头尾封装在一个结构体中

//初始化
void QInit(Queue* pq);
//销毁
void QDestroy(Queue* pq);

//入队列
void QPush(Queue* pq, QDataType x);
//出队列
void QPop(Queue* pq);
//取队头数据
QDataType QFront(Queue* pq);
//取队尾数据
QDataType QBack(Queue* pq);
//判空
bool QEmpty(Queue* pq);
//返回队列有效元素个数
int QSize(Queue* pq);
9.1.2 Queue.c
代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
//初始化
void QInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
//销毁
void QDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
//入队列
void QPush(Queue* pq, QDataType x)
{
	assert(pq);
	//创建newnode
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;
	if (pq->ptail == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
//出队列
void QPop(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	QNode* del = pq->phead;
	pq->phead = pq->phead->next;
	free(del);
	del = NULL;
	if (pq->phead == NULL)
	{
		pq->ptail = NULL;
		//防止ptail成为野指针
	}
	pq->size--;
}
//取队头数据
QDataType QFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}
//取队尾数据
QDataType QBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}
//判空
bool QEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL;
}
//返回队列有效元素个数
int QSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

9.2 TreeNode

9.2.1 TreeNode.c
代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include "Queue.h"
//创建
typedef char BTDataType;
typedef struct BTNode
{
	BTDataType data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode;

//BTNode* BuyNode(BTDataType x)
//{
//	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
//	node->data = x;
//	node->left = NULL;
//	node->right = NULL;
//	return node;
//}
//构建二叉树
BTNode* BTCreate(BTDataType*a,int*pi)
{
	if (a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (root == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	root->data = a[(*pi)++];
	root->left = BTCreate(a,pi);
	root->right = BTCreate(a,pi);
	return root;
}
//先序遍历
void BTPrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	printf("%c ", root->data);
	BTPrevOrder(root->left);
	BTPrevOrder(root->right);
}
//中序遍历
void BTInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	BTInOrder(root->left);
	printf("%c ", root->data);
	BTInOrder(root->right);
}
//后序遍历
void BTPostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("# ");
		return;
	}
	BTPostOrder(root->left);
	BTPostOrder(root->right);
	printf("%c ", root->data);
}
// 层序遍历
void BTLevelOrder(BTNode* root)
{
	Queue q;
	QInit(&q);
	if (root)
		QPush(&q, root);
	int levelsize = 1;
	while (!QEmpty(&q))
	{
		while (levelsize--)
		{
			BTNode* front = QFront(&q);
			QPop(&q);
			printf("%c ", front->data);
			if (front->left)
				QPush(&q, front->left);
			if (front->right)
				QPush(&q, front->right);
		}
		printf("\n");
		levelsize = QSize(&q);
	}
	printf("\n");
	QDestroy(&q);
}
//判断完全二叉树
bool BTComplete(BTNode* root)
{
	Queue q;
	QInit(&q);
	if (root)
		QPush(&q, root);
	int levelsize = 1;
	while (!QEmpty(&q))
	{
		BTNode* front = QFront(&q);
		QPop(&q);
		if (front == NULL)
			break;
		QPush(&q, front->left);
		QPush(&q, front->right);
	}
	while (!QEmpty(&q))
	{
		BTNode* front = QFront(&q);
		QPop(&q);
		if (front)
		{
			QDestroy(&q);
			return false;
		}
	}
	QDestroy(&q);
	return true;
}
//销毁
void BTDestroy(BTNode* root)
{
	if (root == NULL)
		return;
	BTDestroy(root->left);
	BTDestroy(root->right);
	free(root);
}
//二叉树结点个数
//static int size = 0;
int BTSize(BTNode* root)
{
	/*if (root == NULL)
	{
		return;
	}
	++size;
	BTSize(root->left);
	BTSize(root->right);
	return size;*/
	return root == NULL ? 0 : 
		BTSize(root->left) + 
		BTSize(root->right)+1;
}
//叶子节点个数
int BTLSize(BTNode* root)
{
	/*if (root == NULL)
	{
		return 0;
	}
	return root->left == NULL && root->right == NULL ? 1:
		BTLSize(root->left) + BTLSize(root->right);*/
	return (root == NULL ? 0 : 
		(root->left == NULL && root->right == NULL ? 1 :
		BTLSize(root->left) + BTLSize(root->right)));
}
//求树的高度
int BTHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftHeight = BTHeight(root->left);
	int rightHeight = BTHeight(root->right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
//求第k层的节点个数
int BTLKSize(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return BTLKSize(root->left, k - 1) + BTLKSize(root->right, k - 1);
}
//查找值为x的节点
BTNode* BTFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* leftnode = BTFind(root->left, x);
	if (leftnode)
		return leftnode;
	BTNode* rightnode = BTFind(root->right, x);
	if (rightnode)
		return rightnode;
	return NULL;
}
int main()
{
	//char a[] = "ABD##E#H##CF##G##";
	char a[] = "ABC##D##EF##G##";
	int i = 0;
	BTNode* root = BTCreate(a,&i);
	BTPrevOrder(root);
	printf("\n");
	BTInOrder(root);
	printf("\n");
	BTPostOrder(root);
	printf("\n");
	int size1 = BTSize(root);
	printf("%d\n", size1);
	int size2 = BTSize(root);
	printf("%d\n", size2);
	int size3 = BTLSize(root);
	printf("%d\n", size3);
	int h = BTHeight(root);
	printf("%d\n", h);
	int s = BTLKSize(root, 3);
	printf("%d\n", s);

	BTLevelOrder(root);
	printf("%d\n", BTComplete(root));

	BTDestroy(root);
	root = NULL;
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.前置说明
  • 2.二叉树的遍历
    • 2.1 前序、中序以及后序遍历
      • 2.2 前序遍历
        • 2.3 中序遍历
          • 2.4 后序遍历
            • 2.5 层序遍历
              • 2.5.1 分层打印
          • 3.节点个数
            • 3.1 二叉树的节点个数
              • 3.1 叶子节点个数
              • 4. 求树的高度
              • 5. 查找值为x的节点
              • 6. 构建一棵链式二叉树
              • 7. 判断完全二叉树
              • 8. 销毁二叉树
              • 9.实现代码
                • 9.1 Queue
                  • 9.1.1 Queue.h
                  • 9.1.2 Queue.c
                • 9.2 TreeNode
                  • 9.2.1 TreeNode.c
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档