有序二叉树
- 又称二叉排序树,二叉搜索树,二叉查找树
- 左子树的数据小于根节点,根节点的数据小于等于右子树,并且左右子树都符合以上定义
-
注意:由于这种树的中序遍历是从小到大,所以有序二叉树也是一种排序算法,并且有序二叉树中查找某个值,天然是二分查找,所以经常考
-
注意:由于有序二叉树需要频繁地插入和删除,因此不适合使用顺序存储
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 有序二叉树
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
TreeNode* create_tree_node(int data)
{
TreeNode* node = malloc(sizeof(TreeNode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
void _insert_tree(TreeNode** root,TreeNode* node)
{
if(NULL == *root)
{
*root = node;
return;
}
if(node->data < (*root)->data)
_insert_tree(&(*root)->left,node);
else
_insert_tree(&(*root)->right,node);
}
// 添加
void insert_tree(TreeNode** root,int data)
{
_insert_tree(root,create_tree_node(data));
}
void dlr_show(TreeNode* root)
{
if(NULL == root) return;
printf("%d ",root->data);
dlr_show(root->left);
dlr_show(root->right);
}
void ldr_show(TreeNode* root)
{
if(NULL == root) return;
dlr_show(root->left);
printf("%d ",root->data);
dlr_show(root->right);
}
void lrd_show(TreeNode* root)
{
if(NULL == root) return;
dlr_show(root->left);
dlr_show(root->right);
printf("%d ",root->data);
}
// 查找
bool query_tree(TreeNode* root,int data)
{
if(NULL == root) return false;
if(data == root->data) return true;
if(data < root->data)
return query_tree(root->left,data);
return query_tree(root->right,data);
}
// 高度
int high_tree(TreeNode* root)
{
if(NULL == root) return 0;
int lh = high_tree(root->left);
int rh = high_tree(root->right);
return lh>rh?lh+1:rh+1;
}
// 密度
int density_tree(TreeNode* root)
{
if(NULL == root) return 0;
return density_tree(root->left) + denstiy_tree(root->right) + 1;
}
// 销毁
void destroy_tree(TreeNode* root)
{
if(NULL == root) return;
destroy_tree(root->left);
destroy_tree(root->right);
free(root);
}
bool _access_ldr_tree(TreeNode* root,size_t index,int* val,int* k)
{
if(NULL == root) return false;
// 左
if(_access_ldr_tree(root->left,index,val,k)) return true;
// 根
if((*k)++ == index)
{
*val = root->data;
return true;
}
// 右
return _access_ldr_tree(root->right,index,val,k);
}
// 按中序访问
bool access_ldr_tree(TreeNode* root,size_t index,int* val)
{
int k = 0;
// 递归使用同一个k来计数,所以需要共享同一个变量k
return _access_ldr_tree(root,index,val,&k);
}
// 按值删除
bool del_value_tree(TreeNode** root,int data)
{
if(NULL == *root) return false;
// 找到data
if(data == (*root)->data)
{
// 左子树替换 data节点
TreeNode* temp = *root;
*root = temp->left;
// data右子树重新往data的左子树插入
_insert_tree(root,temp->right);
// 删除原节点
free(temp);
// 返回
return true;
}
if(data < (*root)->data)
return del_value_tree(&(*root)->left,data);
return del_value_tree(&(*root)->right,data);
}
// 判断是否平衡
// 左右子树高度差不超过1,并且子树也要满足
bool is_AVL_tree(TreeNode* root)
{
if(NULL == root) return true;
int lh = high_tree(root->left);
int rh = high_tree(root->right);
return abs(lh-rh) <= 1 &&
is_AVL_tree(root->left) && is_AVL_tree(root->right);
}
int main(int argc,const char* argv[])
{
TreeNode* root = NULL;
for(int i=0; i<10; i++)
{
int data = rand()%100;
printf("%d ",data);
insert_tree(&root,data);
}
del_value_tree(&root,83);
printf("\n");
dlr_show(root);
printf("\n");
ldr_show(root);
printf("\n");
printf("query:%d\n",query_tree(root,83));
int val = -1;
access_ldr_tree(root,0,&val);
printf("val:%d\n",val);
printf("AVL:%d\n",is_AVL_tree(root));
}
线索二叉树
- 也是有序二叉树
- 规律:在一棵有n个节点的链式二叉树必定存在n+1个空指针
- 因此链式二叉树中有很多的空指针,可以在有序二叉树中,让这些空指针指向下一个\前一个节点,这样有序遍历树时可以不使用递归而是使用循环进行,以此提高树的遍历效率
- 中序线索二叉树
节点数据项:
- 数据
- 左子树指针
- 右子树指针
- 右子树线索标志位(假:右子树指针指向真的右子树 真:右子树指针指向下一个节点)
实现过程:
- 1、创建一棵有序二叉树
- 2、通过中序遍历创建线索(只需一次)
- 3、根据线索遍历(循环)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 线索二叉树
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
bool rclue; // 为真时,右子树是线索
}TreeNode;
TreeNode* create_tree_node(int data)
{
TreeNode* node = malloc(sizeof(TreeNode));
node->data = data;
node->left = NULL;
node->right = NULL;
node->rclue = false;
return node;
}
void _insert_tree(TreeNode** root,TreeNode* node)
{
if(NULL == *root)
{
*root = node;
return;
}
if(node->data < (*root)->data)
_insert_tree(&(*root)->left,node);
else
_insert_tree(&(*root)->right,node);
}
void insert_tree(TreeNode** root,int data)
{
_insert_tree(root,create_tree_node(data));
}
void ldr_show(TreeNode* root)
{
if(NULL == root) return;
ldr_show(root->left);
printf("%d ",root->data);
ldr_show(root->right);
}
// prev是root的上一个节点
TreeNode* prev = NULL;
// 根据中序遍历,建立线索
void create_clue(TreeNode* root)
{
if(NULL == root) return;
// 左
create_clue(root->left);
// 根
if(NULL != prev && NULL == prev->right)
{
prev->right = root;
prev->rclue = true;
}
prev = root;
// 右
create_clue(root->right);
}
// 按线索遍历
void clue_show(TreeNode* node)
{
while(node)
{
while(node->left) node = node->left;
printf("%d ",node->data);
while(node->rclue)
{
node = node->right;
printf("%d ",node->data);
}
node = node->right;
}
}
int main(int argc,const char* argv[])
{
TreeNode* root = NULL;
for(int i=0; i<10; i++)
{
insert_tree(&root,rand()%100);
}
ldr_show(root);
printf("\n");
create_clue(root);
clue_show(root);
}
选择树
- 是一种完全二叉树,把要存储的数据存放在最后一层,根节点是左右子树中的其中一个,可以是最大的,或者最小的
- 选择树的功能是为了快速地找出其中最大值(胜者树)或者最小值(败者树)