@[TOC](链式二叉树的基本操作)
@[TOC](链式二叉树的遍历)
@[TOC](链式二叉树形状的判断)
@[TOC](链式二叉树的相关计算)
@[TOC](常见的基本OJ题)
@[TOC](单值二叉树(OJ题+源码+简单叙述核心思想))
@[TOC](对称二叉树(OJ题+源码+简单叙述核心思想))
@[TOC](另一颗树的子树(OJ题+源码+简单叙述核心思想))
声明展示:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>;
#include <windows.h>
#include <windows.h>
#include <time.h>
#include <assert.h>
#include<stdbool.h>
//heap链表实现
typedef char NodeDataType;
typedef struct Node
{
NodeDataType val;
Node* leftchild;
Node* rightchild;
};
//创建一个结点
Node* BuyNode(NodeDataType x);
//二叉树前序遍历
void PreOrder(Node* root);
//二叉树中序遍历
void InOrder(Node* root);
//二叉树后序遍历
void PostOrder(Node* root);
//计算非特殊二叉树的结点数
int CountTreeSize(Node* root);
//计算叶子结点的个数
int CountLeavesSize(Node* root);
//计算二叉树第k层结点的个数
int CountLeavesKSize(Node* root, int k);
//计算二叉树的深度(规定一个结点的树深度为1)
int CountTreeDpeth(Node* root);
//二叉树查找值为x的结点
Node* FindTree(Node* root,NodeDataType x);
//二叉树销毁
void TreeDestory(Node* root);
//层序遍历二叉树 //空结点则不打印
void LayerPrintTree(Node* root);
//判断是否为完全二叉树
void IsFullBinaryTree(Node* root);
//因为层序遍历二叉树 以及 判断是否为完全二叉树 需要利用到队列,故以下为队列的代码
typedef Node* QDataType ;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QueueNode;
typedef struct Queue //队列头节点
{
QueueNode* head; //一级结构体指针传参,不可改变此指针指向的地方,但可以改变指针指向地方上的内容
QueueNode* tail;
}Queue;
void QueueInit(Queue* pq);//初始化队列
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
# 链式二叉树的基本操作
链式二叉树的创建
二叉树的内容因为具有不规则性,所以链式二叉的创建不像 链表 堆 队列 或者 用数组存储 特地去写增删查改等操作的函数接口。创建二叉树直接手动链接各结点。
Node* BuyNode(NodeDataType x)
{
Node* tem = (Node*)malloc(sizeof(Node));
if (tem == NULL)
{
printf("malloc faild");
exit(-1);
}
tem->val = x;
return tem;
}
int main()
{
//手搓一个非特殊二叉树
Node* A = BuyNode('A');
Node* B = BuyNode('B');
Node* C = BuyNode('C');
Node* D = BuyNode('D');
Node* E = BuyNode('E');
Node* F = BuyNode('F');
A->leftchild = B;//b
B->leftchild = D;//D
D->rightchild = NULL;
D->leftchild = NULL;
B->rightchild = NULL;
A->rightchild = C;//c
C->leftchild = E;//E
E->leftchild = NULL;
E->rightchild = NULL;
C->rightchild = F;//F
F->leftchild = NULL;
F->rightchild = NULL;
//之后验证函数是否可以在次处验证即可
return 0;
}
链式二叉树查找指定值(val)的的结点。
链式二叉树的销毁
Node* FindTree(Node* root,NodeDataType x )
{
if (root == NULL)
{
return NULL;
}
if (root->val == x)
{
return root;
}
Node* tem1 = FindTree(root->leftchild,x);
Node* tem2 = FindTree(root->rightchild, x);
if (tem1 != NULL)
{
return tem1;
}
if (tem2 != NULL)
{
return tem2;
}
return NULL;
}
void TreeDestory(Node* root)
{
if (root == NULL)
{
return;
}
TreeDestory(root->leftchild);
TreeDestory(root->rightchild);
free(root);
}
# 二叉树的遍历
前序遍历:按 A BC (根左右) 的顺序输出。
中序遍历:按B|A|C (左根右) 的顺序输出。
后序遍历:按BC A (左右根) 的顺序输出。
层序遍历:按照视觉视觉上从上往下,从左向右遍历。
代码实现:
/前序;根 左子树,右子树
void PreOrder(Node* root)
{
if (root == NULL)
{
printf(" NULL ");
return;
}
printf(" %c ", root->val);
PreOrder(root->leftchild);
PreOrder(root->rightchild);
}
//中序: 左子树 根 右子树
void InOrder(Node* root)
{
if (root == NULL)
{
printf(" NULL ");
return;
}
InOrder(root->leftchild);
printf(" %c ", root->val );
InOrder(root->rightchild);
}
//后序: 左子树 右子树 根
void PostOrder(Node* root)
{
if (root == NULL)
{
printf(" NULL");
return;
}
PostOrder(root->leftchild);
PostOrder(root->rightchild);
printf(" %c ", root->val);
}
//层序遍历
void LayerPrintTree(Node* root)
{
if (root == NULL)
{
return;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (QueueEmpty(&q) != 1 )
{
Node* tem = QueueFront(&q);
printf("%c", tem->val);
QueuePop(&q);
if (tem->leftchild != NULL)
{
QueuePush(&q, tem->leftchild);
}
if (tem->rightchild != NULL)
{
QueuePush(&q, tem->rightchild);
}
}
}
# 链式二叉树形状的判断
判断是否为完全二叉树。
完全二叉树的定义:完全二叉树是由满二叉树而引出来的,若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数(即1~h-1层为一个满二叉树),第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
完全二叉树:
非完全二叉树:
#链式二叉树相关计算:
结点数计算 :方法:递归 思想:每经过一个不为空的结点返回值 +1
叶子节点数计算 : 方法:递归 思想:在遍历思想的基础上,判段结点左右孩子均为空时返回值+1
第k层节点计算 :方法:递归 //利用k到达k-1层,k-1的孩子不为空则+1
计算树的深度(规定只有一个结点的树深度为1) :方法:递归 思想:每往下一层便深度+1,
最终谁深度大返回谁。
int CountTreeSize(Node* root) //计算结点个数
{
if (root == NULL)
{
return 0;
}
return CountTreeSize(root->rightchild) + CountTreeSize(root->leftchild) + 1;
}
//计算叶子结点个数
int CountLeavesSize(Node* root)
{
if (root == NULL)
{
return 0;
}
if (root->leftchild == NULL && root->rightchild == NULL)
{
return 1;
}
return CountLeavesSize(root->leftchild) + CountLeavesSize(root->rightchild);
}
//计算二叉树第k层结点的个数
int CountLeavesKSize(Node* root, int k)
{
if (root == NULL)
{
return 0;
}
if (k == 1 )
{
return 1;
}
if (k > 1)
{
return CountLeavesKSize(root->leftchild, k - 1) + CountLeavesKSize(root->rightchild,k - 1);
}
return NULL;
}
//计算深度
int CountTreeDpeth(Node* root)
{
if (root == NULL)
{
return 0;
}
if (root->leftchild == NULL && root->rightchild == NULL)
{
return 1;
}
int tem1 = CountTreeDpeth(root->leftchild);
int tem2 = CountTreeDpeth(root->rightchild);
return tem1 > tem2 ? tem1 + 1 : tem2 + 1 ;
}
# 常见OJ题
# 单值二叉树
题目要求:
核心思想:在递归的基础下,分别比较每个根与左孩子和有孩子的值
源码:
bool isUnivalTree(struct TreeNode* root){
if(root == NULL)
{
return true;
}
//若左子树中的值不等于根结点的值,则返回false
//注:这里一定要注意限制左右孩子的节点,因为左右孩子有可能为NULL
if(root->left && root->val != root->left->val)
{
return false;
}
//如果右子树中的值不等于根结点的值,则返回true
if(root->right && root->val != root->right->val)
{
return false;
}
//如果都相等的话,则说明是单值二叉树
return isUnivalTree(root->left) && isUnivalTree(root->right);
}
# 对称二叉树
题目要求:
核心思想:在递归的基础上,将“左孩子的右孩子“ 和”右孩子的左孩子进行比较“
源码:
bool isMirrorTree(struct TreeNode *p, struct TreeNode *q)
{
if ((p == NULL) && (q == NULL)) {
return true;
} else if ((p == NULL) || (q == NULL)) {
return false;
}
if (p->val != q->val) {
return false;
}
return (isMirrorTree(p->left, q->right)) && (isMirrorTree(p->right, q->left));
}
bool isSymmetric(struct TreeNode* root){
return isMirrorTree(root, root);
}
# 另一棵树的子树
题目要求:
核心思想:对root进行遍历比较,当某个结点的值和subroot的第一个值相同时,开始进行判定是否是相同的树,所以要先写一个判别两个数是否相同的树
源码:
bool issame(struct TreeNode* root, struct TreeNode* subRoot)
{
if((root == NULL) &&(subRoot == NULL))
{
return true;
}
// 一个为空一个不为空,说明不相同,返回false
if((root ==NULL) || (subRoot == NULL) )
{
return false;
}
if(root->val != subRoot->val)
{
return false;
}
return (issame(root->left,subRoot->left)) && (issame(root->right,subRoot->right));
}
//判断是否对称
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
if(root == NULL && subRoot == NULL)
{
return true;
}
if(root == NULL || subRoot == NULL)
{
return false ;
}
if(issame(root,subRoot))
{
return true ;
}
return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}
//本人为初学者,不足之处恳请指正。