要了解二叉树首先要知道什么是树,树是指元素之间存在一对多关系的数据结构,适合存储具有层次关系的数据模型,如:文件树、组织关系、族谱。
树有多种种类:
二叉树:一个结点最多有两个孩子。
普通树:只有一个双亲结点,子结点的数量任意。
B树:多路平衡查找树,
多路:最多有M个子结点
平衡:所有子树的高度相差不超过1
查找:所有结点是有序的
B树和B+树了解即可,普通树一般成二叉树研究。
而一般的应用最多的是二叉树
树的定义:
typedef struct TreeNode
{
char data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
TreeNode* create_tree_node(char data)
{
TreeNode* tree = malloc(sizeof(TreeNode));
tree->data = data;
tree->next1 = NULL;
tree->next2 = NULL;
//可定义两个及以上节点
return tree;
}
从代码可知树可以认为是一种特殊的链表,当树只有一个节点时它就相当于链表。
而二叉树就是只有两个节点(左节点和右节点),代码如下:
typedef struct TreeNode
{
char data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
TreeNode* create_tree_node(char data)
{
TreeNode* tree = malloc(sizeof(TreeNode));
tree->data = data;
tree->left = NULL;
tree->right = NULL;
return tree;
}
二叉树的特殊结构也使得用循环算法来遍历比较麻烦所以一般用递归遍历下面我们来看二叉树是前序,中序,后序的代码实现:
//前序
void dlr_tree(TreeNode* tree)
{
if(NULL == tree)
{
printf("#");
return;
}
printf("%c",tree->data);
dlr_tree(tree->left);
dlr_tree(tree->right);
}
//中序
void ldr_tree(TreeNode* tree)
{
if(NULL == tree)
{
return;
}
ldr_tree(tree->left);
printf("%c",tree->data);
ldr_tree(tree->right);
}
//后序
void lrd_tree(TreeNode* tree)
{
if(NULL == tree)
{
return;
}
lrd_tree(tree->left);
lrd_tree(tree->right);
printf("%c",tree->data);
}
从代码中可知,递归比较方便。
再来看一个代码用于计算二叉树元素的个数:
size_t density_tree(TreeNode* tree)
{
if(NULL == tree)
return 0;
return 1+density_tree(tree->left)+density_tree(tree->right);
}
如果换成循环遍历的话计算完左子节点还要考虑右子节点,左子节点的右节点…其中复杂度可想而知。
而一般的我们把二叉树分成 :
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树,每层的结点数量是:2(n-1),总结点数是:2n-1。
完全二叉树:
除了最后一层外的所有层的结点数是:2^(n-1)。
最后一层的结点按照从左到右的顺序排列。
有序二叉树:
左子结点比双亲结点小,右子结点比双亲结点大,所有结点都遵循该规则。
线索二叉树:
给普通二叉树结点,增加上线索,使用它能够以循环的方式遍历,提高遍历速度。
哈夫曼树:带权重的二叉树。
平衡二叉树:左右子树高度相差不超过1。
红黑树:接近平衡的二叉树,伪平衡二叉树。
堆:
大根堆:双亲结点比左右子结点都大。
小根堆:双亲结点比左右子结点都小。
这些之后再说,