二叉树
链式存储:由一个个节点组成,每个节点都是一个树
节点数据项:
数据项:
左子树指针:
右子树指针:
ABDG##H###CEI###F#J##
#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* creat_tree_node(TREE_TYPE data)
{
TreeNode* node=malloc(sizeof(TreeNode));
node->left=NULL;
node->right=NULL;
node->data=data;
return node;
}
//构建一棵树 前序
/*
TreeNode* creat_tree(void)
{
TREE_TYPE data=0;
scanf("%c",&data);
if(EMPTY == data) return NULL;
TreeNode* node = creat_tree_node(data);
node->left=creat_tree();
node->right=creat_tree();
return node;
}
*/
TreeNode* _creat_tree(char** str)
{
if(EMPTY == **str || END == **str) return NULL;
TreeNode* node=creat_tree_node(**str);
*str+=1;
node->left=_creat_tree(str);
*str+=1;
node->right=_creat_tree(str);
return node;
}
//构建一棵树 前序
TreeNode* creat_tree(char* str)
{
_creat_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 left_high=high_tree(root->left);
int right_high=high_tree(root->right);
return left_high>right_high?left_high+1:right_high+1;
}
int desity_tree(TreeNode* root)
{
if(NULL == root) return 0;
return desity_tree(root->left)+desity_tree(root->right)+1;
}
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);
TreeNode* right=left_tree(root->right,data);
return left?left:right;
}
//插入
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=creat_tree_node(data);
if(NULL==root->right)
return root->right=creat_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;
}
if(del_tree(&(*root)->left,data)) return true;
return del_tree(&(*root)->right,data);
}
void destroy_tree(TreeNode* root)
{
if(NULL == root) return;
destroy_tree(root->left);
destroy_tree(root->right);
free(root);
}
int main(int argc,const char* argv[])
{
TreeNode* root=creat_tree("ABDG##H###CEI###F#J##");
dlr_show(root);
printf("\n");
ldr_show(root);
printf("\n");
lrd_show(root);
printf("\n%c\n",left_tree(root,'A')->data);
destroy_tree(root);
root=NULL;
}
有序二叉树:(二叉排序树、二叉搜索树、二叉查找树)
左子树的数据小于根节点,根节点的数据小于等于右子树,并且左右子树都符合以上定义
注意:由于这种树的中序遍历是从小到大,所以有序二叉树也是一种排序算法,并且有序二叉树中查找某个值,天然是二分查找
注意:由于有序二叉树需要频繁地插入删除,因此不适合使用顺序存储
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//有序二叉树
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
TreeNode* creat_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,creat_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);
return query_tree(root->right,data);
}
//高度
int high_tree(TreeNode* root)
{
if(NULL == root) return 0;
int left_high=high_tree(root->left);
int right_high=high_tree(root->right);
return left_high>right_high?left_high+1:right_high+1;
}
//密度
int desity_tree(TreeNode* root)
{
if(NULL == root) return 0;
return desity_tree(root->left)+desity_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_val_tree(TreeNode** root,int data)
{
if(NULL == *root) return false;
if(data==(*root)->data)
{
TreeNode* temp=*root;
*root=temp->left;
_insert_tree(root,temp->right);
free(temp);
return true;
}
if(data < (*root)->data)
return del_val_tree(&(*root)->left,data);
return del_val_tree(&(*root)->right,data);
}
//判断是否平衡
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_val_tree(&root,83);
del_val_tree(&root,77);
printf("\n");
dlr_show(root);
printf("\n");
ldr_show(root);
printf("\nquery:%d\n",query_tree(root,83));
int val=-1;
access_ldr_tree(root,0,&val);
printf("val:%d\n",val);
}
线索二叉树:
也是有序二叉树
规律:在一颗有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* creat_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,creat_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 creat_clue(TreeNode* root)
{
if(NULL == root) return;
creat_clue(root->left);
if(NULL != prev && NULL == prev->right)
{
prev->right = root;
prev->rclue = true;
}
prev=root;
creat_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;
insert_tree(&root,data);
}
ldr_show(root);
creat_clue(root);
printf("\n");
clue_show(root);
}
选择树:
是一种完全二叉树,把要存储的数据存放在最后一层,根节点是左右子树的其中一个,可以是最大的或者最小的
选择树的功能是快速地找出其中最大(胜者树)或最小值(败者树)
堆:
是一颗完全二叉树,不适合链式存储的树
大顶堆(大根堆):
根节点比左右子树大
小顶堆(小跟堆):
根节点比左右子树小
数据项:
存储数据内存的首地址
容量
数量
运算:
创建、销毁、添加、删除、空堆、满堆、堆顶
#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* creat_heap(int 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 0==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 index=heap->cnt; //编号
while(index>1)
{
if(heap->arr[index/2-1]<heap->arr[index-1])
{
SWAP(heap->arr[index/2-1],heap->arr[index-1]);
index/=2;
continue;
}
return true;
}
return true;
}
void show_heap(Heap* heap)
{
for(int i=0;i<heap->cnt;i++)
{
printf("%d ",heap->arr[i]);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
Heap* heap=creat_heap(10);
for(int i=0;i<10;i++)
{
add_heap(heap,rand()%100);
}
show_heap(heap);
}