本博客中所有源代码:Github托管项目地址
二叉树的介绍
1、普通二叉树、完全二叉树、满二叉树
二叉树:最多有两棵子树的树被称为二叉树
满二叉树:二叉树中所有非叶子结点的度都是2,且叶子结点都在同一层次上
完全二叉树:如果一个二叉树与满二叉树前m个节点的结构相同,这样的二叉树被称为完全二叉树
也就是说,如果把满二叉树从右至左、从下往上删除一些节点,剩余的结构就构成完全二叉树
采用顺序存储的完全二叉树,可以根据任意节点的位置计算其父节点、孩子节点在数组中的位置(下标),如果父节点和孩子节点存在的话。
这也说明,完全二叉树适合使用顺序表存储
2、线索二叉树
n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。
3、哈夫曼树(最优二叉树)
给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
4、二叉搜索(查找、排序)树
对二叉树进行中序遍历时,其输出是一个有序数组
根据二叉排序树的定义,发现其搜索过程具有二分特性,效率较高
缺点:二叉排序树的最终形态与输入数据的顺序有关,
例如,输入数据[1,2,3,4,5,6,7,8,9],最终形成的二叉排序树如下图
此时,二叉树退化成了单链表,查找效率大大下降
5、平衡二叉树
为了克服二叉排序树的缺点,人们想出办法,使得一棵树的左右子树高度大致相等
比较出名的是苏联科学家家G.M. Adelson-Velsky 和 E.M. Landis于1962年提出的,被命名为AVL树,,和红黑树
6、AVL树
任一节点的左子树深度和右子树深度相差不超过1,我们用平衡因子衡量这种差异
任意节点的平衡因子Balance(p)= heigth(p的左子树) - height(p的右子树)
在进行AVL树的插入和删除操作时,当平衡因子=2时,就要调整节点的位置,使其满足AVL树的定义
关于AVL树的插入、删除操作,随后会进行记录
总结:我们知道,实际应用当中,我们经常使用的是查找和排序操作,这在我们的各种管理系统、数据库系统、操作系统等当中,十分常用。
数组的下标寻址十分迅速,但计算机的内存是有限的,故数组的长度也是有限的,实际应用当中的数据往往十分庞大
而且无序数组的查找最坏情况需要遍历整个数组
后来人们提出了二分查找,二分查找要求数组的构造一定有序。二分法查找解决了普通数组查找复杂度过高的问题
任和一种数组无法解决的问题就是插入、删除操作比较复杂,因此,在一个增删查改比较频繁的数据结构中,数组不会被优先考虑
普通链表由于它的结构特点被证明根本不适合进行查找
二叉查找树因为可能退化成链表,同样不适合进行查找
哈希表是数组和链表的折中,,同时它的设计依赖散列函数的设计,数组不能无限长、链表也不适合查找,所以也适合大规模的查找
AVL树的旋转过程非常麻烦,因此插入和删除很慢,也就是构建AVL树比较麻烦
红黑树是平衡二叉树和AVL树的折中,因此是比较合适的。集合类中的Map、关联数组具有较高的查询效率,它们的底层实现就是红黑树
/*bitree.h*/ #ifndef BITREE_H #define BITREE_H #include <stdlib.h> /*为节点定义二叉树结构体*/ typedef struct BiTreeNode_ { void *data;/*存放数据*/ struct BiTreeNode_ *left;/*左孩子*/ struct BiTreeNode_ *right;/*右孩子*/ }BiTreeNode; /*定义二叉树结构体*/ typedef struct BiTree_ { int size;/*存放数据个数*/ int (*compare) (const void *key1,const void *key2);/*预留的一个接口*/ void (*destroy)(void *data);/*封装的析构函数,作用是释放data空间*/ BiTreeNode *root;/*指向根节点的一个指针*/ }BiTree; /*函数接口*/ void bitree_init(BiTree *tree, void (*destroy)(void *data)); void bitree_destroy(BiTree *tree); int bitree_ins_left(BiTree *tree,BiTreeNode *node,const void *data); int bitree_ins_right(BiTree * tree, BiTreeNode * node, const void * data); void bitree_rem_left(BiTree *tree,BiTreeNode *node); void bitree_rem_right(BiTree * tree, BiTreeNode * node); int bitree_merge(BiTree *merge,BiTree *left,BiTree *right,const void *data); #define bitree_size(tree) ((tree) -> size) #define bitree_root(tree) ((tree) -> root) /*node标识是树的分子结束*/ #define bitree_is_eob(node) ((node) == NULL) /*判断是不是叶子结点*/ #define bitree_is_leaf(node) ((node)->left == NULL && (node) ->right == NULL) #define bitree_data(node) ((node) ->data) #define bitree_left(node) ((node)->left) #define bitree_right(node) ((node)->right) #endif
/*bitree.c*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "bitree.h" /*二叉树初始化*/ void bitree_init(BiTree * tree, void(* destroy)(void * data)) { tree ->size = 0; tree ->destroy = destroy; tree ->root = NULL; return ; } /*二叉树销毁*/ void bitree_destroy(BiTree * tree) { /*从二叉树中移除所有的节点*/ bitree_rem_left( tree, NULL); memset(tree,0,sizeof(BiTree); return; } /* 将节点插入到二叉树中,插入到有参数指定节点的左子树 *如果节点为空,且树为空树,就是讲此节点设为root * return 成功返回0,失败-1 */ int bitree_ins_left(BiTree * tree, BiTreeNode * node, const void * data) { BiTreeNode *new_node,**position; /*判断该插入到那个节点*/ if (node == NULL){ /*当node==NULL,说明是根节点,但是如果树不为空,则出错返回-1*/ if (bitree_size(tree) > 0){ return -1; } /*这个意思是position指向根节点*/ position = &tree ->root; } else { /*判断node节点左孩子是否为空*/ if (bitree_left(node) != NULL){ return -1; } position = &node->left; } /*申请node空间保存data*/ if ((new_node = (BiTreeNode *)malloc(sizeof(BiTreeNode))) == NULL) return -1; /*将节点插入到二叉树中*/ new_node ->data = (void *)data; new_node ->left = NULL; new_node ->right = NULL; tree->size ++; return 0; } /*将节点插入到二叉树中,插入到有参数指定节点的右子树 *如果节点为空,且树为空树,就是讲此节点设为root * return 成功返回0,失败-1 */ int bitree_ins_right(BiTree * tree, BiTreeNode * node, const void * data) { BiTreeNode *new_node,**position; /*判断该插入到那个节点*/ if (node == NULL){ /*当node==NULL,说明是根节点,但是如果树不为空,则出错返回-1*/ if (bitree_size(tree) > 0){ return -1; } /*这个意思是position指向根节点*/ position = &tree ->root; } else { /*判断node节点左孩子是否为空*/ if (bitree_right(node) != NULL){ return -1; } position = &node->right; } /*申请node空间保存data*/ if ((new_node = (BiTreeNode *)malloc(sizeof(BiTreeNode))) == NULL) return -1; /*将节点插入到二叉树中*/ new_node ->data = (void *)data; new_node ->left = NULL; new_node ->right = NULL; *position = new_node; tree->size ++; return 0; } /*移除node节点的左孩子如果node=NULL 则移除所有节点 *无返回值 */ void bitree_rem_left(BiTree * tree, BiTreeNode * node) { BiTreeNode **position; /*当为空树时返回*/ if (bitree_size(tree) == 0) return; /* 决定删除那个节点*/ if (node == NULL) position = &tree ->root; else position = &node->left; /*删除这个节点*/ if (*position != NULL){ bitree_rem_left(tree, *position); bitree_rem_right(tree, *position); if (tree->destroy != NULL) tree->destroy(*position -> data); } free(*position); *position = NULL; tree->size --; } /*移除node节点的右孩子如果node=NULL 则移除所有节点 *无返回值 */ void bitree_rem_right(BiTree * tree, BiTreeNode * node) { BiTreeNode **position; /*当为空树时返回*/ if (bitree_size(tree) == 0) return; /* 决定删除那个节点*/ if (node == NULL) position = &tree ->root; else position = &node->right; /*删除这个节点*/ if (*position != NULL){ bitree_rem_left(tree, *position); bitree_rem_right(tree, *position); if (tree->destroy != NULL) tree->destroy(*position -> data); } free(*position); *position = NULL; tree->size --; } /*合并二叉树*/ int bitree_merge(BiTree * merge, BiTree * left, BiTree * right, const void * data) { /*初始化merger*/ bitree_init(merge, left->destroy); /*如何插入失败则返回-1*/ if (bitree_ins_left(merge, NULL, data) != 0){ bitree_destroy(merge); return -1; } bitree_root(merge)->left = bitree_root(left); bitree_root(merge)->right = bitree_root(right); merge->size += bitree_size(left) + bitree_size(right); left ->root = NULL; left->size = 0; right->root = NULL; right ->size = 0; return 0; }
/*bistree.h*/ #ifndef BISTREE_H #define BISTREE_H /*定义平衡因子为AVL树*/ #define AVL_LFT_HEAVY 1 #define AVL_BALANCED 0 #define AVL_RGT_HEAVY -1 /*定义AVL树的节点*/ typedef struct AvlNode_ { void *data; int hidden; int factor;/*平衡因子*/ }AvlNode; /*定义二叉树结构体*/ typedef struct BisTree_ { int size;/*存放数据个数*/ int (*compare) (const void *key1,const void *key2);/*预留的一个接口*/ void (*destroy)(void *data);/*封装的析构函数,作用是释放data空间*/ BiTreeNode *root;/*指向根节点的一个指针*/ }BisTree; /*函数接口*/ void bistree_init (BisTree *tree, int (*compare)(const void *key1,const void *key2),void (*destroy)(void *data)); void bistree_destory(BisTree *tree); int bistree_insert(BisTree *tree,const void *data); int bistree_remove (BisTree *tree,const void *data); int bistree_lookup(BisTree *tree,void **data); #define bistree_size(tree) ((tree)->size) #endif
二叉树主文件bistree.c(旋转)
/*bistree.c*/ #include <stdlib.h> #include <string.h> #include "bistree.h" #include "bitree.h" /*左旋*/ static void rotate_left(BiTreeNode **node) { BiTreeNode *right ,grandchild; right = bitree_right(*node); if (((AvlNode *)bitree_data(right) ->factor == AVL_RGT_HEAVY){ /* RR */ bitree_right(*node) = bitree_left(right); bitree_left(right) = *node; ((AvlNode *)bitree_data(*node))->factor = AVL_BALANCED; ((AvlNode *)bitree_data(right)) ->factor = AVL_BALANCED; *node = right; } else { /*RL*/ grandchild = bitree_left(right); bitree_left(right) = bitree_right(grandchild); bitree_right(grandchild) = right; bitree_right(*node) = bitree_left(grandchild); bitree_left(grandchild) = *node; switch (((AvlNode *)bitree_data(grandchild)) ->factor){ case AVL_LFT_HEAVY: ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED; ((AvlNode *)bitree_data(right)) ->factor = AVL_RGT_HEAVY; break; case AVL_BALANCED: ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED; ((AvlNode *)bitree_data(right)) ->factor = AVL_BALANCED; break; case AVL_RGT_HEAVY: ((AvlNode *)bitree_data(*node)) ->factor = AVL_LFT_HEAVY; ((AvlNode *)bitree_data(right)) ->factor = AVL_BALANCED; break; default: break; } ((AvlNode *)bitree_data(grandchild)) ->factor = AVL_BALANCED; *node = grandchild; } return; }
/*右旋*/ static void rotata_right(BiTreeNode **node) { BiTreeNode *left ,grandchild; left = bitree_left(*node); if (((AvlNode *)bitree_data(left) ->factor == AVL_LFT_HEAVY){ /* LL */ bitree_left(*node) = bitree_right(left); bitree_right(left) = *node; ((AvlNode *)bitree_data(*node))->factor = AVL_BALANCED; ((AvlNode *)bitree_data(left)) ->factor = AVL_BALANCED; *node = left; } else { /*LR*/ grandchild = bitree_right(left); bitree_right(left) = bitree_left(grandchild); bitree_left(grandchild) = left; bitree_left(*node) = bitree_right(grandchild); bitree_right(grandchild) = *node; switch (((AvlNode *)bitree_data(grandchild)) ->factor){ case AVL_LFT_HEAVY: ((AvlNode *)bitree_data(*node)) ->factor = AVL_RGT_HEAVY; ((AvlNode *)bitree_data(left)) ->factor = AVL_BALANCED; break; case AVL_BALANCED: ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED; ((AvlNode *)bitree_data(left)) ->factor = AVL_BALANCED; break; case AVL_RGT_HEAVY: ((AvlNode *)bitree_data(*node)) ->factor = AVL_BALANCED; ((AvlNode *)bitree_data(left)) ->factor = AVL_LFT_HEAVY; break; default: break; } ((AvlNode *)bitree_data(grandchild)) ->factor = AVL_BALANCED; *node = grandchild; } return; }
书中代码略晦涩难懂。