【数据结构】——树
速通回忆
下面是一个二叉树的演示:包括二叉树的类型构造,二叉树存放一个数值,二叉树的遍历(先序遍历、中序遍历、后序遍历)
你可以选择直接看这个演示代码回忆之前学过的内容,或者看下面的介绍进行二次学习
#include "stdio.h"
#include "stdlib.h"
/* 树的元素结构体,结点元素、左子树、右子树 */
typedef struct tree_n{
int num;
struct tree_n *left;
struct tree_n *right;
} tree_node;
/* 树,根结点 */
typedef struct{
tree_node *root;
}tree;
/* 树的末尾一个结点 */
void Tree_Insert(tree *t, int nums){
/* 分配缓存空间 */
tree_node *node_temp = (tree_node *)malloc(sizeof(tree_node));
node_temp->num = nums;
node_temp->left = NULL;
node_temp->right = NULL;
/* 当树为空的时候 */
if(t->root == NULL){
t->root = node_temp;
return ;
}
/* 不为空的时候 */
tree_node *tree_temp = t->root;
while(tree_temp){
/* 比结点小,存放在左子树 */
if(nums < tree_temp->num){
/* 当左字数为空的时候 */
if(tree_temp->left == NULL){
tree_temp->left = node_temp;
return ;
}else{
tree_temp = tree_temp->left;
}
}
/*当数值大于等于结点的时候,存放左字数*/
else{
/* 当右字数为空的时候 */
if(tree_temp->right == NULL){
tree_temp->right = node_temp;
return ;
}else{
tree_temp = tree_temp->right;
}
}
}
}
/* 中序遍历显示二叉树 */
void TreeShow_infix(tree_node* node){
if(node){
TreeShow_infix(node->left);
printf("%d\t", node->num);
TreeShow_infix(node->right);
}
}
/* 先序遍历显示二叉树 */
void TreeShow_pre(tree_node* node){
if(node){
printf("%d\t", node->num);
TreeShow_pre(node->left);
TreeShow_pre(node->right);
}
}
/* 后序遍历显示二叉树 */
void TreeShow_epilogue(tree_node* node){
if(node){
TreeShow_epilogue(node->left);
TreeShow_epilogue(node->right);
printf("%d\t", node->num);
}
}
int main(){
/* 创建一棵树 */
tree tree_temp;
tree_temp.root = NULL;
/* 插入一些结点 */
Tree_Insert(&tree_temp, 5);
Tree_Insert(&tree_temp, 3);
Tree_Insert(&tree_temp, 7);
Tree_Insert(&tree_temp, 2);
Tree_Insert(&tree_temp, 4);
Tree_Insert(&tree_temp, 6);
Tree_Insert(&tree_temp, 8);
/* 显示树的结构 */
printf("中序遍历的树的结构:\n");
TreeShow_infix(tree_temp.root);
printf("\n\n");
printf("先序遍历的树的结构:\n");
TreeShow_pre(tree_temp.root);
printf("\n\n");
printf("后序遍历的树的结构:\n");
TreeShow_epilogue(tree_temp.root);
printf("\n\n");
return 0;
}
树的概念
树属于非线性数据结构结构的一种,树的概念是非常多的,下面一一举例。
没有结点的树称为空(null或empty)树。一棵非空的树包括一个根结点,还(很可能)有多个附加结点,所有结点构成一个多级分层结构
树的定义:n个节点组成的有限集合。n=0,空树;n>0,1个根节点,m个互不相交的有限集,每个子集为根的子树。
基本术语
-
节点的度:树中某个节点的子树(子节点)的个数
-
树的度:树中各节点的度的最大值
-
分支节点:度不为0的节点
-
叶子节点:度为0的节点
-
路径:i->j
-
路径:路径经过的节点数-1
-
孩子节点:节点的后继节点
-
双亲(父母)节点;该节点为其孩子节点的双亲节点
-
兄弟节点:同双亲节点的节点
-
子孙节点:节点的子树的所有节点
-
祖先节点:从树的根节点到该节点路径上的点
-
节点层次:根节点为第一层,以此类推
-
树的高度:树中节点的最大层次
-
有序树:树中节点按照次序从左向右排序
-
森林:互不相交的树的集合
树的性值
-
树的节点树为所有节点的度+1(根节点)
-
度为m的树中第i层最多有m^(i-1)个节点
-
高度为h的m层树至多(m^h-1)/(m-1)个节点
-
具有n个节点的m层树的最小高度为logm( n(m-1) + 1 ) 向上取整
二叉树
二叉树是n个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成
每一个结点中最多拥有一个左结点和一个右结点,并没有多余的结点,这是很明显的二叉树的特征
二叉树特点
-
每个结点最多有两棵树
-
次序不能随意颠倒
-
要区分左结点和右结点
二叉树性质
-
二叉树第i层上的结点数目最多为 2的(i-1)次方个节点
-
深度为k的二叉树至多有2的k次方-1个结点
-
包含n个结点的二叉树的高度至少为log2 (n+1)、
-
在任意一颗二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1
特殊的二叉树
-
斜树:所有结点都只有左结点或右结点,分别称为左斜树、右斜树
-
满二叉树:所有的结点都有左结点和右结点,且所有的叶子都在同一层
-
非叶子结点的度一定为2
-
叶子结点只能出现在最下面
-
同一深度,满二叉树是二叉树类中结点树最多,叶子数最多的
-
-
完全二叉树:对具有n个结点的二叉树按层编号,如果i结点与同样深度的满二叉树的i结点编号完全相同
二叉树结点设计
二叉树其实就一个每个结点都只允许有左右两个孩子的树
一颗完全二叉树,需要设计:
-
结点元素
-
左孩子结点指针
-
右孩子结点指针
-
父结点
//树的结点
typedef struct node{
int data;
struct node* left;
struct node* right;
} Node;
//树根
typedef struct {
Node* root;
} Tree;
二叉树的创建
-
我们创建一个空的结点再进行连接,首先将这个空的结点中的date域赋予数据;
-
再判断tree中是否是一个空树,如果为空,只需要将整个根指向这一个结点即可;
-
如果不为空,再进行判断:
- 输入的数据是否大于或者小于当前比对的结点数据,根据其大小进行相应的排列
//创建树--插入数据
void insert(Tree* tree, int value){
//创建一个节点,让左右指针全部指向空,数据为value
Node* node=(Node*)malloc(sizeof(Node));
node->data = value;
node->left = NULL;
node->right = NULL;
//判断树是不是空树,如果是,直接让树根指向这一个结点即可
if (tree->root == NULL){
tree->root = node;
} else {//不是空树
Node* temp = tree->root;//从树根开始
while (temp != NULL){
if (value < temp->data){ //小于就进左儿子
if (temp->left == NULL){
temp->left = node;
return;
} else {//继续往下搜寻
temp = temp->left;
}
} else { //否则进右儿子
if (temp->right == NULL){
temp->right = node;
return;
}
else {//继续往下搜寻
temp = temp->right;
}
}
}
}
return;
}
遍历,显示树
遍历分为三种方式:中序遍历、先序遍历、后序遍历,这个前后顺序指的是结点相比其左右子结点排序中的顺序
先序遍历:根左右
中序遍历:左根右
后序遍历:左右根用C实现三种遍历的代码虽然只有几行,但是一定要搞清楚其中函数回调的意义!!!
先序遍历二叉树
//树的先序遍历 Preorder traversal
void preorder(Node* node){
if (node != NULL)
{
printf("%d ",node->data);
inorder(node->left);
inorder(node->right);
}
}
中序遍历二叉树
//树的中序遍历 In-order traversal
void inorder(Node* node){
if (node != NULL)
{
inorder(node->left);
printf("%d ",node->data);
inorder(node->right);
}
}
后序遍历二叉树
//树的后序遍历 Post-order traversal
void postorder(Node* node){
if (node != NULL)
{
inorder(node->left);
inorder(node->right);
printf("%d ",node->data);
}
}
二叉树森林互相转换
树转换成二叉树
分为3步:
-
加线:在兄弟(即同一层之间的孩子)之间加一连线
-
抹线:对每个结点,除了其第一个孩子外,除去其与其余孩子之间的连线
-
旋转:以树的根结点为轴心,将整树顺时针转45°
旋转之后,结点的左子树还是左子树,最近的兄弟结点变为右子树
注意:树转换成二叉树其右子树一定为空
二叉树转换成树
同样分为3步:
-
加线:若p结点是双亲结点的左孩子,则将p的右孩子,右孩子的右孩子,……沿分支找到的所有右孩子,都与p的双亲用线连起来
-
抹线:抹掉原二叉树中双亲与右孩子之间的连线
-
调整:将结点按层次排列,形成树结构
森林转换成二叉树
-
将各棵树分别转换成二叉树
-
将每棵树的根结点用线相连,以第一棵树根结点为二叉树的根
-
再以根结点为轴心,顺时针旋转,构成二叉树型结构
二叉树转换成森林
-
抹线:将二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间连线全部抹掉,使之变成孤立的二叉树
-
还原:将孤立的二叉树还原成树(二叉树→树)
相关文章
排序算法(C )
描述 介绍了常用的几种排序算法:**冒泡排序、选择排序、插入排序、快排、希尔排序**、归并排序、堆排 为什么后面两个没有加租?因为目前的我还没发熟练使用 后期如果有时间会出分析讲解视频 **加油!愿祖国强盛**😊😊😊 冒泡排序 冒泡排序原理 从第一个元素开始比较相邻的元素,如果顺序错误则调换顺序,继续往下一一对比,直到序列末尾。 冒泡排序分析 冒泡排序的核心就是:**...
【数据结构】——循环链表
速通回忆 **如果你之前学过链表**,可以直接看我下面的这个项目,实现了下面专题中所有内容; **如果你是个新手**,**_建议先不要看下面这个项目_**,先好好看一下下面每一个部分的代码思路,并尝试自己去写一下 ``` /* * 功能:单向循环链表操作 * 作者:此乃刘同学(www.liustu.com.cn) */ #include "stdio.h" #include...
【数据结构】——栈
速通回忆 **下面是一个链表栈的演示**,**数组栈的演示放在最后面** 如果你不知道什么是链表栈,建议先别看这个“速通回忆”,先看一下理论部分 **如果你之前学过链表**,可以直接看我下面的这个项目,实现了下面专题中所有内容; **如果你是个新手**,**_建议先不要看下面这个项目_**,先好好看一下下面每一个部分的代码思路,并尝试自己去写一下 ``` /* * 功能:链表栈操作...