首页 > 其他分享 >【数据结构】二叉树的链式结构,二叉树的遍历,求节点个数以及高度

【数据结构】二叉树的链式结构,二叉树的遍历,求节点个数以及高度

时间:2024-09-05 22:50:42浏览次数:10  
标签:遍历 return NULL right 二叉树 数据结构 root 节点

目录

1. 二叉树链式结构的概念

2. 二叉树的遍历

2.1 前序遍历

2.2 中序遍历

2.3 后序遍历

2.4 层序遍历

3. 二叉树的节点个数以及高度

3.1 二叉树节点个数

3.2 二叉树叶子节点个数

3.3 二叉树的高度

3.4 二叉树第k层节点个数

3.5 二叉树查找值为x的节点

4.  二叉树的创建和销毁

4.1 二叉树的销毁

4.2 通过前序遍历的数组构建二叉树

4.3 判断是否是完全二叉树

5. 编程题

5.1 相同的树

5.2 单值二叉树

5.3 对称二叉树

5.4 二叉树的前序遍历

5.5 另一棵树的子树

6. 选择题


1. 二叉树链式结构的概念

由空树,根节点,根的左子树,根的右子树组成。


2. 二叉树的遍历

2.1 前序遍历

访问根结点的操作发生在遍历其左右子树之前(根左右)。当根节点为NULL时返回。

1 2 3 N N N 4 5 N N 6 N N(空可以省略)

1. 先访问根节点,然后访问根的左子树。

2. 如果根的左子树不为空就把左子树的第一个节点作为根继续往下。

3. 左子树访问完后就访问右子树。

void PreOrder(BTNode* root)
{
	if (root == NULL) return;

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

2.2 中序遍历

访问根结点的操作发生在遍历其左右子树之中(左根右)。当根节点为NULL时返回。

N 3 N 2 N 1 N 5 N 4 N 6 N(N可以省略) 

1. 先访问根节点的左子树。

2. 将左子树的第一个节点作为根节点继续访问根的左子树。

3. 当左子树为空就返回访问根,然后访问根的右子树。

void InOrder(BTNode* root)
{
	if (root == NULL) return;

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

2.3 后序遍历

访问根结点的操作发生在遍历其左右子树之后

N N 3 N 2 N N 5 N N 6 4 1

void PostOrder(BTNode* root)
{
	if (root == NULL) return;

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

2.4 层序遍历

1. 要借助队列。

2. 每个队列节点里面的数据是二叉树节点的指针。

3. 第一步,一开始,当二叉树根节点不为空就入队列。

4. 第二步,当队列不为空就不断出队列,并带入队头数据的左右节点,前提是他们不为空。

void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	//一开始,当二叉树根节点不为空就入队列。
	if (root != NULL) QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->data);
		if(front->left != NULL) QueuePush(&q, front->left);
		if(front->right != NULL) QueuePush(&q, front->right);
	}
	printf("\n");

	QueueDestroy(&q);
}

3. 二叉树的节点个数以及高度

3.1 二叉树节点个数

1. 返回右子树的节点个数和左子树的节点个数并加上自己。

2. 遇到空节点返回0。

int BinaryTreeSize(BTNode* root)
{
	//遇到空节点返回0。
	if (root == NULL) return 0;

	//返回右子树的节点个数和左子树的节点个数并加上自己。
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;	 
}

3.2 二叉树叶子节点个数

1. 找自己的左子树和右子树。

2. 找到叶子就返回1。

int BinaryTreeLeafSize(BTNode* root)
{
	//空节点返回0
	if (root == NULL) return 0;

	//找到叶子就返回1。
	if (root->left == NULL && root->right == NULL) return 1;

	//找自己的左子树和右子树。
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

3.3 二叉树的高度

1. 遇到空节点返回0。

2. 返回左右子树较大值,并加1也就是加上自己。

int BTHeight(BTNode* root)
{
	//遇到空节点返回0。
	if (root == NULL) return 0;

	//返回左右子树较大值,并加1也就是加上自己。
	int lefthigh = BTHeight(root->left);
	int righthigh = BTHeight(root->right);
	return max(lefthigh, righthigh) + 1;
}

3.4 二叉树第k层节点个数

思路:对于第一层是找第k层,对于第二层是找k-1层,对于第k层就是找当前层,不断让子树去找,每下去一层k就减一,当k==1时就是第k层。

1. k必须大于0。

2. 遇到空节点返回0。

3. 当k == 1返回1。

4. 继续找左右子树。

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	//1. k必须大于0。
	assert(k > 0);

	//2. 遇到空节点返回0。
	if (root == NULL) return 0;

	//3. 当k == 1返回1。
	if (k == 1) return 1;

	//4. 继续找左右子树。
	return BinaryTreeLevelKSize(root->left, k-1) + BinaryTreeLevelKSize(root->right, k-1);
}

3.5 二叉树查找值为x的节点

1. 遇到值相等就返回该节点,遇到空节点就返回空。

2. 先判断根节点的值是否等于x,如果等于就返回根节点,不等于就找自己的左右子树。

3. 记录左右子树的结果,谁找到了就返回,都没找到就返回空。

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL) return NULL;
	if (root->data == x) return root;

	BTNode* left = BinaryTreeFind(root->left, x); 
	if (left != NULL) return left;
	BTNode* right = BinaryTreeFind(root->right, x);
	if (right != NULL) return right;

	return NULL;
}

4.  二叉树的创建和销毁

4.1 二叉树的销毁

1. 利用后序的思想,先释放左子树再释放右子树最后释放自己。

2. 在函数外置空,调用的人自己置空。

void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL) return;
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

4.2 通过前序遍历的数组构建二叉树

链接:二叉树遍历_牛客题霸_牛客网

1. 用%s接收字符串。

2. 利用前序思想构建二叉树,将当前数组下标对应的值作为根的值构建节点,然后数组下标加一,再然后就去构建他的左子树和右子树。

3. 遇到#代表是空,下标加一然后返回空。

#include <stdio.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));
	if (node == NULL)
	{
		perror("malloc");
		return NULL;
	}
	node->data = x;
	node->left = node->right = NULL;

    return node;
}

BTNode* Insert(char* arr, int* pi)
{
    if(arr[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    BTNode* root = BuyNode(arr[*pi]);
    (*pi)++;
    root->left = Insert(arr, pi);
    root->right = Insert(arr, pi);
    return root;
}

void InOrder(BTNode* root)
{
    if(root == NULL) return;
    InOrder(root->left);
    printf("%c ", root->data);
    InOrder(root->right);
}

int main() 
{
    char arr[100];
    scanf("%s", arr);

    int i = 0;
    BTNode* root = Insert(arr, &i);

    InOrder(root);

    return 0;
}

4.3 判断是否是完全二叉树

1. 完全二叉树每一层都是连续的

2. 利用层序遍历的思想,将二叉树节点作为数据插入队列,遇到数据为空就结束遍历。

3. 判断队列剩下的数据有无非空,全都是空证明是连续的,有非空证明不连续。

bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);

	if(root != NULL) 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))
	{ 
		if (QueueFront(&q) != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
		QueuePop(&q);
	}

	QueueDestroy(&q);
	return true;
}

5. 编程题

5.1 相同的树

链接:. - 力扣(LeetCode)

思路:分治子问题。

1. 根节点值相等就比较他们的左子树和右子树。

2. 根节点值不相等直接返回false。

3. 接下来比结构,同时走到空意味着前面的结构和值是相等的,一个为空一个不为空证明结构不相等。 

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if(p->val != q->val) return false;
    
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

5.2 单值二叉树

链接:. - 力扣(LeetCode) 

思路:

1. 将根节点和自己的左右孩子比较,注意左右孩子可能为空。

2. 相等则往下交给自己的左右子树。

bool isUnivalTree(struct TreeNode* root) 
{
    if(root == NULL) return true;
    if(root->left != NULL && root->val != root->left->val) return false;
    if(root->right != NULL && root->val != root->right->val) return false;

    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

5.3 对称二叉树

链接: . - 力扣(LeetCode)

思路:

1. 根节点的左右子树要形成镜像对称。

2. 需要写一个子函数去比较左右子树是否对称。

3. 左子树的左边和右子树的右边对应,左子树的右边和右子树的左边对应。

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if(p->val != q->val) return false;
    
    return isSameTree(p->left, q->right) && isSameTree(p->right, q->left);
}

bool isSymmetric(struct TreeNode* root) 
{
    return isSameTree(root->left, root->right);    
}

5.4 二叉树的前序遍历

链接: . - 力扣(LeetCode)

思路:

1. 题目给个returnSize代表节点的个数。需要自己求。

2. 利用求的节点个数开空间。

3. 再写一个子函数进行前序遍历,将根值放入数组中,下标要传址。

void _preorderTraversal(struct TreeNode* root, int* ret, int* i)
{
    if(root == NULL) return;

    ret[(*i)++] = root->val;
    _preorderTraversal(root->left, ret, i);
    _preorderTraversal(root->right, ret, i);
}

int Size(struct TreeNode* root)
{
    if(root == NULL) return 0;
    else return 1 + Size(root->left) + Size(root->right);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{
    *returnSize = Size(root);
    int* tmp = (int*)malloc(sizeof(int)*(*returnSize));
     
    int i = 0; 
    _preorderTraversal(root, tmp, &i);
    
    return tmp;
}

5.5 另一棵树的子树

链接: . - 力扣(LeetCode)

思路:

1. 遍历root,将root每个节点和subroot比较。

2. 注意,遍历到空意味着前面的比较都不相等。subroot也不可能为空。

bool isSameTree(struct TreeNode* p, struct TreeNode* q) 
{
    if(p == NULL && q == NULL) return true;
    if(p == NULL || q == NULL) return false;
    if(p->val != q->val) return false;
    
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root == NULL) return false;
    
    if(isSameTree(root, subRoot) == true) return true;

    return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); 
}

6. 选择题

1.某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。则该完全二叉树的前序序列为()

A. ABDHECFG

B. ABCDEFGH

C. HDBEAFCG

D. HDEBFGCA

答:A

2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK; 中序遍历:HFIEJKG.则二叉树根结点为()

A. E

B. F

C. G

D. H

答:A

3.设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为____。

A. adbce

B. decab

C. debac

D. abcde

答:D

4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为

A. FEDCBA

B. CBAFED

C. DEFCBA

D. ABCDEF 

答:A

标签:遍历,return,NULL,right,二叉树,数据结构,root,节点
From: https://blog.csdn.net/m0_71164215/article/details/141336329

相关文章

  • 浙大数据结构:01-复杂度2 Maximum Subsequence Sum
    数据结构MOOCPTA习题01-复杂度2MaximumSubsequenceSum#include<iostream>usingnamespacestd;constintM=100005;inta[M];intmain(){ intk; cin>>k; intf=1; for(inti=0;i<k;i++) { cin>>a[i]; if(a[i]>=0)//如......
  • JavaScript 中的 数据结构
    数据结构数据结构是计算机存储、组织数据的方式。1.数组数组是最最基本的数据结构,很多语言都内置支持数组。数组是使用一块连续的内存空间保存数据,保存的数据的个数在分配内存的时候就是确定的。2.栈栈是一种遵循后进先出(LIFO)原则的有序集合在栈里,新元素都接近栈顶,旧元素......
  • 【数据结构】快速排序与归并排序的非递归实现
    ......
  • 快速排序(动图详解)(C语言数据结构)
    快速排序:        快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:        任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左......
  • c++遍历数组的多种方式
    方法一:普通的for循环for(inti=0;i<sizeof(a)/sizeof(a[0]);i++){cout<<a[i]<<"";}方法二:指针数组int*p[len];for(inti=0;i<len;i++){p[i]=&a[i];cout<<*p[i];}———————————————......
  • 【数据结构】排序算法系列——插入排序(附源码+图解)
    插入排序算法思想插入排序的算法思想其实很容易理解,它秉持着一个不变的循环:比较->交换->比较->交换…因为我们排序最终的目的是要得到递增或者递减的数据,那么在原有的数据中,我们可以将数据依次两两进行比较:如果是升序,那么就将较小的放在较大的前面如果是降序,那么就将较大......
  • Java-数据结构-链表-习题(三)(๑´ㅂ`๑)
    文本目录:​❄️一、习题一:  ▶ 思路: ▶ 代码:​❄️二、习题二: ▶ 思路: ▶ 代码:​❄️三、习题三: ▶ 思路: ▶ 代码:​❄️四、习题四:    ▶ 思路:   ▶ 代码:​❄️五、习题五: ▶ 思路:    ▶ 代码:  ​❄️六、习题六:   ......
  • 数据结构总结心得
    1.在数据结构数据的概念中,数据的最小单位是数据项2.数据结构中的存储结构分为顺序存储结构和链式存储结构  从逻辑上可分为线性结构和非线性结构3.带头结点的单链表head为空的条件是head->next=NULL4.在具有n各个元素的循环队列中,队满时具有n-1个元素5.栈的入栈操......
  • LeeCode-226. 翻转二叉树
    要求给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。如下图所示反转所有左右节点.解题思路与94题类似,采用递归调用遍历子节点。在基本结构中,先调换左右节点,再对左右节点内部递归调用本身。实现代码TreeNode*invertTree(TreeNode*root){if......
  • 如何使用JavaScript遍历对象
    一、使用for-in循环——简单直接,快速上手for-in循环是最基础也是最常用的对象遍历方法。它语法简单,适合初学者快速掌握constuser={name:'Alice',age:25,job:'Engineer'};for(constkeyinuser){constvalue=user[key];console.log(`${key......