本文所有代码均在仓库中,这是一个完整的由纯C语言实现的可以存储任意类型元素的数据结构的工程项目。



最后也是最重要的一点,数据结构的通用性和舒适的体验感,下面以平衡二叉树为例:
#include "tree-structure/balanced-binary-tree/BalancedBinaryTree.h"
#include "tree-structure/balanced-binary-tree/BalancedBinaryTree.h"
int dataCompare(void *, void *);
typedef struct People {
char *name;
int age;
} *People;
int main(int argc, char **argv) {
struct People dataList[] = {
{"张三", 15},
{"李四", 3},
{"王五", 7},
{"赵六", 10},
{"田七", 9},
{"周八", 8},
};
BalancedBinaryTree tree = balancedBinaryTreeConstructor(NULL, 0, dataCompare);
for (int i = 0; i < 6; ++i) {
balancedBinaryTreeInsert(&tree, dataList + i, dataCompare);
}
return 0;
}
/**
* 根据人的年龄比较
*/
int dataCompare(void *data1, void *data2) {
int sub = ((People) data1)->age - ((People) data2)->age;
if (sub > 0) {
return 1;
} else if (sub < 0) {
return -1;
} else {
return 0;
}
}
#include "tree-structure/balanced-binary-tree/BalancedBinaryTree.h"
int dataCompare(void *, void *);
void dataPrint(void *);
typedef struct People {
char *name;
int age;
} *People;
int main(int argc, char **argv) {
struct People dataList[] = {
{"张三", 15},
{"李四", 3},
{"王五", 7},
{"赵六", 10},
{"田七", 9},
{"周八", 8},
};
BalancedBinaryTree tree = balancedBinaryTreeConstructor(NULL, 0, dataCompare);
for (int i = 0; i < 6; ++i) {
balancedBinaryTreeInsert(&tree, dataList + i, dataCompare);
balancedBinaryTreePrint(tree, dataPrint);
printf("-------------\n");
}
return 0;
}
/**
* 根据人的年龄比较
*/
int dataCompare(void *data1, void *data2) {
int sub = ((People) data1)->age - ((People) data2)->age;
if (sub > 0) {
return 1;
} else if (sub < 0) {
return -1;
} else {
return 0;
}
}
/**
* 打印人的年龄
* @param data
*/
void dataPrint(void *data) {
People people = (People) data;
printf("%d", people->age);
}
打印的结果如下:

最后期待大佬们的点赞。
树是由 n n n个结点组成的有限集,其中每个结点有零个或多个子结点以及零个或一个父结点,没有父结点的结点称为根结点,每一个非根结点有且只有一个父结点。除根结点外的其余结点可以分为 m m m个互不相交的有限集,其中每个有限集本身就是一棵树,这些树又称为根的子树。森林就是 m m m棵不相交的树的集合,树一定是森林,但森林不一定是树。

树一般有以下三种存储方式:
双亲表示法采用一组连续的空间存储每一个结点,同时在每个结点中增设一个伪指针,这个伪指针指向其双亲结点在连续空间中的位置:

struct ParentTreeNode {
void *data;
int parent;
};
struct ParentTree {
struct ParentTreeNode *nodeList;
int size;
int nodeCount;
};
在孩子表示法中,每个结点不再增设一个伪指针,而是增设一个存储当前结点孩子下标的链表:

struct ChildTreeNode {
void *data;
int index; //表示当前接结点在数组中的位置,仅在链表中使用
struct ChildTreeNode *child;
};
struct ChildTree {
struct ChildTreeNode *nodeList;
int size;
int nodeCount;
};
孩子兄弟表示法又称为二叉树表示法,它采用二叉链表作为树的存储结构,其中每个结点包含三部分内容:结点值、指向第一个孩子结点的指针以及指向下一个兄弟结点的指针:

struct ChildSiblingTreeNode {
void *data;
struct ChildSiblingTreeNode *firstChild;
struct ChildSiblingTreeNode *nextSibling;
};
二叉树是指每个结点最多只有两棵子树且子树之间顺序不能颠倒的树,这两棵子树分别称为左子树和右子树。二叉树与度为 2 2 2的有序树的区别如下:
二叉树的性质如下:

二叉树的顺序存储是指用一组地址连续的存储单元依次自上而下、自左向右存储完全二叉树上的结点元素,这样树中结点的序号就可以唯一反应结点之间的关系。对于不是完全二叉树的二叉树,需要填充空结点让其每个结点与完全二叉树上的结点对应。因此非完全二叉树的二叉树通常采用链式存储,链表结点至少包含三个域:数据域、左孩子指针域和右孩子指针域。还可以增加一个指针域指向其双亲。
struct BinaryTreeNode {
void *data;
struct BinaryTreeNode *lNode;
struct BinaryTreeNode *rNode;
};
遍历一棵二叉树要决定对根结点N、左子树L和右子树R的访问顺序,常见的访问顺序如下:
void preOrder(BinaryTree tree, LinkedQueue preOrderList) {
if (tree != NULL) {
linkedQueueEnQueue(preOrderList, tree->data);
preOrder(tree->lNode, preOrderList);
preOrder(tree->rNode, preOrderList);
}
}
void inOrder(BinaryTree tree, LinkedQueue inOrderList) {
if (tree != NULL) {
inOrder(tree->lNode, inOrderList);
linkedQueueEnQueue(inOrderList, tree->data);
inOrder(tree->rNode, inOrderList);
}
}
void postOrder(BinaryTree tree, LinkedQueue postOrderList) {
if (tree != NULL) {
postOrder(tree->lNode, postOrderList);
postOrder(tree->rNode, postOrderList);
linkedQueueEnQueue(postOrderList, tree->data);
}
}
void levelOrder(BinaryTree tree, LinkedQueue levelOrderList) {
LinkedQueue queue = linkedQueueConstructor();
linkedQueueEnQueue(queue, tree);
while (!linkedQueueIsEmpty(queue)) {
BinaryTreeNode *node = linkedQueueDeQueue(queue);
linkedQueueEnQueue(levelOrderList, node->data);
if (node->lNode != NULL) {
linkedQueueEnQueue(queue, node->lNode);
}
if (node->rNode != NULL) {
linkedQueueEnQueue(queue, node->rNode);
}
}
}
由二叉树的以下遍历序列组合可以唯一确认一棵二叉树(此外,如果将二叉树的某一遍历序列使用填充元素填充为满二叉树的相同遍历序列,那么也可以唯一确定一棵二叉树):
以先序和中序序列为例描述一下算法思想:
/**
* 前序中序构造
* @param preOrderList 前序序列
* @param inOrderList 中序序列
* @param compare 比较函数
* @param ps 前序起始位置
* @param pe 前序结束位置
* @param is 中序起始位置
* @param ie 中序结束位置
* @return 二叉树
*/
BinaryTree binaryTreePreInOrderConstructor(void **preOrderList, void **inOrderList, int (*compare)(void *, void *), int ps, int pe, int is, int ie) {
BinaryTreeNode *root = malloc(sizeof(BinaryTreeNode));
root->data = preOrderList[ps - 1];
int lLen, rLen;
for (int i = is; i <= ie; ++i) {
if (compare(inOrderList[i - 1], root->data)) {
lLen = i - is;
rLen = ie - i;
break;
}
}
if (lLen) {
root->lNode = binaryTreePreInOrderConstructor(preOrderList, inOrderList, compare, ps + 1, ps + lLen, is, is + lLen - 1);
} else {
root->lNode = NULL;
}
if (rLen) {
root->rNode = binaryTreePreInOrderConstructor(preOrderList, inOrderList, compare, pe - rLen + 1, pe, ie - rLen + 1, ie);
} else {
root->rNode = NULL;
}
return root;
}
由于二叉树的结构简单、规律性最强,因此在处理树和森林时一般将它们转换成一个唯一的二叉树进行。由于树和二叉树都可以使用二叉链表表示,那么就可以以二叉链表做媒介来进行转化。
每一层的结点数都达到最大值的二叉树称为满二叉树,满二叉树的性质如下:

一棵高度为 h h h含有 n n n个结点的二叉树,对树中的结点自上而下,自左到右从 1 1 1开始编号,如果编号为 i i i的结点与满二叉树中编号为 i i i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。完全二叉树的性质如下:

在含有 n n n个结点的二叉树中,含有 n + 1 n+1 n+1个空指针域。线索化是指利用这些空指针域存放指向结点的前驱和后继的指针,它的规则如下:
此外还需要增加两个标志位标识指针域是指向左右孩子还是指向前驱后继,最好再添加一个指针域指向其父结点。
struct ThreadedBinaryTreeNode {
void *data;
ThreadedBinaryTreeNode *lNode;
ThreadedBinaryTreeNode *rNode;
ThreadedBinaryTreeNode *pNode;
bool lIsPredecessor;
bool rIsSuccessor;
};

构造一棵线索二叉树分为两步:
ThreadTreeThreadTree转换成一个真正的线索二叉树以前序线索化为例,它的算法思想为:
tree指针指向当前访问的结点,predecessor指针指向tree的前驱tree的左指针是否为空,若为空则将其指向predecessorpredecessor 的右指针是否为空,若为空则将其指向tree/**
* 先序线索化
* @param tree
* @param predecessor
* @return
*/
ThreadedBinaryTree preOrderThreaded(ThreadedBinaryTree tree, ThreadedBinaryTreeNode *predecessor) {
if (tree != NULL) {
if (tree->lNode == NULL) {
tree->lNode = predecessor;
tree->lIsPredecessor = true;
}
if (predecessor != NULL && predecessor->rNode == NULL) {
predecessor->rNode = tree;
predecessor->rIsSuccessor = true;
}
predecessor = tree;
if (tree->lIsPredecessor == false) {
preOrderThreaded(tree->lNode, predecessor);
}
if (tree->rIsSuccessor == false) {
preOrderThreaded(tree->rNode, predecessor);
}
}
}
以前序线序哦二叉树为例,寻找tree结点前驱的算法思想如下:
tree->lIsPredecessor == true,则直接返回其左孩子tree的左孩子不指向其前驱:
tree是其父结点的左孩子,则直接返回其父结点tree是其父结点的右孩子
/**
* 寻找前序序列的前驱
* @param tree
* @return
*/
ThreadedBinaryTreeNode *preOrderFirstNode(ThreadedBinaryTree tree) {
if (tree->lIsPredecessor == true) {
return tree->lNode;
} else {
ThreadedBinaryTreeNode *parent = tree->pNode;
if (parent->lNode == tree) {
return parent;
} else {
if (parent->lIsPredecessor == true || parent->lNode == NULL) {
return parent;
} else {
ThreadedBinaryTreeNode *node = parent->lNode;
while (node != NULL) {
if (node->rNode == tree) {
break;
} else if (node->rNode != NULL) {
node = node->rNode;
} else if (node->lIsPredecessor == false && node->lNode != NULL) {
node = node->lNode;
}
}
return node;
}
}
}
}
寻找后继的算法思想如下:
tree->rIsSuccessor == true,则直接返回其右孩子tree的右孩子不指向其后继:
tree->lIsPredecessor == false && tree->lNode != NULL,返回其左孩子/**
* 寻找前序序列的后继
* @param tree
* @return
*/
ThreadedBinaryTreeNode *preOrderNextNode(ThreadedBinaryTree tree) {
if (tree->rIsSuccessor == true) {
return tree->rNode;
} else {
if (tree->lIsPredecessor == false && tree->lNode != NULL) {
return tree->lNode;
} else {
return tree->rNode;
}
}
以前序线序哦二叉树为例,前序线索二叉树中包含了二叉树的前驱和后继的信息,在对其进行遍历时,只需要找到前序序列中的第一个结点,然后依次找结点的后继,直至其后继为空。
/**
* 线索二叉树前序遍历
* @param tree
* @param queue
*/
void threadedBinaryTreePreOrder(ThreadedBinaryTree tree, LinkedQueue queue) {
for (ThreadedBinaryTreeNode *node = tree; node != NULL; node = preOrderNextNode(node)) {
linkedQueueEnQueue(queue, node->data);
}
}
如果给树中结点赋一个有某种含义的数值,则这个数值称为该结点的权。结点的权和根结点到该结点的路径长度的乘积称为结点的带权路径长度,树的带权路径长度是树中所有叶子结点带权路径长度之和。带权路径长度最小的二叉树称为最优二叉树。最优二叉树的特点如下:
struct HuffmanTreeNode {
void *data;
void *weight;
struct HuffmanTreeNode *lNode;
struct HuffmanTreeNode *rNode;
};

给定 n n n个结点以及它们的权值,那么构造过程如下:
/**
* 构造哈夫曼树
* @param dataList 数据列表
* @param weightList 权值列表
* @param size 大小
* @param reCompare 权值逆序比较
* @param weightSum 权值相加
* @return
*/
HuffmanTree huffmanTreeNodeConstructor(void *dataList[], void *weightList[], int size, int (*reCompare)(void *, void *), void *(*weightSum)(void *, void *)) {
HuffmanTreeNode *forest[size];
int treeCount = 0;
for (int i = 0; i < size; ++i) {
HuffmanTreeNode *node = malloc(sizeof(HuffmanTreeNode));
node->data = dataList[i];
node->weight = weightList[i];
node->lNode = NULL;
node->rNode = NULL;
forest[i] = node;
treeCount++;
}
sorted(forest, size, reCompare);
for (; treeCount != 1;) {
HuffmanTreeNode *node = malloc(sizeof(HuffmanTreeNode));
node->lNode = forest[0];
forest[0] = NULL;
treeCount--;
node->rNode = forest[1];
forest[1] = NULL;
treeCount--;
node->data = NULL;
node->weight = weightSum(node->lNode->weight, node->rNode->weight);
forest[0] = node;
sorted(forest, size, reCompare);
}
return forest[0];
}
由哈夫曼树可以得到哈夫曼编码:
/**
* 是否是叶子结点
* @param node
* @return
*/
static bool isLeafNode(HuffmanTreeNode *node) {
return node->lNode == NULL && node->rNode == NULL;
}
/**
* 哈夫曼编码
* @param tree
* @param target
* @param compare
* @return
*/
char *huffmanCoding(HuffmanTree tree, void *target, int (*compare)(void *, void *)) {
if (tree != NULL) {
char *lr = huffmanCoding(tree->lNode, target, compare);
char *rr = huffmanCoding(tree->rNode, target, compare);
if (lr != NULL) {
char *code = calloc(strlen(lr) + 2, sizeof(char));
strcat(code, "0");
strcat(code, lr);
return code;
} else if (rr != NULL) {
char *code = calloc(strlen(rr) + 2, sizeof(char));
strcat(code, "1");
strcat(code, rr);
return code;
} else if (tree->lNode != NULL && isLeafNode(tree->lNode) && compare(tree->lNode->data, target) == 0) {
return "0";
} else if (tree->rNode != NULL && isLeafNode(tree->rNode) && compare(tree->rNode->data, target) == 0) {
return "1";
} else {
return NULL;
}
} else {
return NULL;
}
}
二叉排序树是满足以下性质的二叉树:
对二叉排序树进行中序遍历可以得到一个递增有序的有序序列。
struct SortedBinaryTreeNode {
void *data;
SortedBinaryTreeNode *lNode;
SortedBinaryTreeNode *rNode;
};
算法思想:
/**
* 二叉排序树的插入
* @param tree
* @param element
* @param compare
* @return
*/
bool sortedBinaryTreeInsert(SortedBinaryTree *tree, void *element, int (*compare)(void *, void *)) {
if ((*tree) == NULL) {
*tree = malloc(sizeof(SortedBinaryTreeNode));
(*tree)->data = element;
(*tree)->lNode = NULL;
(*tree)->rNode = NULL;
return true;
} else {
int cmpResult = compare(element, (*tree)->data);
if (cmpResult == 0) {
return false;
} else if (cmpResult > 0) {
if ((*tree)->rNode == NULL) {
SortedBinaryTreeNode *node = malloc(sizeof(SortedBinaryTreeNode));
node->data = element;
node->rNode = NULL;
node->rNode = NULL;
(*tree)->rNode = node;
return true;
} else {
return sortedBinaryTreeInsert(&(*tree)->rNode, element, compare);
}
} else {
if ((*tree)->lNode == NULL) {
SortedBinaryTreeNode *node = malloc(sizeof(SortedBinaryTreeNode));
node->data = element;
node->rNode = NULL;
node->rNode = NULL;
(*tree)->lNode = node;
return true;
} else {
return sortedBinaryTreeInsert(&(*tree)->lNode, element, compare);
}
}
}
}
算法思想:
/**
* 二叉排序树的查找
* @param tree
* @param element
* @param compare
* @return
*/
SortedBinaryTreeNode *sortedBinaryTreeSearch(SortedBinaryTree tree, void *element, int (*compare)(void *, void *)) {
if (tree == NULL) {
return NULL;
} else {
int cmpResult = compare(element, tree->data);
if (cmpResult == 0) {
return tree;
} else if (cmpResult > 0) {
return sortedBinaryTreeSearch(tree->rNode, element, compare);
} else {
return sortedBinaryTreeSearch(tree->lNode, element, compare);
}
}
}
算法思想:
/**
* 删除元素
* @param tree
* @param element
* @param compare
* @return
*/
bool sortedBinaryTreeDelete(SortedBinaryTree *tree, void *element, int (*compare)(void *, void *)) {
if (*tree == NULL) {
return false;
} else {
int cmpResult = compare(element, (*tree)->data);
if (cmpResult == 0) {
if ((*tree)->lNode == NULL && (*tree)->rNode == NULL) {
free(*tree);
*tree = NULL;
return true;
} else if ((*tree)->lNode == NULL) {
SortedBinaryTreeNode *node = (*tree);
*tree = (*tree)->rNode;
free(node);
return true;
} else if ((*tree)->rNode == NULL) {
SortedBinaryTreeNode *node = (*tree);
*tree = (*tree)->lNode;
free(node);
return true;
} else {
SortedBinaryTreeNode *node = (*tree)->rNode;
while (node->lNode != NULL) {
node = node->lNode;
}
(*tree)->data = node->data;
return sortedBinaryTreeDelete(&(*tree)->rNode, node->data, compare);
}
} else if (cmpResult > 0) {
return sortedBinaryTreeDelete(&(*tree)->rNode, element, compare);
} else {
return sortedBinaryTreeDelete(&(*tree)->lNode, element, compare);
}
}
}
结点的平衡因子定义如下:
平衡因子
=
左子树高
−
右子树高
平衡因子=左子树高-右子树高
平衡因子=左子树高−右子树高
树中任一结点的平衡因子的绝对值不超过
1
1
1的二叉树称为平衡二叉树,平衡二叉树避免了树高的过度增长,如果可以保证一棵二叉排序树为平衡二叉树,那么就可以减少搜索元素时比较的次数,从而提高二叉排序树的性能。
struct BalancedBinaryTreeNode {
void *data;
BalancedBinaryTreeNode *lNode;
BalancedBinaryTreeNode *rNode;
};
当对一棵平衡二叉树进行插入或删除操作时,有可能会导致平衡二叉树失衡,此时应该从插入或删除结点往回找到第一个不平衡结点,调整以该结点为根的子树,这棵被调整的树称为最小不平衡子树。平衡二叉树的失衡类型有以下四种,针对不同的类型有不同的调整策略。
void ll(BalancedBinaryTree *tree) {
BalancedBinaryTreeNode *rootNode = *tree;
BalancedBinaryTreeNode *lNode = rootNode->lNode;
BalancedBinaryTreeNode *lrNode = lNode->rNode;
*tree = lNode;
lNode->rNode = rootNode;
rootNode->lNode = lrNode;
}

void rr(BalancedBinaryTree *tree) {
BalancedBinaryTreeNode *rootNode = *tree;
BalancedBinaryTreeNode *rNode = rootNode->rNode;
BalancedBinaryTreeNode *rlNode = rNode->lNode;
*tree = rNode;
rNode->lNode = rootNode;
rootNode->rNode = rlNode;
}

void lr(BalancedBinaryTree *tree) {
BalancedBinaryTreeNode *rootNode = *tree;
BalancedBinaryTreeNode *lNode = rootNode->lNode;
BalancedBinaryTreeNode *lrNode = lNode->rNode;
BalancedBinaryTreeNode *lrlNode = lrNode->lNode;
BalancedBinaryTreeNode *lrrNode = lrNode->rNode;
*tree = lrNode;
lrNode->lNode = lNode;
lrNode->rNode = rootNode;
lNode->rNode = lrlNode;
rootNode->lNode = lrrNode;
}

void rl(BalancedBinaryTree *tree) {
BalancedBinaryTreeNode *rootNode = *tree;
BalancedBinaryTreeNode *rNode = rootNode->rNode;
BalancedBinaryTreeNode *rlNode = rNode->lNode;
BalancedBinaryTreeNode *rllNode = rlNode->lNode;
BalancedBinaryTreeNode *rlrNode = rlNode->rNode;
*tree = rlNode;
rlNode->lNode = rootNode;
rlNode->rNode = rNode;
rNode->lNode = rlrNode;
rootNode->rNode = rllNode;
}

最后是失衡调整算法,在这个算法中只需要判断失衡类型是哪种并调用相应的算法即可:
void imbalanceAdjust(BalancedBinaryTree *tree) {
int lDeep = balancedBinaryTreeDeep((*tree)->lNode);
int rDeep = balancedBinaryTreeDeep((*tree)->rNode);
int balance = lDeep - rDeep;
if (balance > 1) {
lDeep = balancedBinaryTreeDeep((*tree)->lNode->lNode);
rDeep = balancedBinaryTreeDeep((*tree)->lNode->rNode);
//左左和左右
if (lDeep > rDeep) {
ll(tree);
} else {
lr(tree);
}
} else if (balance < -1) {
lDeep = balancedBinaryTreeDeep((*tree)->rNode->lNode);
rDeep = balancedBinaryTreeDeep((*tree)->rNode->rNode);
//右右和右左
if (rDeep > lDeep) {
rr(tree);
} else {
rl(tree);
}
} else {
return;
}
}
对于平衡二叉树的插入而言,只要调整第一棵最小不平衡子树,只要第一棵最小不平衡子树恢复了平衡,那么整棵树就恢复了平衡。
/**
* 二叉排序树的插入
* @param tree
* @param element
* @param compare
* @return
*/
bool balancedBinaryTreeInsert(BalancedBinaryTree *tree, void *element, int (*compare)(void *, void *)) {
if ((*tree) == NULL) {
*tree = malloc(sizeof(BalancedBinaryTreeNode));
(*tree)->data = element;
(*tree)->lNode = NULL;
(*tree)->rNode = NULL;
return true;
} else {
int cmpResult = compare(element, (*tree)->data);
if (cmpResult == 0) {
return false;
} else if (cmpResult > 0) {
if ((*tree)->rNode == NULL) {
BalancedBinaryTreeNode *node = malloc(sizeof(BalancedBinaryTreeNode));
node->data = element;
node->rNode = NULL;
node->rNode = NULL;
(*tree)->rNode = node;
return true;
} else {
bool result = balancedBinaryTreeInsert(&(*tree)->rNode, element, compare);
imbalanceAdjust(tree);
return result;
}
} else {
if ((*tree)->lNode == NULL) {
BalancedBinaryTreeNode *node = malloc(sizeof(BalancedBinaryTreeNode));
node->data = element;
node->rNode = NULL;
node->rNode = NULL;
(*tree)->lNode = node;
return true;
} else {
bool result = balancedBinaryTreeInsert(&(*tree)->lNode, element, compare);
imbalanceAdjust(tree);
return result;
}
}
}
}
对于平衡二叉树的删除而言,需要在被删除的结点处一直向上回溯,找到所有最小不平衡子树并进行失衡调整。
/**
* 删除元素
* @param tree
* @param element
* @param compare
* @return
*/
bool balancedBinaryTreeDelete(BalancedBinaryTree *tree, void *element, int (*compare)(void *, void *)) {
if (*tree == NULL) {
return false;
} else {
int cmpResult = compare(element, (*tree)->data);
if (cmpResult == 0) {
if ((*tree)->lNode == NULL && (*tree)->rNode == NULL) {
free(*tree);
*tree = NULL;
return true;
} else if ((*tree)->lNode == NULL) {
BalancedBinaryTreeNode *node = (*tree);
*tree = (*tree)->rNode;
free(node);
return true;
} else if ((*tree)->rNode == NULL) {
BalancedBinaryTreeNode *node = (*tree);
*tree = (*tree)->lNode;
free(node);
return true;
} else {
BalancedBinaryTreeNode *node = (*tree)->rNode;
while (node->lNode != NULL) {
node = node->lNode;
}
(*tree)->data = node->data;
bool result = balancedBinaryTreeDelete(&(*tree)->rNode, node->data, compare);
imbalanceAdjust(tree);
return result;
}
} else if (cmpResult > 0) {
bool result = balancedBinaryTreeDelete(&(*tree)->rNode, element, compare);
imbalanceAdjust(tree);
return result;
} else {
bool result = balancedBinaryTreeDelete(&(*tree)->lNode, element, compare);
imbalanceAdjust(tree);
return result;
}
}
}
虽然平衡二叉树可以保证二叉排序树的性能,但是频繁的平衡调整代价较大,为此在平衡二叉树上放宽了条件,引入了红黑树,红黑树是具有以下性质的二叉排序树:
struct RedBlackTreeNode {
void *data;
RedBlackTreeNode *lNode;
RedBlackTreeNode *rNode;
RedBlackTreeNode *pNode;
int color;
};
红黑树的性质如下:
红黑树插入的算法思想如下:①先查找,确定插入的位置(和二叉搜索树相同)。②插入结点是根结点则染成黑色,否则就染成红色。③如果插入新结点后满足红黑树的定义,则插入结束,否则就进行调整(此时只可能违反红黑树的第四条性质)。针对不同的类型有不同的调整策略:
static void ll(RedBlackTree *tree) {
RedBlackTreeNode *rootNode = *tree;
RedBlackTreeNode *rootPNode = (*tree)->pNode;
RedBlackTreeNode *lNode = rootNode->lNode;
RedBlackTreeNode *lrNode = lNode->rNode;
*tree = lNode;
lNode->pNode = rootPNode;
lNode->rNode = rootNode;
rootNode->pNode = lNode;
rootNode->lNode = lrNode;
if (lrNode != NULL) {
lrNode->pNode = rootNode;
}
reverseColor(rootNode);
reverseColor(lNode);
}
static void rr(RedBlackTree *tree) {
RedBlackTreeNode *rootNode = *tree;
RedBlackTreeNode *rootPNode = (*tree)->pNode;
RedBlackTreeNode *rNode = rootNode->rNode;
RedBlackTreeNode *rlNode = rNode->lNode;
*tree = rNode;
rNode->pNode = rootPNode;
rNode->lNode = rootNode;
rootNode->pNode = rNode;
rootNode->rNode = rlNode;
if (rlNode != NULL) {
rlNode->pNode = rootNode;
}
reverseColor(rootNode);
reverseColor(rNode);
}
static void lr(RedBlackTree *tree) {
RedBlackTreeNode *rootNode = *tree;
RedBlackTreeNode *rootPNode = (*tree)->pNode;
RedBlackTreeNode *lNode = rootNode->lNode;
RedBlackTreeNode *lrNode = lNode->rNode;
RedBlackTreeNode *lrlNode = lrNode->lNode;
RedBlackTreeNode *lrrNode = lrNode->rNode;
*tree = lrNode;
lrNode->pNode = rootPNode;
lrNode->lNode = lNode;
lNode->pNode = lrNode;
lrNode->rNode = rootNode;
rootNode->pNode = lrNode;
lNode->rNode = lrlNode;
if (lrlNode != NULL) {
lrlNode->pNode = lNode;
}
rootNode->lNode = lrrNode;
if (lrrNode != NULL) {
lrrNode->pNode = rootNode;
}
reverseColor(rootNode);
reverseColor(lrNode);
}
static void rl(RedBlackTree *tree) {
RedBlackTreeNode *rootNode = *tree;
RedBlackTreeNode *rootPNode = (*tree)->pNode;
RedBlackTreeNode *rNode = rootNode->rNode;
RedBlackTreeNode *rlNode = rNode->lNode;
RedBlackTreeNode *rllNode = rlNode->lNode;
RedBlackTreeNode *rlrNode = rlNode->rNode;
*tree = rlNode;
rlNode->pNode = rootPNode;
rlNode->lNode = rootNode;
rootNode->pNode = rlNode;
rlNode->rNode = rNode;
rNode->pNode = rlNode;
rNode->lNode = rlrNode;
if (rlrNode != NULL) {
rlrNode->pNode = rNode;
}
rootNode->rNode = rllNode;
if (rllNode != NULL) {
rllNode->pNode = rootNode;
}
reverseColor(rootNode);
reverseColor(rlNode);
}
完整的失衡调整代码如下:
static void imbalanceAdjust(RedBlackTree tree, RedBlackTree *root) {
RedBlackTreeNode *fatherNode = tree->pNode;
if (fatherNode == NULL) {
return;
}
RedBlackTreeNode *grandFatherNode = fatherNode->pNode;
if (grandFatherNode == NULL) {
return;
}
RedBlackTreeNode *uncleNode = grandFatherNode->lNode == fatherNode ? grandFatherNode->rNode : grandFatherNode->lNode;
if (!(tree->color == RED && fatherNode->color == RED)) {
return;
}
if (uncleNode == NULL || uncleNode->color == BLACK) {
if (grandFatherNode->lNode == fatherNode) {
if (fatherNode->lNode == tree) {
if (grandFatherNode->pNode == NULL) {
ll(root);
} else {
ll(grandFatherNode->pNode->lNode == grandFatherNode ? &(grandFatherNode->pNode->lNode) : &(grandFatherNode->pNode->rNode));
}
} else {
if (grandFatherNode->pNode == NULL) {
lr(root);
} else {
lr(grandFatherNode->pNode->lNode == grandFatherNode ? &(grandFatherNode->pNode->lNode) : &(grandFatherNode->pNode->rNode));
}
}
} else {
if (fatherNode->rNode == tree) {
if (grandFatherNode->pNode == NULL) {
rr(root);
} else {
rr(grandFatherNode->pNode->lNode == grandFatherNode ? &(grandFatherNode->pNode->lNode) : &(grandFatherNode->pNode->rNode));
}
} else {
if (grandFatherNode->pNode == NULL) {
rl(root);
} else {
rl(grandFatherNode->pNode->lNode == grandFatherNode ? &(grandFatherNode->pNode->lNode) : &(grandFatherNode->pNode->rNode));
}
}
}
} else {
reverseColor(grandFatherNode);
reverseColor(fatherNode);
reverseColor(uncleNode);
if (grandFatherNode->pNode == NULL) {
grandFatherNode->color = BLACK;
} else {
imbalanceAdjust(grandFatherNode, root);
}
}
}
完整的插入代码如下:
static bool insert(RedBlackTree *tree, RedBlackTree *root, void *element, int (*compare)(void *, void *)) {
if ((*tree) == NULL) {
*tree = malloc(sizeof(RedBlackTreeNode));
(*tree)->data = element;
(*tree)->lNode = NULL;
(*tree)->rNode = NULL;
(*tree)->pNode = NULL;
(*tree)->color = BLACK;
return true;
} else {
int cmpResult = compare(element, (*tree)->data);
if (cmpResult == 0) {
return false;
} else if (cmpResult > 0) {
if ((*tree)->rNode == NULL) {
RedBlackTreeNode *node = malloc(sizeof(RedBlackTreeNode));
node->data = element;
node->rNode = NULL;
node->rNode = NULL;
node->pNode = *tree;
node->color = RED;
(*tree)->rNode = node;
imbalanceAdjust(node, root);
return true;
} else {
return insert(&(*tree)->rNode, root, element, compare);
}
} else {
if ((*tree)->lNode == NULL) {
RedBlackTreeNode *node = malloc(sizeof(RedBlackTreeNode));
node->data = element;
node->rNode = NULL;
node->rNode = NULL;
node->pNode = *tree;
node->color = RED;
(*tree)->lNode = node;
imbalanceAdjust(node, root);
return true;
} else {
return insert(&(*tree)->lNode, root, element, compare);
}
}
}
}
/**
* 二叉排序树的插入
* @param tree
* @param element
* @param compare
* @return
*/
bool redBlackTreeInsert(RedBlackTree *tree, void *element, int (*compare)(void *, void *)) {
return insert(tree, tree, element, compare);
}
B树又称为多路平衡查找树,B数中所有结点的孩子个数的最大值称为B树的阶,通常用 m m m表示,B树要么是空树,要么是满足以下条件的 m m m叉树:
struct BTreeNode {
void **dataList;
BTreeNode **childList;
int dataCount;
};