第六周总结04

本文介绍了有序二叉树的概念,包括其性质、插入和查找操作,并提供了C语言实现。接着,讨论了线索二叉树的创建,通过中序遍历建立线索,以及如何进行线索遍历。此外,还提及了选择树作为完全二叉树在查找最大或最小值中的应用。
摘要由CSDN通过智能技术生成

有序二叉树

  • 又称二叉排序树,二叉搜索树,二叉查找树
  • 左子树的数据小于根节点,根节点的数据小于等于右子树,并且左右子树都符合以上定义
  • 注意:由于这种树的中序遍历是从小到大,所以有序二叉树也是一种排序算法,并且有序二叉树中查找某个值,天然是二分查找,所以经常考

  • 注意:由于有序二叉树需要频繁地插入和删除,因此不适合使用顺序存储

#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);
}

选择树

  • 是一种完全二叉树,把要存储的数据存放在最后一层,根节点是左右子树中的其中一个,可以是最大的,或者最小的
  • 选择树的功能是为了快速地找出其中最大值(胜者树)或者最小值(败者树)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值