【初阶数据结构】 左右逢源的分支诗律 二叉树3

📖 点击展开/收起 文章目录

文章目录

1. 遍历方式

1. 层序遍历

OJ层序遍历

在这里题目本身是要判断是否是完全二叉树,回顾一下完全二叉树性质是除了最后一层其他层全满,最后一层节点靠左依次排列中间不能有空缺位置,在这里我们怎么思考这个问题呢?

不论什么情况只要不是完全二叉树,她一定会有一个空节点在非空节点的前面,因为NULL会比最后一个节点先入队列
入队列过程


检查非空节点我这里列出来了两种情况,一种完全二叉树,一种非完全二叉树

c 复制代码
bool isCompleteTree(struct TreeNode* root) {
    	Queue q;
	QueueInit(&q);
		QueuePush(&q,root);
    	while (!QueueEmpty(&q))
	{
		TreeNode*front = QueueFront(&q);
		QueuePop(&q);
            if(front==NULL)
            {
                break;
            } 
			QueuePush(&q, front->left);
	QueuePush(&q, front->right);
          
	}
    while (!QueueEmpty(&q))
    {
        TreeNode*front = QueueFront(&q);
        QueuePop(&q);
        if(front)
        {
            return false;
        }
    }
	return true;
}

有小伙伴不想自己写队列的可以直接复制这里代码,然后做题,我把`队列代码也列在这里

可看看直接调用即可

  • queue代码
c 复制代码
 typedef struct TreeNode TreeNode;
typedef struct TreeNode* QDataType;
typedef struct QNode
{
	struct QNode* next;
	QDataType x;
}QNode;
typedef struct Queue
{
	QNode* ptail;
	QNode* phead;
	int size;
}Queue;
 void QueueInit(Queue* pq)
{
	assert(pq);
	pq->ptail = pq->phead = NULL;
	pq->size = 0;
}

void QueueDestory(Queue* pq)
{
	assert(pq);
	while (pq->phead)
	{
		QNode* next = pq->phead->next;
		free(pq->phead);
			pq->phead = next;
	}
	pq->ptail =pq->phead = NULL;
	pq->size = 0;
	//当queue是malloc的结构体才要free在函数外面
	//free(pq);
	//pq
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("newnode malloc fail");
	}
	newnode->next = NULL;
	newnode->x = x;
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
		pq->size++;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
		pq->size++;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq && pq->size > 0);
	if (pq->size == 1)
	{
		pq->ptail = NULL;
	}
	QNode* next = pq->phead->next;
	free(pq->phead);
	pq->phead = next;
	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq && pq->size > 0);
	return pq->phead->x;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq && pq->size > 0);
	return pq->ptail->x;
}

bool QueueEmpty(Queue* pq)
{
	return pq->size == 0;
}

int QueueSize(Queue* pq)
{
	return pq->size;
}

void QueuePrint(Queue* pq)
{
	assert(pq && pq->size > 0);
	QNode* cur = pq->phead;
	while (cur)
	{
		printf("%d ", cur->x);
		cur = cur->next;
	}
}

2. 前序遍历

在第一期我们讲过了二叉树的前序中序后序遍历,但是那只是打印数据,并没有存储数据

这一期我们将学习将遍历的数据在数组里存起来,并返回

OJ前序遍历

前序遍历,二叉树1讲得比较清楚,这里我就不做赘述,主要讲讲返回值

int* returnSize

这里是指的是数组大小,你返回一个数组,不知道数组大小很容易访问越界,不知道有多少个数据

int* preorderTraversal

这里返回的就是装有遍历序列的数组

c 复制代码
//前序遍历
void PrevOrder(BTNode* root, int* a, int* pi)
{
	if (root == NULL)
	{
		return ;
	}
	//存根节点数据
	a[*pi] = root->val;
	(*pi)++;
	PrevOrder(root->left, a, pi);
	PrevOrder(root->right, a, pi);
}
//计算数组大小
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right)+1;
}
int* preorderTraversal(BTNode* root, int* returnSize) {
	if (root == NULL)
	{
		return NULL;
	}
	*returnSize = TreeSize(root);
	int* a = (int*)malloc((*returnSize)*sizeof(int));
	int i = 0;
	 PrevOrder(root, a, &i);
	 return a;
}

后面两种遍历方式代码如下:(自取)

3. 中序遍历

OJ中序遍历

c 复制代码
void InOrder(BTNode* root, int* a, int* pi)
{
	if(root==NULL)
    {
        return;
    }
	InOrder(root->left, a, pi);
      a[*pi]=root->val;
    (*pi)++;
	InOrder(root->right, a, pi);
  
}
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right)+1;
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
	
	*returnSize = TreeSize(root);
	int* a = (int*)malloc((*returnSize)*sizeof(int));
    if (root == NULL)
	{
		return NULL;
	}
	int i = 0;
	 InOrder(root, a, &i);
	 return a;
}

4. 后序遍历

OJ后序遍历

c 复制代码
void BackOrder(BTNode* root, int* a, int* pi)
{
	if(root==NULL)
    {
        return;
    }
	BackOrder(root->left, a, pi);
	BackOrder(root->right, a, pi);
    a[*pi]=root->val;
    (*pi)++;
}
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right)+1;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
	
	*returnSize = TreeSize(root);
	int* a = (int*)malloc((*returnSize)*sizeof(int));
    if (root == NULL)
	{
		return NULL;
	}
	int i = 0;
	 BackOrder(root, a, &i);
	 return a;
}

2. 二叉树的创建

当然这里的题目还要难点你还要进行中序遍历,前面有不做赘述
OJ二叉树的创建与遍历

在这里由于篇幅我只做了左树的遍历

c 复制代码
typedef struct BnariyTree
{
	char val;
	struct BnariyTree* left;
	struct BnariyTree* right;
}BTNode;
BTNode* CreatTree(int* pi,char* a)
{
	if (a[*pi] == '#')
	{
		return NULL;
	}
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
	}
	node->val = a[*pi];
	(*pi)++;
	node->left = CreatTree(pi, a);
	(*pi)++;
	node->right = CreatTree(pi, a);
	return node;
}
 

3. 二叉树的销毁

先销毁左子树再销毁右子树再销毁根节点

c 复制代码
void DestoryTree(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	DestoryTree(root->left);
	DestoryTree(root->right);
	free(root);
}

最优二叉树(哈夫曼树)

哈夫曼树,又称最优二叉树,是一类带权路径长度 WPL 最小的二叉树,由 David A. Huffman 于 1952 年提出,核心用于数据压缩(哈夫曼编码)。

这里简单提一提,

一开始会再一个集合里面放一堆节点数为1的二叉树组成一个的森林

数值大小就称作他的权,数值越大,权越大

选取两个数值每次选取根节点大小最小的两颗二叉树,根节点求和,和的值做为权当新的根节点,合成新的二叉树

哈夫曼树为什么叫最优二叉树?

因为他都是两两合成根节点,没有度为1的节点

哈夫曼编码

你可以自己定向 左为0,向右为1

这样每一个节点都只有唯一的编码

在这里原来集合里的节点为1个的二叉树,都会有唯一编码,注意这里只有度为0的节点才有编码,也就是原集合中的节点编码

哈夫曼编码

编码长度可以不同但是

1>:0000 3>:001

2>:0001 4>:01

在这里初阶二叉树终于告一段落,谢谢大家的支支持!!!

希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

相关推荐
也曾看到过繁星7 小时前
数据结构---顺序表
数据结构
meilindehuzi_a8 小时前
深入浅出数据结构:Python 字典(Dict)与集合(Set)的哈希表底层全链路追踪
数据结构·python·散列表
_日拱一卒8 小时前
LeetCode:207课程表
java·数据结构·算法·leetcode·职场和发展
.千余11 小时前
【C++】C++类与对象2:C++构造函数、运算符重载与流输入输出全面解析
c语言·开发语言·前端·c++·经验分享
z2005093013 小时前
今日算法(回溯子集)(模版题)
数据结构·算法·leetcode
QiLinkOS13 小时前
【用呼吸重构创造价值关系——QiLink生态】
c语言·数据结构·c++·人工智能·单片机·嵌入式硬件·算法
水无痕simon13 小时前
8 判断,分支,循环语句
c语言
朔北之忘 Clancy13 小时前
2026 年 3 月青少年软编等考 C 语言二级真题解析
c语言·开发语言·c++·学习·青少年编程·题解·考级
万法若空13 小时前
Libevent C语言开发完全教程:从入门到实战
c语言·网络
晚风予卿云月14 小时前
【前缀和】一维前缀和 & 二维前缀和
数据结构·c++·算法