学习笔记之 树和二叉树的学习

一、树的介绍

​ 树是一种非线性的数据结构,是以分支关系定义的层次结构,比如人类社会中的族谱、及各种机制、组织的关系都可以用树形象的表示。重点学习二叉树的存储和相关操作,还要讨论树、森林、二叉树的转换关系。

二、树的定义和基本术语

**树:**是n个结点的有限集,当0==n时称为空树,我们不讨论空树。

**根结点:**树的最顶层的结点,一棵树有且仅有一个。

**子树:**一棵树除根结点外,剩余的是若干个互不相交的有限集,每一个集合本身又是棵树,称称为根的子树。

**结点的度:**树的结点包含一个数据元素及若干个指向其子树的分支,结点拥有的子树称为结点的度。

**叶子结点:**结构的度为0,被称为叶子结点或终端结点。

**分支结点:**结构的度不为0,被称为分支结点或非终端结点,也被称为内部结点。

**树的度:**是指树内各结点度的最大值。

**密度:**指的是一棵树中,所有结点的总数。

**孩子、双亲、兄弟、祖先、子孙:**结点的子树称为该结点的孩子,而该结点是孩子结点的双亲,拥有共同双亲的结点互为兄弟,从双亲结点往上,直到根结点都称为孩子结点的祖先结点,以某结点为根的子树中的任一结点都被称为该结点的子孙。

**层数、深度、高度:**从根结点开始定义,根为第一层、根的孩子为第二层依次类推,树中结点的最大层数被称为树的深度或高度,双亲在同一层的结点互为堂兄弟。

**有序树和无序树:**将树中结点的各子树看成从左到右是有序次,即不能交换(顺序有意义,表达一些含义),则称该树为有序树,否则称为无序树。

**森林:**若干个棵互不相交的树的集合称为森林,对树中每个结点而言,其子树集合就是森林。

就逻辑结构而言,任何一棵树都是一个二元组 Tree = (root,F),其中root是数据元素,称做树的根结点,F是若干棵子树构成的森林。

三、二叉树的定义和性质

二叉树:

​ 是一种特殊的树型结构,也就是每个结点最多有两棵子树(二叉树中不存在度大于2的结点),并且二叉树的子树有左右之分,顺序不能颠倒。

满二叉树:

​ 若一棵树的层数为k,它总结点数是2^k-1,则这棵树就是满二叉树。

完全二叉树:

​ 若一棵树的层数为k,它前k-1层的总结点数是2^(k-1)-1,第k层的结点按照从左往右的顺序排列,则这棵树就是完全二叉树。

二叉树的性质:

性质1:

​ 在二叉树的第i层上,最多有2^(i-1)个结点。

性质2:

​ 深夜为k的二叉树,最多有2^k-1个节点。

性质3:

​ 对于任何一棵二叉树,如果叶子结点的数量为n0,度为2结点的数量为n2,则n0=n2+1;

性质4:

​ 具有n个结点的完全二叉树的高度为(log2n)+1。

性质5:

​ 有一个n个结点的完全二叉树,结点按照从上到下从左到右的顺序排序为1~n。

​ 1、i > 1时,i/2就是它的双亲结点。

​ 2、i*2是i的左子树,当i*2>n时,则i没有左子树。

​ 3、2*i+1是i的右子树,2*i+1>n时,则i没有右子树。

三、二叉树的遍历

前序遍历:

​ 1、判断二叉树是否为空,若二叉树为空,则不操作。

​ 2、访问根结点

​ 3、前序遍历左子树

​ 4、前序遍历右子树

中序遍历:

​ 1、判断二叉树是否为空,若二叉树为空,则不操作。

​ 2、中序遍历左子树

​ 3、访问根结点

​ 4、中序遍历右子树

后序遍历:

​ 1、判断二叉树是否为空,若二叉树为空,则不操作。

​ 2、后序遍历左子树

​ 3、后序遍历右子树

​ 4、访问根结点

层序遍历:

​ 按照从上到下、从左到右的顺序遍历二叉树,需要与队列结构配合,普通的顺序队列即可,不需要链式队列或循环队列。

四、二叉树的顺序表示与实现

​ 前提:由于顺序存储需要根据元素的相对位置确定关系,所有先把二叉树补成完全二叉树,之前空的点可以使用特殊的值表示,并把完全二叉树的层序遍历结果存储到数组中,只有补成了完全二叉树,才能根据性质5的公式对二叉树进行相关操作。

​ 注意:性质5的公式是按照结点的序号设计的,在使用时要注意数组下标与序号的转换。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>

#define PARENT_TREE(i) 	((i + 1) / 2 - 1)
#define LEFT_TREE(i) 	((i + 1) * 2 - 1)
#define RIGHT_TREE(i) 	((i + 1) * 2)

typedef struct TreeArray
{
    
    
	char *arr;
	size_t cnt;
} TreeArray;

// 创建树
TreeArray *create_tree(const char *str)
{
    
    
	TreeArray *tree = malloc(sizeof(TreeArray));
	tree->cnt = strlen(str);
	tree->arr = malloc(tree->cnt);
	strncpy(tree->arr, str, tree->cnt);
	return tree;
}

// 初始化树
void init_tree(TreeArray *tree, const char *str)
{
    
    
	free(tree->arr);
	tree->cnt = strlen(str);
	tree->arr = malloc(tree->cnt);
	strncpy(tree->arr, str, tree->cnt);
}

// 销毁树
void destroy_tree(TreeArray *tree)
{
    
    
	free(tree->arr);
	free(tree);
}

// 清空树
void clear_tree(TreeArray *tree)
{
    
    
	free(tree->arr);
	tree->cnt = 0;
}

// 判断是否是空树
bool empty_tree(TreeArray *tree)
{
    
    
	return 0 == tree->cnt || '#' == tree->arr[0];
}

// 计算树的深度
size_t hight_tree(TreeArray *tree)
{
    
    
	size_t hight = 1;
	while (pow(2, hight) < tree->cnt)
		hight++;
	return hight;
}

// 访问根结点
char root_tree(TreeArray *tree)
{
    
    
	if (empty_tree(tree))
		return '#';

	return tree->arr[0];
}

// 访问指定的结点
char value_tree(TreeArray *tree, size_t index)
{
    
    
	if (index >= tree->cnt)
		return '#';

	return tree->arr[index];
}

// 给指定的位置赋值
bool assign_tree(TreeArray *tree, size_t index, char value)
{
    
    
	if (index >= tree->cnt)
		return false;

	tree->arr[index] = value;
	return true;
}

// 访问双亲结点
char parent_tree(TreeArray *tree, size_t index)
{
    
    
	if (0 == index || PARENT_TREE(index) >= tree->cnt)
		return '#';

	return tree->arr[PARENT_TREE(index)];
}

// 访问左子树结点
char left_child_tree(TreeArray *tree, size_t index)
{
    
    
	if (LEFT_TREE(index) >= tree->cnt)
		return '#';

	return tree->arr[LEFT_TREE(index)];
}

// 访问右子树结点
char right_child_tree(TreeArray *tree, size_t index)
{
    
    
	if (RIGHT_TREE(index) >= tree->cnt)
		return '#';
	return tree->arr[RIGHT_TREE(index)];
}

// 访问左兄弟结点
char left_sigling_tree(TreeArray *tree, size_t index)
{
    
    
	int left = LEFT_TREE(PARENT_TREE(index));
	if (0 == index || left >= tree->cnt || left == index)
		return '#';

	return tree->arr[left];
}

// 访问右兄弟结点
char right_sigling_tree(TreeArray *tree, size_t index)
{
    
    
	int right = RIGHT_TREE(PARENT_TREE(index));
	if (0 == index || right >= tree->cnt || right == index)
		return '#';

	return tree->arr[right];
}

// 插入子树 lr(left true,right false)
bool insert_tree(TreeArray *tree, size_t index, bool lr, char value)
{
    
    
	size_t pos = lr ? LEFT_TREE(index) : RIGHT_TREE(index);
	if (pos >= tree->cnt || '#' != tree->arr[pos])
		return false;

	tree->arr[pos] = value;
	return true;
}

bool delete_tree(TreeArray *tree, size_t index, bool lr)
{
    
    
	// 计算出要删除的子树的下标
	size_t pos = lr ? LEFT_TREE(index) : RIGHT_TREE(index);
	// 判断要删除的子树下标是否合法
	if (pos >= tree->cnt)
		return false;

	// 计算出要删除结点的左右子树下标
	size_t pos_left = LEFT_TREE(pos), pos_right = RIGHT_TREE(pos);
	// 判断删除的结点是否有左子树,如果有则删除失败
	if (pos_left < tree->cnt && '#' != tree->arr[pos_left])
		return false;
	// 判断删除的结点是否有右子树,如果有则删除失败
	if (pos_right < tree->cnt && '#' != tree->arr[pos_right])
		return false;

	tree->arr[pos] = '#';
	return true;
}

// 前序遍历二叉树
void _pre_order_tree(TreeArray *tree, int index)
{
    
    
	// 根
	if (index >= tree->cnt || '#' == tree->arr[index])
		return;
	printf("%c ", tree->arr[index]);
	// 左
	_pre_order_tree(tree, LEFT_TREE(index));
	// 右
	_pre_order_tree(tree, RIGHT_TREE(index));
}

// 前序遍历
void pre_order_tree(TreeArray *tree)
{
    
    
	_pre_order_tree(tree, 0);
	printf("\n");
}

void _in_order_tree(TreeArray *tree, int index)
{
    
    
	if (index >= tree->cnt || '#' == tree->arr[index])
		return;
	// 左
	_in_order_tree(tree, LEFT_TREE(index));
	// 根
	printf("%c ", tree->arr[index]);
	// 右
	_in_order_tree(tree, RIGHT_TREE(index));
}

// 中序遍历
void in_order_tree(TreeArray *tree)
{
    
    
	_in_order_tree(tree, 0);
	printf("\n");
}

void _post_order_tree(TreeArray *tree, int index)
{
    
    
	if (index >= tree->cnt || '#' == tree->arr[index])
		return;
	// 左
	_post_order_tree(tree, LEFT_TREE(index));
	// 右
	_post_order_tree(tree, RIGHT_TREE(index));
	// 根
	printf("%c ", tree->arr[index]);
}

// 后序遍历
void post_order_tree(TreeArray *tree)
{
    
    
	_post_order_tree(tree, 0);
	printf("\n");
}

// 层序遍历
void level_order_tree(TreeArray *tree)
{
    
    
	for (int i = 0; i < tree->cnt; i++)
	{
    
    
		if ('#' != tree->arr[i])
			printf("%c ", tree->arr[i]);
	}
	printf("\n");
}

int main(int argc, const char *argv[])
{
    
    
	TreeArray *tree = create_tree("FCEADHG##B###M");
	level_order_tree(tree);
	printf("---------------------\n");
	printf("%d\n", hight_tree(tree));
	printf("%c\n", right_sigling_tree(tree, 4));
	insert_tree(tree, 0, true, 'X');
	printf("%d\n", delete_tree(tree, 1, false));
	return 0;
}

五、二叉树的链式表示与实现

有两种创建链式二叉树的方式:

**方式一:**需要给每个度不为2的结点补充一些空白子结点,使用树中除了空白结点其它结点的度全为2,然后以前序的方式遍历二叉树,然后以遍历的结果创建二叉树。

**方式二:**不需要对二叉做任何改变,以前序+中序或中序+后序的遍历结果创建二叉树。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct TreeNode
{
    
    
	char data;
	struct TreeNode *left;
	struct TreeNode *right;
} TreeNode;

TreeNode *create_node(char data)
{
    
    
	TreeNode *node = malloc(sizeof(TreeNode));
	node->data = data;
	node->left = NULL;
	node->right = NULL;
	return node;
}

// 方式1
TreeNode *create_tree(const char **str)
{
    
    
	if ('#' == **str)
		return NULL;
	TreeNode *root = create_node(**str);
	*str += 1;
	root->left = create_tree(str);
	*str += 1;
	root->right = create_tree(str);
	return root;
}

// 方式二
TreeNode *pre_in_create_tree(char *pre, char *in, int len)
{
    
    
	if (len <= 0)
		return NULL;

	TreeNode *root = create_node(*pre);

	int pos = 0;
	while (*pre != in[pos])
		pos++;

	root->left = pre_in_create_tree(pre + 1, in, pos);
	root->right = pre_in_create_tree(pre + 1 + pos, in + 1 + pos, len - 1 - pos);
	return root;
}

// 方式二
TreeNode *post_in_create_tree(char *post, char *in, int len)
{
    
    
	if (len <= 0)
		return NULL;

	TreeNode *root = create_node(post[len - 1]);

	int pos = 0;
	while (post[len - 1] != in[pos])
		pos++;

	root->left = post_in_create_tree(post, in, pos);
	root->right = post_in_create_tree(post + pos, in + pos + 1, len - 1 - pos);
}

size_t height_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return 0;

	size_t lh = height_tree(root->left);
	size_t rh = height_tree(root->right);

	return lh > rh ? lh + 1 : rh + 1;
}

size_t density_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return 0;

	return 1 + density_tree(root->left) + density_tree(root->right);
}

void pre_order_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;
	printf("%c ", root->data);
	pre_order_tree(root->left);
	pre_order_tree(root->right);
}

void in_order_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	in_order_tree(root->left);
	printf("%c ", root->data);
	in_order_tree(root->right);
}

void post_order_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	post_order_tree(root->left);
	post_order_tree(root->right);
	printf("%c ", root->data);
}

void level_tree(TreeNode *root)
{
    
    
	size_t density = density_tree(root), front = 0, rear = 0;
	TreeNode *queue[density];
	queue[rear++] = root;

	while (front != rear)
	{
    
    
		TreeNode *node = queue[front++];
		printf("%c ", node->data);
		if (NULL != node->left)
			queue[rear++] = node->left;
		if (NULL != node->right)
			queue[rear++] = node->right;
	}
}

int main(int argc, const char *argv[])
{
    
    
	const char *pre_str = "FCA##DB###EH##GM###";
	TreeNode *pre_root = create_tree(&pre_str);
	pre_order_tree(pre_root);
	printf("\n");

	/*
	char post[] = "ADCHGEF";
	char in[] = "ACDFHEG";
	TreeNode* root = post_in_create_tree(post,in,7);
	pre_order_tree(root);
	printf("%d\n",height_tree(root));
	printf("%d\n",density_tree(root));
	*/
	level_tree(pre_root);

	return 0;
}

六、二叉搜索树的表示与实现

二叉搜索树介绍:

​ 二叉搜索树又叫作有序二叉树、二叉查找树,具有以下特点:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。

​ 二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势(O(log2n);所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct TreeNode
{
    
    
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	size_t height;	// 结点的高度
	size_t density; // 结点的密度
} TreeNode;

// 创建结点
TreeNode *create_node(int val)
{
    
    
	TreeNode *root = malloc(sizeof(TreeNode));
	root->val = val;
	root->left = NULL;
	root->right = NULL;
	root->height = 1;
	root->density = 1;
	return root;
}

// 自动调整树的高度和密度
void auto_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	int lh = 0, rh = 0, ld = 0, rd = 0;
	if (NULL != root->left)
	{
    
    
		// 当左子树不为空时,调整左子树的高度和密度
		auto_tree(root->left);
		// 重新获取左子树的高度和密度
		lh = root->left->height;
		ld = root->left->density;
	}

	if (NULL != root->right)
	{
    
    

		// 当右子树不为空时,调整右子树的高度和密度
		auto_tree(root->right);
		// 重新获取右子树的高度和密度
		rh = root->right->height;
		rd = root->right->density;
	}

	// 更新当前结点的高度和密度
	root->height = lh > rh ? lh + 1 : rh + 1;
	root->density = ld + rd + 1;
}

void _add_tree(TreeNode **root, TreeNode *node)
{
    
    
	if (NULL == *root)
	{
    
    
		*root = node;
		return;
	}

	if ((*root)->val > node->val)
		_add_tree(&(*root)->left, node);
	else
		_add_tree(&(*root)->right, node);
}

void add_tree(TreeNode **root, int val)
{
    
    
	// root是main函数中root指针的地址
	_add_tree(root, create_node(val));
	auto_tree(*root);
}

// 之所这样设计是为了方便删除并兼顾查询,查询到的是指向值为val结点的指针的地址
TreeNode **_query_tree(TreeNode **root, int val)
{
    
    
	if (NULL == *root)
		return root;

	if (val == (*root)->val)
		return root;
	if (val <= (*root)->val)
		return _query_tree(&(*root)->left, val);
	else
		return _query_tree(&(*root)->right, val);
}

bool query_tree(TreeNode *root, int val)
{
    
    
	TreeNode **node = _query_tree(&root, val);
	return NULL != *node;
}

void _del_tree(TreeNode **root)
{
    
    
	TreeNode *temp = *root;
	if (NULL == temp->left)
		*root = temp->right;
	else if (NULL == temp->right)
		*root = temp->left;
	else
	{
    
    
		*root = temp->left;
		_add_tree(root, temp->right);
	}
	free(temp);
}

bool del_tree(TreeNode **root, int val)
{
    
    
	TreeNode **node = _query_tree(root, val);
	if (NULL == *node)
		return false;

	_del_tree(node);
	auto_tree(*root);
	return true;
}

bool modify_tree(TreeNode **root, int old, int val)
{
    
    
	TreeNode **node = _query_tree(root, old);
	if (NULL == *node)
		return false;

	_del_tree(node);
	_add_tree(root, create_node(val));
	auto_tree(*root);
	return true;
}

void _in_order_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	_in_order_tree(root->left);
	printf("%d ", root->val);
	_in_order_tree(root->right);
}

void in_order_tree(TreeNode *root)
{
    
    
	_in_order_tree(root);
	printf("\n");
}

void level_order_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	TreeNode *queue[root->density];
	int front = 0, rear = 0;
	queue[rear++] = root;

	while (front != rear)
	{
    
    
		int cnt = rear - front;
		while (cnt--)
		{
    
    
			TreeNode *node = queue[front++];
			printf("[v:%d h:%d d:%d] ", node->val, node->height, node->density);
			if (NULL != node->left)
				queue[rear++] = node->left;
			if (NULL != node->right)
				queue[rear++] = node->right;
		}
		printf("\n");
	}
}

// 访问第k个小的数,按大小值的顺序访问
void _assign_tree(TreeNode *root, int k, int *pos, int *ptr)
{
    
    
	if (NULL == root)
		return;

	_assign_tree(root->left, k, pos, ptr);
	if (++*pos == k)
		*ptr = root->val;
	_assign_tree(root->right, k, pos, ptr);
}

int assign_tree(TreeNode *root, int k)
{
    
    
	if (k < 1)
		return -1;

	int pos = 0, val = -1;
	_assign_tree(root, k, &pos, &val);
	return val;
}

int main(int argc, const char *argv[])
{
    
    
	TreeNode *root = NULL;
	for (int i = 0; i < 10; i++)
	{
    
    
		add_tree(&root, rand() % 100);
	}
	in_order_tree(root);
	modify_tree(&root, 77, 99);
	in_order_tree(root);
	level_order_tree(root);

	return 0;
}

二叉搜索树的缺点:

​ 二叉搜索树的元素添加顺序会影响二叉搜索树的形状,二叉搜索树的形状会影响它的操作效率,在极端情况下,二叉搜索树可能会呈单枝状分布,使用速度接近单向链表,这种极端情况出现在的原因就添加的元素基本有序。

七、平衡二叉树

平衡二叉树介绍:

​ 平衡二叉树的全称叫平衡二叉搜索树,它首是一棵二叉搜索树,且具有以下性质:它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

​ 对于一般的二叉搜索树,它的理想高度是为log2n,其各操作的时间复杂度(O(log2n))。但是,在某些极端的情况下(如:在插入的序列是有序的时),二叉搜索树将退化成近似单向链表,此时它的操作时间复杂度将退化成线性的,即O(n)。

​ 我们可以通过随机化建立二叉搜索树来尽量的避免这种情况,但是在进行了多次的操作之后,由于在删除时,我们总是选择将待删除节点的后继代替它本身,这样就会造成总是右边的节点数目减少,以至于树向左偏沉。这同时也会造成树的平衡性受到破坏,提高它的操作的时间复杂度,而平衡二叉搜索树就可以弥补这个缺点。

如何把不平衡的二叉树调整为平衡二叉树:

​ 我在检查二叉树是否平衡时,肯定是从叶子结点往根结点遍历,因此我们遇到的不平衡的二叉树有以下四种情况,分别是:

//1 解决方法:以B轴向右旋转
      A						   B
     / \                     /   \
    B   t1                  C     A
   / \                     / \   /  \
  C   t2                  t4 t3 t2  t1
 / \
t4   t3


//2 解决方法:先以C轴向左旋转,再以C为轴向右旋转
    A                A                 C
   / \              / \              /   \
  B   t1           C   t1          B      A  
 / \              / \             /  \   /  \
t2  C            B   t3          t2  t4 t3   t1
   / \          / \
  t4   t3      t2  t4
 
//3 解决方法:以B轴向左旋转
  A				 B		
 / \           /   \
t1  B         A     C
   / \       / \   / \
  t2  C     t1 t2 t3  t4
     / \
	t3   t4
	
//4 解决方法:以C轴向右旋转,再以C轴向左旋转
  A           A              C
 / \         / \           /   \
t1  B       t1  C         A     B
   / \         / \       / \   / \
  C   t4      t2  B     t1 t2 t3  t4
 / \              / \
t2   t3          T3  T4
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define TreeHight(node) (NULL == (node) ? 0 : (node)->height)

typedef struct TreeNode
{
    
    
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	size_t height;
} TreeNode;

// 创建结点
TreeNode *create_node(int val)
{
    
    
	TreeNode *root = malloc(sizeof(TreeNode));
	root->val = val;
	root->left = NULL;
	root->right = NULL;
	root->height = 1;
	return root;
}

// 调整树的高度
void auto_height_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	auto_height_tree(root->left);
	auto_height_tree(root->right);
	int lh = TreeHight(root->left);
	int rh = TreeHight(root->right);
	root->height = lh > rh ? lh + 1 : rh + 1;
}

void right_rotate_tree(TreeNode **rpp)
{
    
    
	TreeNode *A = *rpp;
	TreeNode *B = A->left;
	TreeNode *t = B->right;

	*rpp = B;
	B->right = A;
	A->left = t;
    auto_height_tree(*rpp);
}

void left_rotate_tree(TreeNode **rpp)
{
    
    
	TreeNode *A = *rpp;
	TreeNode *B = A->right;
	TreeNode *t = B->left;

	*rpp = B;
	B->left = A;
	A->right = t;
    auto_height_tree(*rpp);
}

void auto_balance_tree(TreeNode **rpp)
{
    
    
	if (NULL == *rpp)
		return;

	auto_balance_tree(&(*rpp)->left);
	auto_balance_tree(&(*rpp)->right);

	int lh = TreeHight((*rpp)->left);
	int rh = TreeHight((*rpp)->right);

	if (lh - rh > 1)
	{
    
    
		if (TreeHight((*rpp)->left->left) >= TreeHight((*rpp)->left->right))
			right_rotate_tree(rpp);
		else
		{
    
    
			left_rotate_tree(&(*rpp)->left);
			right_rotate_tree(rpp);
		}
		auto_balance_tree(rpp);
	}
	else if (lh - rh < -1)
	{
    
    
		if (TreeHight((*rpp)->right->right) >= TreeHight((*rpp)->right->left))
			left_rotate_tree(rpp);
		else
		{
    
    
			right_rotate_tree(&(*rpp)->right);
			left_rotate_tree(rpp);
		}
		auto_balance_tree(rpp);
	}
}

bool is_balance_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return true;

	bool flag1 = is_balance_tree(root->left);
	bool flag2 = is_balance_tree(root->right);

	return flag1 && flag2 && 1 >= abs(TreeHight(root->left) - TreeHight(root->right));
}

void _in_order_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	_in_order_tree(root->left);
	printf("%d ", root->val);
	_in_order_tree(root->right);
}

void in_order_tree(TreeNode *root)
{
    
    
	_in_order_tree(root);
	printf("\n");
}

void level_order_tree(TreeNode *root)
{
    
    
	if (NULL == root)
		return;

	TreeNode *queue[100];
	int front = 0, rear = 0;
	queue[rear++] = root;

	while (front != rear)
	{
    
    
		int cnt = rear - front;
		while (cnt--)
		{
    
    
			TreeNode *node = queue[front++];
			printf("[v:%d h:%d] ", node->val, node->height);
			if (NULL != node->left)
				queue[rear++] = node->left;
			if (NULL != node->right)
				queue[rear++] = node->right;
		}
		printf("\n");
	}
}

// 添加结点
void _add_tree(TreeNode **rpp, TreeNode *node)
{
    
    
	if (NULL == *rpp)
	{
    
    
		*rpp = node;
		return;
	}

	if (node->val < (*rpp)->val)
		_add_tree(&(*rpp)->left, node);
	else
		_add_tree(&(*rpp)->right, node);
}

// 添加元素
void add_tree(TreeNode **rpp, int val)
{
    
    
	// 创建结点并添加
	_add_tree(rpp, create_node(val));
	// 调整树的高度
	auto_height_tree(*rpp);
	// 让树自动平衡
	auto_balance_tree(rpp);
}

// 初始化二权树
TreeNode *init_tree(int *arr, int size)
{
    
    
	TreeNode *root = NULL;
	// 循环把所有的元素创建结点并添加到树中
	for (int i = 0; i < size; i++)
	{
    
    
		_add_tree(&root, create_node(arr[i]));
	}

	// 调整树的高度
	auto_height_tree(root);
	// 让树自动平衡
	auto_balance_tree(&root);
	return root;
}

int main(int argc, const char *argv[])
{
    
    
	int arr[10] = {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	TreeNode *root = NULL;
	for (int i = 0; i < 10; i++)
	{
    
    
		add_tree(&root, arr[i]);
	}
	printf("%d\n", is_balance_tree(root));
	return 0;
}

平衡二叉树的优点:

​ 避免二叉搜索树的单支状分布的情况,能让二叉搜索树以最佳的状态进行操作,时间复杂接近O(log2n)。

平衡二叉树的缺点:

​ 平衡二叉树在创建、添加、删除时,为了让二叉树保持平衡需要进行大量的左旋、右旋、高度计算,所以平衡二叉树在创建时,添加、删除结点时速度比较慢。

​ 因此平衡二叉树适合使用在数据量大且数据量稳定的情况,没有大量的添加、删除动作,大多数情况下都是进行查询操作。

红黑树与AVL树的区别:

​ 1、AVL树在物理上就是平衡的,所以在创建、添加、删除时速度比较慢,但它的查询速度接近平衡二叉树的极限。

​ 2、红黑树是一种特殊的AVL树,它的物理结构不是严格的平衡,而是接近平衡,从根结点所有的叶子结点的速度大致相同,它的非绝对平衡使用节约很多左旋、右旋的次数,因此它创建、添加、删除时速度比AVL树要快,查询速度接近AVL树。

线索二叉树

赫夫曼树

赫夫曼编码

文件压缩工具

auto_balance_tree(rpp);
}

// 初始化二权树
TreeNode *init_tree(int *arr, int size)
{
TreeNode *root = NULL;
// 循环把所有的元素创建结点并添加到树中
for (int i = 0; i < size; i++)
{
_add_tree(&root, create_node(arr[i]));
}

// 调整树的高度
auto_height_tree(root);
// 让树自动平衡
auto_balance_tree(&root);
return root;

}

int main(int argc, const char *argv[])
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
TreeNode *root = NULL;
for (int i = 0; i < 10; i++)
{
add_tree(&root, arr[i]);
}
printf(“%d\n”, is_balance_tree(root));
return 0;
}


#### 平衡二叉树的优点:

​	避免二叉搜索树的单支状分布的情况,能让二叉搜索树以最佳的状态进行操作,时间复杂接近O(log2n)。

#### 平衡二叉树的缺点:

​	平衡二叉树在创建、添加、删除时,为了让二叉树保持平衡需要进行大量的左旋、右旋、高度计算,所以平衡二叉树在创建时,添加、删除结点时速度比较慢。

​	因此平衡二叉树适合使用在数据量大且数据量稳定的情况,没有大量的添加、删除动作,大多数情况下都是进行查询操作。

#### 红黑树与AVL树的区别:

​	1、AVL树在物理上就是平衡的,所以在创建、添加、删除时速度比较慢,但它的查询速度接近平衡二叉树的极限。

​	2、红黑树是一种特殊的AVL树,它的物理结构不是严格的平衡,而是接近平衡,从根结点所有的叶子结点的速度大致相同,它的非绝对平衡使用节约很多左旋、右旋的次数,因此它创建、添加、删除时速度比AVL树要快,查询速度接近AVL树。











​	

​	

​	

猜你喜欢

转载自blog.csdn.net/m0_62480610/article/details/126319174