数据结构——树

树型结构:

1、树的基本概念

    一种表示层次关系(一对多)的数据结构
    有且仅有一个特定的节点,该节点没有前趋,被称为根节点
    剩余的n个互不相交的子集,其中的每个子集也都是一棵树,都被称为根节点的子树
    注意:树型结构具有递归性(树中有树)

2、树的表示方法:

    倒悬树、嵌套法、凹凸法

3、树的专业术语

    节点:      组成树的基础元素,同时它也是一棵树
    节点的度:  该节点的子树的数量,与该节点有直接关系的
    树的度(密度):树中节的度的最大值
    树的深度:  树的最大层次树为树的深度
    节点的层次:根节点的层次为1,它的孩子层次为2,孩子的孩子层次为3,以此类推
    叶子节点:  节点的度为0的节点
    双亲和孩子:节点的子树称为它的孩子节点,则该节点为孩子节点的双亲
    兄弟节点:  具有同一个双亲节点的节点 
    祖先:    从根节点出发到该节点,经过的所有节点都被称为该节点的祖先
    子孙:  一个节点的子树中任意的一个节点都被称为它的子孙
    堂兄弟: 双亲不是同一个节点,但是双亲在同一层的节点互为堂兄弟     
    森林:  n个不相交的树的集合称为森林

4、树的存储

在这里插入图片描述

    树可以顺序存储、链式存储,也可以混合存储,由于存储的信息不同,有以下表示方式:
        位置    data  双亲 
         0       A    -1
         1       B     0
         2       C     0
         3       D     1
         4       E     2
         5       F     2
         6       G     3
         7       H     4
         8       I     4
    优点:方便找到双亲
    缺点:查找孩子节点不方便

在这里插入图片描述
list_queue.h

#ifndef LIST_QUEUE_H
#define LIST_QUEUE_H

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

#define TYPE int

//	设计节点
typedef struct Node
{
	TYPE data;
	struct Node* next;
}Node;

//	设计链式队列结构
typedef struct ListQueue
{
	Node* head;	//	指向队头节点的指针
	Node* tail;	//	指向队尾节点的指针
	size_t size;//	节点个数
}ListQueue;

//	创建节点
Node* create_node(TYPE val);

//	创建队列结构
ListQueue* create_list_queue(void);

//	队空
bool empty_list_queue(ListQueue* queue);

//	入队
void push_list_queue(ListQueue* queue,TYPE val);

//	出队
bool pop_list_queue(ListQueue* queue);

//	队头
TYPE head_list_queue(ListQueue* queue);

//	队尾
TYPE tail_list_queue(ListQueue* queue);

//	数量
size_t size_list_queue(ListQueue* queue);

//	销毁
void destory_list_queue(ListQueue* queue);

#endif//LIST_QUEUE_H

list_queue.c

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

//	顺序存储 双亲表示法

//	设计节点
typedef struct TreeNode
{
	char data;	//	数据
	int parent;	//	双亲节点下标
}TreeNode;

//	设计树的顺序结构
typedef struct Tree
{
	TreeNode* arr;	//	存储节点内存的首地址
	size_t cal;		//	容量
	size_t cnt;		//	节点个数
}Tree;

//	创建
Tree* create_tree(size_t cal)
{
	Tree* tree = malloc(sizeof(Tree));
	tree->arr = malloc(sizeof(TreeNode)*cal);//申请出一块连续的存储节点的内存
	tree->cal = cal;
	tree->cnt = 0;
	return tree;
}

//	parent是双亲的data
//  添加子树
bool add_tree(Tree* tree,char data,char parent)
{
	//	树不存在满的情况,可以扩容
	if(tree->cnt >= tree->cal)
	{
		tree->cal *= 2;
		tree->arr = realloc(tree->arr,sizeof(TreeNode)*tree->cal);//扩容tree->arr,sizeof(TreeNode)*tree->cal是扩容后的大小)
	}

	//	默认根节点的双亲是'\0'
	if('\0' == parent)
	{
		tree->arr[0].data = data;
		tree->arr[0].parent = -1;
		tree->cnt = 1;
		return true;
	}

	for(int i=0; i<tree->cnt; i++)
	{
		if(tree->arr[i].data == parent)
		{
			tree->arr[tree->cnt].data = data;
			tree->arr[tree->cnt++].parent = i;
			return true;
		}
	}
	return false;
}

void show_tree(Tree* tree)
{
	for(int i=0; i<tree->cnt; i++)
	{
		printf("index: %d  data: %c parent: %d\n",
			i,tree->arr[i].data,tree->arr[i].parent);
	}
}

//	计算节点的度
int node_count(Tree* tree,char data)
{
	int count = 0,index = -1;
	for(int i=0; i<tree->cnt; i++)
	{
		if(data == tree->arr[i].data)
		{
			index = i;
			break;
		}	
	}
	if(-1 == index) return -1;
	for(int i=0; i<tree->cnt; i++)
	{
		if(index == tree->arr[i].parent)
		{
			count++;	
		}
	}
	return count;
}

//	层序遍历 
void level_show_tree(Tree* tree)
{
	//	创建一个队列
	ListQueue* queue = create_list_queue();//创建queue队列

	//	根节点入队
	push_list_queue(queue,tree->arr[0].data);//入队

	while(!empty_list_queue(queue))//队列为空时结束
	{
		//	出队队头并显示
		char data = head_list_queue(queue);//查看队头,赋给data
		printf("%c ",data);
		pop_list_queue(queue);//出队

		//	找出该节点的子节点并入队
		int index = -1;
		for(int i=0; i<tree->cnt; i++)
		{
			if(data == tree->arr[i].data)
			{
				index = i;
				break;
			}
		}
		for(int i=0; i<tree->cnt; i++)
		{
			if(index == tree->arr[i].parent)
			{
				push_list_queue(queue,tree->arr[i].data);	
			}
		}
	}
	//	销毁队列,queue是自己创的,次数多了的话会造成内存泄露
	destory_list_queue(queue);
}

int main(int argc,const char* argv[])
{
	Tree* tree = create_tree(10);
	add_tree(tree,'A','\0');
	add_tree(tree,'B','A');
	add_tree(tree,'C','A');
	add_tree(tree,'D','B');
	add_tree(tree,'E','C');
	add_tree(tree,'F','C');
	add_tree(tree,'G','D');
	add_tree(tree,'H','E');
	add_tree(tree,'I','E');
	add_tree(tree,'X','B');
	add_tree(tree,'Y','B');
	show_tree(tree);
	printf("count:%d\n",node_count(tree,'C'));
	level_show_tree(tree);
}

孩子表示法:

        顺序:  浪费内存
        位置    data  sub_arr(存储子节点下标的数组)
        0       A    1、2
        1       B    3
        2       C    4、5
        3       D    6
        4       E    7、8
        5       F    
        6       G     
        7       H     
        8       I     
        链式:  节约空间
        位置    data  ListHead
        0       A    1->2->N
        1       B    3-N
        2       C    4->5->N
        3       D    6->N
        4       E    7->8->N
        5       F    
        6       G     
        7       H     
        8       I 
        优点:方便找孩子
        缺点:查找双亲节点麻烦

兄弟表示法:

        双亲只存储第一个子节点,然后链式地指向所有的兄弟节点
        数据域:
            第一个子节点,数据,兄弟节点指针
        优点:可以方便地查询到所有的兄弟节点
        缺点:查找双亲麻烦
    
    总结:普通树不常用,一般需要转换为二叉树使用

二叉树:

二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树
定义:节点的度最多为2

特殊的二叉树:

    每层的节点数都是2^(i-1),这种树叫做满二叉树
    深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树

二叉树的性质:

    性质1:二叉树的第i层上最多有2^(i-1)个节点
    性质2:深度为h的二叉树中至多含有2^h-1个节点
    性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有      n0=n2+1
    性质4:具有n个节点的完全二叉树深为log(2)x+1(其中x表示不大于n的最大整数) 
    性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点: 
    当i=1时,该节点为根,它无双亲节点 
    当i>1时,该节点的双亲节点的编号为i/2 
    若2i≤n,则有编号为2i的左子节点,否则没有左子节点
    若2i+1≤n,则有编号为2i+1的右子节点,否则没有右子节点

二叉树的操作:

    构建、销毁、遍历、深度、密度、插入、删除、查询、求左、求右、求根

二叉树的遍历:

在这里插入图片描述

    前序:根、左、右
    中序:左、根、右
    后序:左、右、根
    注意:前中后序由根节点决定,并且左右子树的次序不能改变
    注意:前序+中序、后序+中序 能够还原一棵树,前序+后序是无法还原的(因为无法确定根的左右子树)
    
    层序:从上到下、从左到右遍历一棵树,必须与队列配合使用

gcc -std=gnu99 list_queue.c bin_array_tree.c

二叉树的存储:

顺序:

    必须按照完全二叉树的格式存储,空位置使用特殊数据代替
        数据项:
            容量
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "list_queue.h"

#define TREE_TYPE char
#define EMPTY '#'

typedef struct BinTree
{
	TREE_TYPE* arr; // 存储节点的内存首地址
	size_t cal;
}BinTree;

//	构建
BinTree* create_tree(TREE_TYPE* arr,size_t len)//数组长度
{
	BinTree* tree = malloc(sizeof(BinTree));
	tree->arr = malloc(sizeof(TREE_TYPE)*len);
	//	把arr拷贝到tree->arr
	memcpy(tree->arr,arr,sizeof(TREE_TYPE)*len);
	tree->cal = len;
	return tree;
}

//	销毁
void destory_tree(BinTree* tree) 
{
	free(tree->arr);
	free(tree);
}

void _dlr_show(BinTree* tree,size_t index)
{
	if(index-1 >= tree->cal || EMPTY == tree->arr[index-1]) return;
	printf("%c ",tree->arr[index-1]);
	_dlr_show(tree,index*2);
	_dlr_show(tree,index*2+1);
}

//	前序遍历
void dlr_show(BinTree* tree)
{
	_dlr_show(tree,1);
	printf("\n");
}

void _ldr_show(BinTree* tree,size_t index)
{
	if(index-1 >= tree->cal || EMPTY == tree->arr[index-1]) return;
	
	_ldr_show(tree,index*2);
	printf("%c ",tree->arr[index-1]);
	_ldr_show(tree,index*2+1);
}

//	中序遍历
void ldr_show(BinTree* tree)
{
	_ldr_show(tree,1);	
	printf("\n");
}

void _lrd_show(BinTree* tree,size_t index)
{
	if(index-1 >= tree->cal || EMPTY == tree->arr[index-1]) return;
	
	_lrd_show(tree,index*2);
	_lrd_show(tree,index*2+1);
	printf("%c ",tree->arr[index-1]);
}

//	后序遍历
void lrd_show(BinTree* tree)
{
	_lrd_show(tree,1);	
	printf("\n");
}

//	层序遍历
void level_show(BinTree* tree)
{
	//	创建队列
	ListQueue* queue = create_list_queue();
	//	根入队
	push_list_queue(queue,1);
	
	while(!empty_list_queue(queue))
	{
	//	获取队头
		int index = head_list_queue(queue);
	//	计算左右子树编号
		int left = index*2;
	//	子树入队
		if(left-1 < tree->cal && EMPTY != tree->arr[left-1])
		{
			push_list_queue(queue,left);
		}
		int right = index*2+1;
		if(right-1 < tree->cal && EMPTY != tree->arr[right-1])
		{
			push_list_queue(queue,right);	
		}
	//	打印队头
		printf("%c ",tree->arr[index-1]);
	//	队头出队
		pop_list_queue(queue);
	}
	destory_list_queue(queue);
}

int _high_tree(BinTree* tree,size_t index)
{
	//	出口
	if(index-1 >= tree->cal || EMPTY == tree->arr[index-1]) 
		return 0;
	int lh = _high_tree(tree,index*2);
	int rh = _high_tree(tree,index*2+1);
	return lh > rh ? lh+1 : rh+1;
}

//	树的高度
int high_tree(BinTree* tree)
{
	return _high_tree(tree,1);	
}

int _density_tree(BinTree* tree,size_t index)
{
	if(index-1 >= tree->cal || EMPTY == tree->arr[index-1])
		return 0;
	return 1+_density_tree(tree,index*2)+_density_tree(tree,index*2+1);
}

//	树的密度 求节点总个数
int density_tree(BinTree* tree)
{
	//	return _density_tree(tree,1);
	//  循环比递归快
	
	int density = 0;
	for(int i=0; i<tree->cal; i++)
	{
		if(EMPTY != tree->arr[i]) density++;
	}
	return density;
	
}

//	插入
bool insert_tree(BinTree* tree,TREE_TYPE pdata,TREE_TYPE data)
{
	size_t index = 1;
	while(index-1 < tree->cal)
	{
		if(tree->arr[index-1] == pdata)
		{
			//	扩容
			if(index*2-1 >= tree->cal)
			{
				tree->arr = realloc(tree->arr,tree->cal*2+1);
				for(int i=tree->cal; i<(tree->cal*2+1); i++)
					tree->arr[i] = EMPTY;
				tree->cal = tree->cal*2+1;
			}
			
			if(EMPTY == tree->arr[index*2-1])
				return tree->arr[index*2-1] = data;
			if(EMPTY == tree->arr[index*2])
				return tree->arr[index*2] = data;
			return false;
		}
		index++;
	}
	return false;
}

//	删除 只删除叶子节点
bool del_tree(BinTree* tree,TREE_TYPE data)
{
	size_t index = 1;
	while(index-1 < tree->cal)
	{
		if(data == tree->arr[index-1])
		{
			//	左右子树超出范围,一定是叶子节点
			//	如果不超范围,左右都为空也一定是叶子节点
			//  也可以用高度判断叶子节点,叶子结点的高度为1,如果高度为其他数则不是
			if(index*2-1 < tree->cal && EMPTY != tree->arr[index*2-1])
				return false;
			if(index*2 < tree->cal && EMPTY != tree->arr[index*2])
				return false;
			tree->arr[index-1] = EMPTY;
			return true;
		}
		index++;
	}
	return false;
}


//	求左子树的下标
int left_tree(BinTree* tree,TREE_TYPE data)
{
	int index = 1;
	while(index-1 < tree->cal)
	{
		if(tree->arr[index-1] == data)
		{
			if(index*2-1 < tree->cal && EMPTY != tree->arr[index*2-1])
			{
				return index*2-1;	//左子树的下标  
			}
			return -1;
		}
		index++;
	}
	return -1;
}

//	求右
int right_tree(BinTree* tree,TREE_TYPE data)
{
	int index = 1;
	while(index-1 < tree->cal)
	{
		if(tree->arr[index-1] == data)
		{
			if(index*2 < tree->cal && EMPTY != tree->arr[index*2])
			{
				return index*2;	
			}
			return -1;
		}
		index++;
	}
	return -1;
}

//	求根
int root_tree(BinTree* tree,TREE_TYPE data)
{
	int index = 1;
	while(index-1 < tree->cal)
	{
		if(tree->arr[index-1] == data)
		{
			return index-1;	
		}
		index++;
	}
	return -1;
}

int main(int argc,const char* argv[])
{
	BinTree* tree = create_tree("ABCD#EFG###HI",13);
	dlr_show(tree);
	ldr_show(tree);
	lrd_show(tree);
	level_show(tree);
	printf("\nhigh:%d\n",high_tree(tree));
	printf("density:%d\n",density_tree(tree));
	printf("left:%d\n",left_tree(tree,'H'));
	insert_tree(tree,'G','X');
	dlr_show(tree);
	del_tree(tree,'A');
	dlr_show(tree);
}

链式:

    由一个个的节点组成,每个节点就是一棵树
        节点数据项:
            数据
            左子树指针
            右子树指针
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define TREE_TYPE char
#define EMPTY '#'
#define END '\0'

//	设计树的节点
typedef struct TreeNode
{
	TREE_TYPE data;
	struct TreeNode* left;
	struct TreeNode* right;
}TreeNode;

//	创建树的节点
TreeNode* create_tree_node(TREE_TYPE data)
{
	TreeNode* node = malloc(sizeof(TreeNode));
	node->data = data;
	node->left = NULL;
	node->right = NULL;
	return node;
}

/*TreeNode* create_tree(void)
{
	TREE_TYPE data = 0;
	scanf("%c",&data);
	if(EMPTY == data) return NULL;
	TreeNode* node = create_tree_node(data);
	node->left = create_tree();
	node->right = create_tree();
	return node;
}
*/

TreeNode* _create_tree(char** str)//*str的指向一直在被改变,所以要传二级指针,共享这个指针
{
	if(EMPTY == **str || END == **str) return NULL;
	TreeNode* node = create_tree_node(**str);
	*str += 1;
	node->left = _create_tree(str);//这里的str已经并定义成二级指针 
	*str += 1;
	node->right = _create_tree(str);
	return node;//返回给他的调用者,即上一个指向他的地址
}	

//	构建二叉树 调用者按照前序结果来构建
TreeNode* create_tree(char* str)
{
	return _create_tree(&str);//指针取地址,即为二级指针
}

//	前序遍历
void dlr_show(TreeNode* root)
{
	if(NULL == root) return;
	printf("%c ",root->data);
	dlr_show(root->left);
	dlr_show(root->right);
}

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

//	后序
void lrd_show(TreeNode* root)
{
	if(NULL == root) return;
	lrd_show(root->left);
	lrd_show(root->right);
	printf("%c ",root->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 1+density_tree(root->left)+density_tree(root->right);
}

//	求左
TreeNode* left_tree(TreeNode* root,TREE_TYPE data)
{
	if(NULL == root) return NULL;
	if(root->data == data)
		return root->left;
	TreeNode* left = left_tree(root->left,data);
	if(left) return left;
	TreeNode* right = left_tree(root->right,data);
	if(right) return right;
	return NULL;
}

//	求右
TreeNode* right_tree(TreeNode* root,TREE_TYPE data)
{
	if(NULL == root) return NULL;
	if(root->data == data)
		return root->right;
	TreeNode* left = right_tree(root->left,data);
	if(left) return left;
	TreeNode* right = right_tree(root->right,data);
	if(right) return right;
	return NULL;
	
}

//	求根
TreeNode* root_tree(TreeNode* root,TREE_TYPE data);


//	插入
bool insert_tree(TreeNode* root,TREE_TYPE pdata,TREE_TYPE data)
{
	if(NULL == root) return false;
	if(root->data == pdata)
	{
		if(NULL == root->left)
			return root->left = create_tree_node(data);
		if(NULL == root->right)
			return root->right = create_tree_node(data);
		return false;
	}
	bool lflag = insert_tree(root->left,pdata,data);
	bool rflag = insert_tree(root->right,pdata,data);
	return lflag || rflag;
}

//	删除
bool del_tree(TreeNode** root,TREE_TYPE data)
{
	if(NULL == *root) return false;
	if((*root)->data == data)
	{
		if((*root)->left || (*root)->right) return false;
		free(*root);
		*root = NULL;
		return true;
	}
	bool lflag = del_tree(&(*root)->left,data);
	bool rflag = del_tree(&(*root)->right,data);
	return lflag || rflag;
}

int main(int argc,const char* argv[])
{
	TreeNode* root = create_tree("ABDG####CEH##I##F##\0");
/*	printf("high:%d\n",high_tree(root));
	printf("density:%d\n",density_tree(root));
	TreeNode* left = right_tree(root,'C');
	printf("%c\n",left->data);
	insert_tree(root,'F','X');
	insert_tree(root,'F','Y');
*/
	del_tree(&root,'H');
	del_tree(&root,'A');
	ldr_show(root);
}

在这里插入图片描述

有序二叉树:

左子树的数据小于根,右子树的数据大于等于根,这种二叉树称为有序二叉树
注意:有序二叉树的中序遍历就是从小到大,所以有序二叉树也是一种排序算法
对有序二叉树的查找又天然是二分查找,所以经常考
注意:由于这种树的节点需要频繁地插入删除,因此不适合用顺序存储
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210528111425197.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pbmdibzY0,size_16,color_FFFFFF,t_70)
#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指83,即根
	{
		*root = node;
		return;
	}
	if((*root)->data > node->data)
		_insert_tree(&(*root)->left,node);//*root是解一次引用,相当于TreeNode*,是一个指向节点的指针,对指针取地址相当于变成了二级指针
	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;
	ldr_show(root->left);
	printf("%d ",root->data);
	ldr_show(root->right);
}

//	后序
void lrd_show(TreeNode* root)
{
	if(NULL == root) return;
	lrd_show(root->left);
	lrd_show(root->right);
	printf("%d ",root->data);
}

//	查询
bool query_tree(TreeNode* root,int data)
{
	if(NULL == root) return false;
	if(root->data == data) return true;

	if(root->data > data)
		return query_tree(root->left,data);
	else
		return query_tree(root->right,data);
}

//	密度
int density_tree(TreeNode* root)
{
	if(NULL == root) return 0;
	return 1+density_tree(root->left)+density_tree(root->right);
}

//	高度
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;
}

//	销毁
void destory_tree(TreeNode* root)
{
	if(NULL == root) return;
	destory_tree(root->left);
	destory_tree(root->right);
	free(root);
}

//	按照中序来查找数据
bool _access_tree(TreeNode* root,size_t index,int* count,int* val)
{
	if(NULL == root) return false;
	_access_tree(root->right,index,count,val);
	if((*count)++ == index)
	{
		*val = root->data;
		return true;
	}
	_access_tree(root->left,index,count,val);
}

//	访问第index小的数
bool access_tree(TreeNode* root,size_t index,int* val)
{
	int count = 1;
	return _access_tree(root,index,&count,val);
}


//	按值删除
bool del_tree(TreeNode** root,int data)
{
	if(NULL == *root) return false;
	if((*root)->data == data)//(*root)->
	{
		TreeNode* temp = *root;
		*root = temp->left;
		if(temp->right)
			_insert_tree(root,temp->right);//需要加判断temp->right 是否为空,若为空加进去会出现段错误
		free(temp);
		return true;
	}
	if(data < (*root)->data)
		return del_tree(&(*root)->left,data);
	else
		return del_tree(&(*root)->right,data);

}

/*-------------------------*/
//	镜像树
void mirror_tree(TreeNode* root)
{
	if(NULL  == root) return false;
	TreeNode* temp = root->left;
	root->left = root->right;
	root->right = temp;
	mirror_tree(root->left);
	mirror_tree(root->right);
}

bool _is_sym(TreeNode* root1,TreeNode* root2)
{
	if(root1->data != root2->data) return false;
	if(NULL == root1 && NULL != root2) return false;
	if(NULL != root1 && NULL == root2) return false;
	if(NULL == root1 && NULL == root2) return true;

	bool lflag = _is_sym(root1->left,root2->right);
	bool rflag = _is_sym(root1->right,root2->left);
	return lflag && rflag;
}

//	对称
bool is_sym(TreeNode* root)
{
	return _is_sym(root->left,root->right);	
}

//	两课树比较
bool treecmp(TreeNode* r1,TreeNode* r2)
{
	if(NULL == r1 && NULL == r2) return true;
	if(NULL == r1 && NULL != r2) return false;
	if(NULL != r1 && NULL == r2) return true;
	
	if(r1->data != r2->data) return false;
	return treecmp(r1->left,r2->left) && treecmp(r1->right,r2->right);
}

//	判断子结构
bool is_son(TreeNode* root1,TreeNode* root2)
{
	if(NULL == root1) return false;

	if(root1->data == root2->data)
		return treecmp(root1,root2);
	return is_son(root1->left,root2) || is_son(root1->right,root2);
}

void __add_tail_list(TreeNode** head,TreeNode* node)
{
	printf("%d\n",node->data);
	if(NULL == *head)
	{
		*head = node;	
	}
	else
	{
		(*head)->left->right = node;
		node->left = (*head)->left;
	}
	(*head)->left = node;
//	 node->right = *head;
}

void _tree_to_list(TreeNode* root,TreeNode** head)
{
	if(NULL == root) return;
	//按照中序添加进链表
	_tree_to_list(root->left,head);
	__add_tail_list(head,root);
	_tree_to_list(root->right,head);
}

//	有序二叉树转有序双向链表
TreeNode* tree_to_list(TreeNode* root)
{
	//	不带头节点的链表
	TreeNode* head = NULL;
	_tree_to_list(root,&head);
	head->left->right = head;	
	return head;
}

void z_show(TreeNode* root)
{
	ListStack* s1 = create_list_stack();
	ListStack* s2 = create_list_stack();

	//	根入s1
	push_list_stack(s1,root);

	while(!empty_list_stack(s1) || !empty_list_stack(s2))
	{
		while(!empty_list_stack(s1))
		{
			TreeNode* node = top_list_stack(s1);
			pop_list_stack(s1);
			printf("%d ",node->data);
			if(node->left) 	push_list_stack(s2,node->left);
			if(node->right)	push_list_stack(s2,node->right);
		}
		while(!empty_list_stack(s2))
		{
			TreeNode* node = top_list_stack(s2);
			pop_list_stack(s2);
			printf("%d ",node->data);
			if(node->right) push_list_stack(s1,node->right);
			if(node->left) 	push_list_stack(s1,node->left);
		}
	}
}

int main(int argc,const char* argv[])
{
	TreeNode* root = NULL;
	for(int i=0; i<10; i++)
	{
		int data = rand()%100;
		insert_tree(&root,data);
	}
	z_show(root);
	/*dd
	TreeNode* head = tree_to_list(root);
	TreeNode* n = head;
	do{
		printf("%d ",n->data);
		n = n->right;
	}while(n!=head);
	TreeNode* root2 = NULL;
	insert_tree(&root2,93);
	insert_tree(&root2,86);
	insert_tree(&root2,92);
	printf("flag=%d\n",is_son(root,root2));
	printf("\n");
	ldr_show(root);
	printf("\n%d\n",query_tree(root,93));
	int num = 0;
	access_tree(root,100,&num);
	printf("num=%d\n",num);
	*/
}

作业:

1、把一棵二叉树转换成它的镜像树
//	镜像树
void mirror_tree(TreeNode* root)
{
	if(NULL  == root) return false;
	TreeNode* temp = root->left;
	root->left = root->right;
	root->right = temp;
	mirror_tree(root->left);
	mirror_tree(root->right);
}
2、输入两棵二叉树A,B,判断B是不是A的子结构(约定空树不是任何树的子结构)
//	两课树比较
bool treecmp(TreeNode* r1,TreeNode* r2)
{
	if(NULL == r1 && NULL == r2) return true;
	if(NULL == r1 && NULL != r2) return false;
	if(NULL != r1 && NULL == r2) return true;
	
	if(r1->data != r2->data) return false;
	return treecmp(r1->left,r2->left) && treecmp(r1->right,r2->right);
}

//	判断子结构
bool is_son(TreeNode* root1,TreeNode* root2)
{
	if(NULL == root1) return false;

	if(root1->data == root2->data)
		return treecmp(root1,root2);
	return is_son(root1->left,root2) || is_son(root1->right,root2);
}

3、将一棵有序二叉树转换为有序的双向链表
void __add_tail_list(TreeNode** head,TreeNode* node)//尾添加
{
	printf("%d\n", node->data);
	if(NULL == head)
	{
		*head = node;
	}
	else
	{
		(*head)->left->right = node;
		node->left=(*head)->left;
	}
			(*head)->left = node;
}
void _tree_to_list(TreeNode* root,TreeNode** head)
{
	if(NULL == root) return;
	_tree_to_list(root->left,head);
	__add_tail_list(head,node)'
	_tree_to_list(root->right,head);
}
//	有序二叉树转有序双向链表
TreeNode* tree_to_list(TreeNode* root)
{
	TreeNode* head = NULL;
	_tree_to_list(root,*head);
	head->left->right = head;
	return head;
}
4、计算出有序二叉树的第K大的值是多少
5、判断一棵二叉树是否对称的
bool _is_sym(TreeNode* root1,TreeNode* root2)
{
	if(root1->data != root2->data) return false;
	if(NULL == root1 && NULL !=root2) return flase;
	if(NULL != root1 && NULL == root2) return false;
	if(NULL == root1 && NULL == root2) return true;
	 
	int lflag = _is_sym(root1->left,root2->right);
	int rflag = _is_sym(root1->right,root2->left);
	return lflag && rflag;
}
6、请实现一个函数,该函数按照Z字型遍历打印二叉树,即第一行从左到右打印节点,第二行从右

在这里插入图片描述

void z_show(TreeNode* root)
{
	ListStack* s1 = create_list_stack();
	ListStack* s2 = create_list_stack();

	//	根入s1
	push_list_stack(s1,root);

	while(!empty_list_stack(s1) || !empty_list_stack(s2))
	{
		while(!empty_list_stack(s1))
		{
			TreeNode* node = top_list_stack(s1);
			pop_list_stack(s1);
			printf("%d ",node->data);
			if(node->left) 	push_list_stack(s2,node->left);
			if(node->right)	push_list_stack(s2,node->right);
		}
		while(!empty_list_stack(s2))
		{
			TreeNode* node = top_list_stack(s2);
			pop_list_stack(s2);
			printf("%d ",node->data);
			if(node->right) push_list_stack(s1,node->right);
			if(node->left) 	push_list_stack(s1,node->left);
		}
	}
}

线索二叉树:

规律:在有n个节点的链式二叉树中,必定存在n+1个空指针域

链式二叉树中有很多的空指针域,可以让这些右指针指向下一个节点,这样在遍历树时可以不用递归而是使用循环,可以提高树的遍历速度

中序线索二叉树节点数据项:
    数据
    左子树指针
    右子树指针
    右子树指针标志  (假表示指向的是右子树,真表示指向下一个节点)

实现过程:
    1、按照中序遍历过程创建线索
    2、按照线索来进行遍历(循环)

在这里插入图片描述

#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;//return跳出此时的create函数
	//	左
	create_clue(root->left);

	//	根
	//	通过中序遍历找到root的上一个节点prve,如果该节点存在,并且右子树为空,则右子树指向下一个节点root
	if(NULL != prev && NULL == prev->right)
	{
		prev->right = root;
		prev->rclue = true;
	}
	//	处理完后,root就成为了上一个节点
	prev = root;

	//	右
	create_clue(root->right);
}

//	按照线索进行遍历
void clue_show(TreeNode* root)
{
	while(root)
	{
		while(root->left)
			root = root->left;
		printf("%d ",root->data);
		while(root->rclue)
		{
			root = root->right;
			printf("%d ",root->data);
		}
		root = 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);
	}
	printf("\n");
//	ldr_show(root);	按照递归遍历
	create_clue(root);
	clue_show(root);//按照循环遍历
}

选择树:(胜者树、败者树)

是一种完全二叉树,把所有要比较的数据放在最后一层,根节点是左右子树中的一个,是它们的最大或最小,选择树的功能是快速地找出其中的最大或者最小值   

在这里插入图片描述

在这里插入图片描述

堆:

是一种完全二叉树,不适合链式存储
大顶堆(大根堆):
    根节点比左右子树大
小顶堆(小根堆):
    根节点比左右子树小

在这里插入图片描述

数据项:
    存储节点的内存的首地址
    容量
    数量
运算:
    创建、添加、删除、堆满、堆空、堆顶

堆可以实现优先队列的效果
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define swap(a,b) {typeof(a) (t)=(a);(a)=(b);(b)=(t);}//typeof(int*) a,b;等价于:   int *a,*b;
#define TYPE int 

typedef struct Heap
{
	TYPE* arr;
	size_t cal;
	size_t cnt;
}Heap;

//	创建
Heap* create_heap(size_t cal)
{
	Heap* heap = malloc(sizeof(Heap));
	heap->arr = malloc(sizeof(TYPE)*cal);
	heap->cal = cal;
	heap->cnt = 0;
	return heap;
}

//	空堆
bool empty_heap(Heap* heap)
{
	return !heap->cnt;	
}

//	满堆
bool full_heap(Heap* heap)
{
	return heap->cnt == heap->cal;
}

//	添加
bool add_heap(Heap* heap,TYPE data)//这里heap不要二级指针,这是顺序的,指针指向不会改变,顺序是定好的
{
	if(full_heap(heap))	return false;

	heap->arr[heap->cnt++] = data;

	//	调整成大顶堆
	//	编号
	int i = heap->cnt;
	while(i > 1)
	{
		if(heap->arr[i-1] > heap->arr[i/2-1])	
		{
			swap(heap->arr[i-1],heap->arr[i/2-1]);
		}
		i = i/2;
	}
	return true;
}

//	删除
bool del_heap(Heap* heap)
{
	if(empty_heap(heap)) return false;

	//	交换堆顶和末尾
	swap(heap->arr[0],heap->arr[heap->cnt-1]);
	//	删除末尾
	heap->cnt--;

	//	从上到下,调整成大顶堆
	int i = 1;
	while(i-1 < heap->cnt)
	{
		//	右子树存在,比较左右子树,左子树中放左右的最大值
		if(i*2 < heap->cnt && heap->arr[i*2] > heap->arr[i*2-1])
		{
			swap(heap->arr[i*2],heap->arr[i*2-1]);	
		}
		// 左子树存在,比较根与左子树,根放最大值
		if(i*2-1 < heap->cnt && heap->arr[i*2-1] > heap->arr[i-1])
		{
			swap(heap->arr[i*2-1],heap->arr[i-1]);	
			i = i*2;
		}
		else
		{
			break;
		}
	}
	return true;
}

//	堆顶
TYPE top_heap(Heap* heap)
{
	return heap->arr[0];
}

//	遍历
void show_heap(Heap* heap)
{
	for(int i=0; i<heap->cal; i++)
	{
		printf("%d ",heap->arr[i]);	
	}
	printf("\n");
}

//	堆排序
void sort_heap(int* arr,int len)
{
	//	把数组调整成堆结构
	for(int i=len; i>1; i--)
	{
		int j = i;
		while(1 < j)
		{
			if(arr[j-1] > arr[j/2-1])	swap(arr[j-1],arr[j/2-1]);
			j = j/2;
		}
	}
	//	删除堆顶,并从上到下调整,直到堆为空
	while(len > 1)
	{
		swap(arr[0],arr[len-1]);
		len--;

		int i = 1;
		while(i-1 < len)
		{
			if(i*2 < len && arr[i*2] > arr[i*2-1])
				swap(arr[i*2],arr[i*2-1]);
			if(i*2-1 < len && arr[i*2-1] > arr[i-1])
				swap(arr[i*2-1],arr[i-1]);
			i = i*2;
		}
	}

}


int main(int argc,const char* argv[])
{
	int arr[10] = {};
	for(int i=0; i<10; i++)
	{
		arr[i] = rand()%100;	
	}
	sort_heap(arr,10);

	for(int i=0; i<10; i++)
	{
		printf("%d ",arr[i]);	
	}
	/*
	Heap* heap = create_heap(10);
	for(int i=0; i<10; i++)
	{
		int data = rand()%100;
		add_heap(heap,data);
	}
	//show_heap(heap);
	for(int i=0; i<10; i++)
	{
		printf("top:%d\n",top_heap(heap));
		del_heap(heap);
	}
	*/
}

让下标与编号相等版

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

#define TYPE int
#define swap(a,b) {typeof(a) t=(a);(a)=(b);(b)=t;}

typedef struct Heap
{
	TYPE* arr;
	size_t cal;
	size_t cnt;
}Heap;

Heap* create_heap(size_t cal)
{
	Heap* heap = malloc(sizeof(Heap));
	//	第一个位置不使用,让下标与编号相等
	heap->arr = malloc(sizeof(TYPE)*(cal+1));
	heap->cal = cal;
	heap->cnt = 0;
	return heap;
}

//	销毁堆
void destory_heap(Heap* heap)
{
	free(heap->arr);
	free(heap);
}

//	堆空
bool empty_heap(Heap* heap)
{
	return !heap->cnt;	
}
//	堆满
bool full_heap(Heap* heap)
{
	return heap->cnt == heap->cal;	
}

//	添加
bool add_heap(Heap* heap,TYPE data)
{
	if(full_heap(heap)) return false;
	heap->arr[++heap->cnt] = data;

	//	从下到上调整
	int i = heap->cnt;
	while(i > 1)
	{
		if(heap->arr[i] > heap->arr[i/2])	
			swap(heap->arr[i],heap->arr[i/2]);
		i = i/2;
	}
	return true;
}

//	删除
bool del_heap(Heap* heap)
{
	if(empty_heap(heap)) return false;

	swap(heap->arr[1],heap->arr[heap->cnt]);
	heap->cnt--;

	//	从上到下调整
	int i = 1;
	while(i <= heap->cnt)
	{
		if(i*2+1 <= heap->cnt && heap->arr[i*2+1] > heap->arr[i*2])
			swap(heap->arr[i*2+1],heap->arr[i*2]);
		if(i*2 <= heap->cnt && heap->arr[i*2] > heap->arr[i])
			swap(heap->arr[i*2],heap->arr[i]);
		i = i*2;
	}
	return true;
}

//	遍历
void show_heap(Heap* heap)
{
	for(int i=1; i<=heap->cal; i++)
	{
		printf("%d ",heap->arr[i]);	
	}
	printf("\n");
}

int main(int argc,const char* argv[])
{
	Heap* heap = create_heap(10);
	for(int i=0; i<10; i++)
	{
		int	data = rand()%100;
		add_heap(heap,data);
	}
	do{
		show_heap(heap);
	}while(del_heap(heap));
}

在这里插入图片描述

平衡二叉树:

前提是有序的二叉树,它的左右子树高度相差不超过1,它所有的子树也要满足这个要求
如果一个有序的二叉树呈单支状(接近单支),它的效率接近链表,查找、访问效率较低,因此当达到平衡时它的效率才最高
由于节点的位置受到值的影响,因此只能调整,而不能强行修改

二叉树不平衡的基础原因:
        x                                   y
       / \                                /   \
      y   t1     以y为轴向右旋转          z     x
     / \                                / \   / \
    z  t2                              t3 t4 t2 t1
   / \
  t3 t4

        x                                   y
       / \      以y为轴向左旋转            /   \   
      t1  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;
}

//	求左右子树的高度差,以此检查左右子树是否平衡
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)
	{
		//	左子树高
		//	y的左子树高于等于右子树
		if(is_balance(x->left) >= 0)
		{
			//	右旋转
			x = right_rotate(x);
		}
		else
		{
			//	左旋转
			x->left = left_rotate(x->left);
			//	右旋转
			x = right_rotate(x);
		}
	}

	if(rh - lh >1)
	{
		//	右子树高
		//	y的右子树高于等于左子树
		if(is_balance(x->right) <= 0)
		{
			//	左旋转	
			x = left_rotate(x);

		}
		else
		{
			//	右旋转
			x->right = right_rotate(x->right);
			//	左旋转
			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* max_tree(TreeNode* root)
{
	TreeNode* max = root;
	while(max->right) max = max->right;
	return max;
}

TreeNode* min_tree(TreeNode* root)
{
	TreeNode* min = root;
	while(min->left) min = min->left;
	return min;
}

TreeNode* del_tree(TreeNode* root,int data)
{
	if(NULL == root) return NULL;
	if(root->data == data)
	{
		//	1、左右子树都为空
		if(NULL == root->left && NULL == root->right)
		{
			free(root);
			return NULL;
		}
		//	2、左子树为空,替换为右子树
		if(NULL == root->left)
		{
			TreeNode* temp = root->right;
			free(root);
			return temp;
		}
		//	3、右子树为空,替换为左子树
		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;
			//	删除node
			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++)
	{
		int data = rand()%100;
		root = insert_tree(root,i);//需要用root接一下,因为这里调用的是一级指针,如果不接root不改变 
	}

	root = del_tree(root,2);
	root = del_tree(root,0);

	printf("high:%d\n",high_tree(root));
	ldr_show(root);
	printf("\n");
	dlr_show(root);
}

在这里插入图片描述

红黑树:

是一种自平衡的树,它的平衡不是根据子树的高度来调整的,而是给节点设置一个颜色,来达到平衡。
优点:插入和删除的效率,比AVL树要高
缺点:没有AVL树均匀,所以查找、访问效率没有AVL树高
规则:
1.节点是红色或黑色 
2.根节点是黑色。
3.每个叶子节点都是黑色的空节点(NIL节点)。
4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值