1、线索二叉树
规律:在有n个节点的链式二叉树中必定存在n+1个指针域
正因为链式二叉树中有很多的空指针,可以让这些指针这向下一个节点,这样在遍历时可以不用递归,二使用循环,可以提高遍历速度。
#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_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_node(data));
}
void ldr_show(TreeNode* root)
{
if(NULL == root) return;
ldr_show(root->left);
printf("%d ",root->data);
ldr_show(root->right);
}
// 表示上一个节点
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++)
{
int data = rand()%100;
printf("%d ",data);
insert_tree(&root,data);
}
printf("\n");
ldr_show(root);
printf("\n");
create_clue(root);
clue_show(root);
}
2、平衡二叉树
平衡二叉树:
前提是有序的二叉树,它的左右子树的高度差不超过1,它的所有子树也要满足这个要求。
如果一棵有序二叉树呈现单支状(接近单支),它的效率接近链表,因此只有达到平衡时它的效率才高。
由于节点的位置受值的影响,因此只能进行调整,而不能强行修改。
二叉树不平衡的基础原因:
x y
/ \ / \
y t1 以y为轴向右旋转 z x
/ \ / \ / \
z t2 t3 t4 t2 t1
/ \
t3 t4
x y
/ \ / \
t1 y 以y为轴向左旋转 x z
/ \ / \ / \
t2 z t1 t2 t3 t4
/ \
t3 t4
x x z
/ \ / \ / \
y t1 z t1 y x
/ \ / \ / \ / \
t2 z y t4 t2 t3 t4 t1
/ \ / \
t3 t4 t2 t3
以z为轴向左旋转 以z为轴向右旋转 达到平衡
x x z
/ \ / \ / \
t1 y t1 z x y
/ \ / \ / \ / \
z t2 t3 y t1 t3 t4 t2
/ \ / \
t3 t4 t4 t2
以z为轴向右旋转 以z为轴向左旋转
注:简单理解位置调整就是将二叉树中节点的大小进行整理排序,整理好的二叉树中的数据顺序没有变,但是更加的便于操作
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 平衡二叉树
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
TreeNode* create_node(int data)
{
TreeNode* node = malloc(sizeof(TreeNode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
// 高度
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;
}
// 检查左右子树是否平衡(平衡因子)是否高度差大于1
int is_balance(TreeNode* root)
{
return high_tree(root->left) - high_tree(root->right);
}
// 左旋转
TreeNode* left_rotate(TreeNode* x)
{
TreeNode* y = x->right;
TreeNode* t2 = y->left;
y->left = x;
x->right = t2;
return y;
}
// 右旋转
TreeNode* right_rotate(TreeNode* x)
{
TreeNode* y = x->left;
TreeNode* t2 = y->right;
y->right = x;
x->left = t2;
return y;
}
// 自动平衡处理函数
TreeNode* auto_balance(TreeNode* x)
{
if(NULL == x) return NULL;
int lh = high_tree(x->left);
int rh = high_tree(x->right);
if(lh - rh > 1)
{
if(is_balance(x->left) >= 0)
{
//y 右旋转
x = right_rotate(x);
}
else
{
//z 左旋转
x->left = left_rotate(x->left);
//z 右旋转
x = right_rotate(x);
}
}
if(rh - lh > 1)
{
if(is_balance(x->right) <= 0)
{
//y 左旋转
x = left_rotate(x);
}
else
{
//z 右旋转
x->right = right_rotate(x->right);
//z 左旋转
x = left_rotate(x);
}
}
return x;
}
// 插入
TreeNode* insert_tree(TreeNode* root,int data)
{
if(NULL == root)
return create_node(data);
if(data < root->data)
root->left = insert_tree(root->left,data);
else
root->right = insert_tree(root->right,data);
// 平衡处理
root = auto_balance(root);
return root;
}
//中序
void ldr_show(TreeNode* root)
{
if(NULL == root) return;
ldr_show(root->left);
printf("%d ",root->data);
ldr_show(root->right);
}
//前序遍历
void dlr_show(TreeNode* root)
{
if(NULL == root) return;
printf("%d ",root->data);
dlr_show(root->left);
dlr_show(root->right);
}
/*
删除节点
1、待删除的节点是叶子节点,直接删除
2、待删除的节点左或右子树为空,则使用非空子节点替换
3、待删除的节点左右子树非空,则根据左右子树的高度,选择最大子节点(左)或者最小子节点(右)替换
*/
TreeNode* min_tree(TreeNode* root)
{
TreeNode* min = root;
while(min->left) min = min->left;
return min;
}
TreeNode* max_tree(TreeNode* root)
{
TreeNode* max = root;
while(max->right) max = max->right;
return max;
}
TreeNode* del_tree(TreeNode* root,int data)
{
if(NULL == root) return NULL;
if(data == root->data)
{
if(NULL == root->left && NULL == root->right)
{
free(root);
return NULL;
}
if(NULL == root->left)
{
TreeNode* temp = root->right;
free(root);
return temp;
}
if(NULL == root->right)
{
TreeNode* temp = root->left;
free(root);
return temp;
}
int lh = high_tree(root->left);
int rh = high_tree(root->right);
if(lh > rh)
{
TreeNode* node = max_tree(root->left);
root->data = node->data;
root->left = del_tree(root->left,root->data);
}
else
{
TreeNode* node = min_tree(root->right);
root->data = node->data;
root->right = del_tree(root->right,root->data);
}
return root;
}
if(data < root->data)
root->left = del_tree(root->left,data);
else
root->right = del_tree(root->right,data);
root = auto_balance(root);
return root;
}
int main(int argc,const char* argv[])
{
TreeNode* root = NULL;
for(int i=0;i<10;i++)
{
root = insert_tree(root,i);
}
root = del_tree(root,0);
root = del_tree(root,2);
ldr_show(root);
printf("\n");
dlr_show(root);
printf("\n%d\n",high_tree(root));
}