1 二叉树
1.1 相关概念
在计算机中,二叉树是指每个节点最多只有两个子节点的树形结构
× 其中起始的节点叫做根节点,整棵树只有一个根节点,除了根节点之外,每个节点都有且只有一个父节点
× 其中没有任何子节点的节点叫做叶子节点,除了叶子节点之外,每个节点最多只有两个子节点,也就是说叶子节点只有父节点,没有子节点
× 除了根节点和叶子节点之外,剩下的节点叫做枝节点,枝节点有父节点也有子节点
× 如果该二叉树中每层节点均达到最大值,也就是每个枝节点都有两个子节点,则该二叉树叫做满二叉树
× 如果该二叉树中除了最下面一层之外,每层节点个数均达到最大值,并且最下面一层的节点都连续集中在左侧,则该二叉树叫做完全二叉树
1.1 相关概念
在计算机中,二叉树是指每个节点最多只有两个子节点的树形结构
× 其中起始的节点叫做根节点,整棵树只有一个根节点,除了根节点之外,每个节点都有且只有一个父节点
× 其中没有任何子节点的节点叫做叶子节点,除了叶子节点之外,每个节点最多只有两个子节点,也就是说叶子节点只有父节点,没有子节点
× 除了根节点和叶子节点之外,剩下的节点叫做枝节点,枝节点有父节点也有子节点
× 如果该二叉树中每层节点均达到最大值,也就是每个枝节点都有两个子节点,则该二叉树叫做满二叉树
× 如果该二叉树中除了最下面一层之外,每层节点个数均达到最大值,并且最下面一层的节点都连续集中在左侧,则该二叉树叫做完全二叉树
1.2 基本的特征
二叉树具有递归嵌套式的空间结构,也就是说对于一棵二叉树来说,可以拆分为若干个小二叉树组成,因此采用递归的方法处理二叉树比较方便
处理方式如下:
处理(二叉树)
{
if(是空树) 直接处理完毕
else
{
处理根节点;
处理左子树; => 递归
处理右子树; => 递归
}
}
1.3 二叉树的存储结构
(1)顺序存储结构
一般来说, 从上到下, 从左到右依次存储节点,对于非完全二叉树来说,采用虚节点来补成完全二叉树
(2)链式存储结构
一般来说,每个节点中除了存储数据元素本身之外,还需要两个指针,分别记录左右子节点的地址
如:
typedef struct Node
{
int data; // 数据内容
struct Node *left; // 记录左子树的地址
struct Node *right; //记录右子树的地址
}Node;
1.4 基本操作
创建、销毁、插入新元素、删除元素、查找指定的元素、修改指定的元素、判断二叉树是否为满、判断二叉树是否为空、计算二叉树节点的个数、获取根节点的元素值、遍历
1.5 二叉树的遍历方式
(1) 先序遍历(DLR - data left right)
先遍历根节点,再遍历左子树,最后遍历右子树,又叫做先根遍历
(2) 中序遍历(LDR - left data right) ** ( 重点 )
先遍历左子树,再遍历根节点,最后遍历右子树,又叫做中根遍历
(3) 后序遍历(LRD - left right data)
先遍历左子树,再遍历右子树,最后遍历根节点,又叫做后根遍历
1.6 有序二叉树
一般来说,当左子树不为空时,则左子树的元素值小于等于根节点;当右子树不为空时,则右子树的元素值大于等于根节点,左右子树也分别有序,满足上述特征的二叉树,叫做有序二叉树。
二叉树具有递归嵌套式的空间结构,也就是说对于一棵二叉树来说,可以拆分为若干个小二叉树组成,因此采用递归的方法处理二叉树比较方便
处理方式如下:
处理(二叉树)
{
if(是空树) 直接处理完毕
else
{
处理根节点;
处理左子树; => 递归
处理右子树; => 递归
}
}
1.3 二叉树的存储结构
(1)顺序存储结构
一般来说, 从上到下, 从左到右依次存储节点,对于非完全二叉树来说,采用虚节点来补成完全二叉树
(2)链式存储结构
一般来说,每个节点中除了存储数据元素本身之外,还需要两个指针,分别记录左右子节点的地址
如:
typedef struct Node
{
int data; // 数据内容
struct Node *left; // 记录左子树的地址
struct Node *right; //记录右子树的地址
}Node;
1.4 基本操作
创建、销毁、插入新元素、删除元素、查找指定的元素、修改指定的元素、判断二叉树是否为满、判断二叉树是否为空、计算二叉树节点的个数、获取根节点的元素值、遍历
1.5 二叉树的遍历方式
(1) 先序遍历(DLR - data left right)
先遍历根节点,再遍历左子树,最后遍历右子树,又叫做先根遍历
(2) 中序遍历(LDR - left data right) ** ( 重点 )
先遍历左子树,再遍历根节点,最后遍历右子树,又叫做中根遍历
(3) 后序遍历(LRD - left right data)
先遍历左子树,再遍历右子树,最后遍历根节点,又叫做后根遍历
1.6 有序二叉树
一般来说,当左子树不为空时,则左子树的元素值小于等于根节点;当右子树不为空时,则右子树的元素值大于等于根节点,左右子树也分别有序,满足上述特征的二叉树,叫做有序二叉树。
***********************************************************************************
有序二叉树的代码实现:
#include <stdio.h>
#include <stdlib.h>
//定义节点的数据类型
typedef struct Node
{
int data; // 存储数据内容
struct Node *left; // 左子树的地址
struct Node *right; // 右子树的地址
} Node;
//定义有序二叉树的数据类型
typedef struct
{
Node *root; // 记录根节点的地址
int cnt; //记录节点的个数
}Tree;
//实现向有序二叉树中插入新节点的操作
void insert_data(Tree *pt, int data);
// 插入新节点的递归函数
void insert(Node **pRoot, Node *pn);
//采用中序遍历方法进行遍历
void travel_data(Tree *pt);
//遍历的递归函数
void travel(Node *pRoot);
//创建节点
Node *create_node(int data);
//清空二叉树节点
void clear_data(Tree *pt);
//递归清除节点
void clear(Node **pRoot);
//删除功能
void del_data(Tree *tp, int data);
int main(void)
{
//创建有序二叉树,并且进行初始化
Tree tree;
tree.root = NULL;
tree.cnt = 0;
//插入新节点,进行遍历
insert_data(&tree, 50);
travel_data(&tree); // 50
insert_data(&tree, 70);
travel_data(&tree); // 50 70
insert_data(&tree, 20);
travel_data(&tree); // 20 50 70
insert_data(&tree, 60);
travel_data(&tree); // 20 50 60 70
printf("二叉树中节点个数:%d\n", tree.cnt);
clear_data(&tree);
travel_data(&tree);
printf("二叉树中节点个数:%d\n", tree.cnt);
return 0;
}
Node **del(Node *pRoot, int data)
{
if (pRoot->data == data)
{
return &pRoot;
}
if (pRoot->left != NULL)
{
del(pRoot->left, data);
}
if (pRoot->right != NULL)
{
del(pRoot->right, data);
}
}
//删除功能
void del_data(Tree *pt, int data)
{
Node **del(pt->root, data);
}
//递归清除节点
void clear(Node **pRoot)
{
if ((*pRoot)->left == NULL && (*pRoot)->right == NULL)
{
free(*pRoot);
*pRoot = NULL;
return;
}
if ((*pRoot)->left != NULL)
{
clear(&(*pRoot)->left);
}
if ((*pRoot)->right != NULL)
{
clear(&(*pRoot)->right);
}
}
//清空二叉树节点
void clear_data(Tree *pt)
{
if (pt->root == NULL)
{
return;
}
while (pt->root != NULL)
{
clear(&pt->root);
}
pt->cnt = 0;
}
//创建节点
Node *create_node(int data)
{
Node *pn = (Node *)malloc(sizeof(Node));
pn->data = data;
pn->left = NULL;
pn->right = NULL;
}
//遍历的递归函数
void travel(Node *pRoot)
{
//判断二叉树不为空时才需要遍历
if (pRoot != NULL)
{
//1.遍历左子树
travel(pRoot->left);
//2.遍历根节点
printf("%d ", pRoot->data);
//3.遍历右子树
travel(pRoot->right);
}
}
//采用中序遍历方法时行遍历
void travel_data(Tree *pt)
{
//调用递归函数进行遍历
travel(pt->root);
printf("\n");
}
// 插入新节点的递归函数
void insert(Node **pRoot, Node *pn)
{
//1.判断二叉树是否为空,如果为空则让根节点指针直接指向新节点
if (NULL == *pRoot)
{
*pRoot = pn;
return;
}
//2.如果二叉树不为空,比较根节点和新节点大小
//2.1如果根节点大于新节点,插入左子树
if ((*pRoot)->data > pn->data)
{
insert(&(*pRoot)->left, pn);
}
//2.2如果根节点小于等于新节点,插入右子树
else
{
insert(&(*pRoot)->right, pn);
}
}
//实现向有序二叉树中插入新节点的操作
void insert_data(Tree *pt, int data)
{
//1.创建新节点,进行初始化
//Node *pn = (Node *)malloc(sizeof(Node));
//pn->data = data;
//pn->left = NULL;
//pn->right = NULL;
Node *pn = create_node(data);
//2.插入新节点到二叉树中,调用递归函数
insert(&pt->root, pn);
//3.二叉树中节点个数加1
pt->cnt++;
}