btree.h

  1. //实现对order序(阶)的B-TREE结构基本操作的封装。
  2. //查找:search,插入:insert,删除:remove。
  3. //创建:create,销毁:destory,打印:print。
  4. #ifndef BTREE_H
  5. #define BTREE_H
  6.  
  7. #ifdef __cplusplus
  8. extern "C" {
  9. #endif
  10.  
  11. ////* 定义m序(阶)B 树的最小度数BTree_D=ceil(m)*/
  12. /// 在这里定义每个节点中关键字的最大数目为:2 * BTree_D - 1,即序(阶):2 * BTree_D.
  13. #define BTree_D 2
  14. #define ORDER (BTree_D * 2) //定义为4阶B-tree,2-3-4树。最简单为3阶B-tree,2-3树。
  15. //#define ORDER (BTree_T * 2-1) //最简单为3阶B-tree,2-3树。
  16.  
  17. typedef int KeyType;
  18. typedef struct BTNode{
  19. int keynum; /// 结点中关键字的个数,keynum <= BTree_N
  20. KeyType key[ORDER-1]; /// 关键字向量为key[0..keynum - 1]
  21. struct BTNode* child[ORDER]; /// 孩子指针向量为child[0..keynum]
  22. bool isLeaf; /// 是否是叶子节点的标志
  23. }BTNode;
  24.  
  25. typedef BTNode* BTree; ///定义BTree
  26.  
  27. ///给定数据集data,创建BTree。
  28. void BTree_create(BTree* tree, const KeyType* data, int length);
  29.  
  30. ///销毁BTree,释放内存空间。
  31. void BTree_destroy(BTree* tree);
  32.  
  33. ///在BTree中插入关键字key。
  34. void BTree_insert(BTree* tree, KeyType key);
  35.  
  36. ///在BTree中移除关键字key。
  37. void BTree_remove(BTree* tree, KeyType key);
  38.  
  39. ///深度遍历BTree打印各层结点信息。
  40. void BTree_print(const BTree tree, int layer=1);
  41.  
  42. /// 在BTree中查找关键字 key,
  43. /// 成功时返回找到的节点的地址及 key 在其中的位置 *pos
  44. /// 失败时返回 NULL 及查找失败时扫描到的节点位置 *pos
  45. BTNode* BTree_search(const BTree tree, int key, int* pos);
  46.  
  47. #ifdef __cplusplus
  48. }
  49. #endif
  50.  
  51. #endif

  

btree.c

  1. //实现对order序(阶)的B-TREE结构基本操作的封装。
  2. //查找:search,插入:insert,删除:remove。
  3. //创建:create,销毁:destory,打印:print。
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <assert.h>
  7. #include "btree.h"
  8.  
  9. //#define max(a, b) (((a) > (b)) ? (a) : (b))
  10. #define cmp(a, b) ( ( ((a)-(b)) >= (0) ) ? (1) : (0) ) //比较a,b大小
  11. #define DEBUG_BTREE
  12.  
  13. // 模拟向磁盘写入节点
  14. void disk_write(BTNode* node)
  15. {
  16. //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。
  17. printf("向磁盘写入节点");
  18. for(int i=0;i<ORDER-1;i++){
  19. printf("%c",node->key[i]);
  20. }
  21. printf("\n");
  22. }
  23.  
  24. // 模拟从磁盘读取节点
  25. void disk_read(BTNode** node)
  26. {
  27. //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。
  28. printf("向磁盘读取节点");
  29. for(int i=0;i<ORDER-1;i++){
  30. printf("%c",(*node)->key[i]);
  31. }
  32. printf("\n");
  33. }
  34.  
  35. // 按层次打印 B 树
  36. void BTree_print(const BTree tree, int layer)
  37. {
  38. int i;
  39. BTNode* node = tree;
  40.  
  41. if (node) {
  42. printf("第 %d 层, %d node : ", layer, node->keynum);
  43.  
  44. //打印出结点中的全部元素,方便调试查看keynum之后的元素是否为0(即是否存在垃圾数据);而不是keynum个元素。
  45. for (i = 0; i < ORDER-1; ++i) {
  46. //for (i = 0; i < node->keynum; ++i) {
  47. printf("%c ", node->key[i]);
  48. }
  49.  
  50. printf("\n");
  51.  
  52. ++layer;
  53. for (i = 0 ; i <= node->keynum; i++) {
  54. if (node->child[i]) {
  55. BTree_print(node->child[i], layer);
  56. }
  57. }
  58. }
  59. else {
  60. printf("树为空。\n");
  61. }
  62. }
  63.  
  64. // 结点node内对关键字进行二分查找。
  65. int binarySearch(BTNode* node, int low, int high, KeyType Fkey)
  66. {
  67. int mid;
  68. while (low<=high)
  69. {
  70. mid = low + (high-low)/2;
  71. if (Fkey<node->key[mid])
  72. {
  73. high = mid-1;
  74. }
  75. if (Fkey>node->key[mid])
  76. {
  77. low = mid+1;
  78. }
  79. if (Fkey==node->key[mid])
  80. {
  81. return mid;//返回下标。
  82. }
  83. }
  84. return 0;//未找到返回0.
  85. }
  86.  
  87. /***************************************************************************************
  88. 将分裂的结点中的一半元素给新建的结点,并且将分裂结点中的中间关键字元素上移至父节点中。
  89. parent 是一个非满的父节点
  90. node 是 tree 孩子表中下标为 index 的孩子节点,且是满的,需分裂。
  91. 分裂确保有序的情况下是均衡的
  92. *******************************************************************/
  93. void BTree_split_child(BTNode* parent, int index, BTNode* node)
  94. {
  95. #ifdef DEBUG_BTREE
  96. printf("BTree_split_child!\n");
  97. #endif
  98. assert(parent && node);
  99. int i;
  100.  
  101. // 创建新节点,存储 node 中后半部分的数据
  102. BTNode* newNode = (BTNode*)calloc(sizeof(BTNode), 1);
  103. if (!newNode) {
  104. printf("Error! out of memory!\n");
  105. return;
  106. }
  107.  
  108. newNode->isLeaf = node->isLeaf;
  109. newNode->keynum = BTree_D - 1;
  110.  
  111. // 拷贝 node 后半部分关键字,然后将node后半部分置为0。
  112. for (i = 0; i < newNode->keynum; ++i){
  113. newNode->key[i] = node->key[BTree_D + i];
  114. node->key[BTree_D + i] = 0;
  115. }
  116.  
  117. // 如果 node 不是叶子节点,拷贝 node 后半部分的指向孩子节点的指针,然后将node后半部分指向孩子节点的指针置为NULL。
  118. if (!node->isLeaf) {
  119. for (i = 0; i < BTree_D; i++) {
  120. newNode->child[i] = node->child[BTree_D + i];
  121. node->child[BTree_D + i] = NULL;
  122. }
  123. }
  124.  
  125. // 将 node 分裂出 newNode 之后,里面的数据减半
  126. node->keynum = BTree_D - 1;
  127.  
  128. // 调整父节点中的指向孩子的指针和关键字元素。分裂时父节点增加指向孩子的指针和关键元素。
  129. for (i = parent->keynum; i > index; --i) {
  130. parent->child[i + 1] = parent->child[i];
  131. }
  132.  
  133. parent->child[index + 1] = newNode;
  134.  
  135. for (i = parent->keynum - 1; i >= index; --i) {
  136. parent->key[i + 1] = parent->key[i];
  137. }
  138.  
  139. parent->key[index] = node->key[BTree_D - 1];
  140. ++parent->keynum;
  141.  
  142. node->key[BTree_D - 1] = 0;
  143.  
  144. // 写入磁盘
  145. disk_write(parent);
  146. disk_write(newNode);
  147. disk_write(node);
  148. }
  149.  
  150. void BTree_insert_nonfull(BTNode* node, KeyType key)
  151. {
  152. assert(node);
  153.  
  154. int i;
  155.  
  156. // 节点是叶子节点,直接插入,如果比其他值小,那么移动其他值
  157. if (node->isLeaf) {
  158. i = node->keynum - 1;
  159. while (i >= 0 && key < node->key[i]) {
  160. node->key[i + 1] = node->key[i];
  161. --i;
  162. }
  163.  
  164. node->key[i + 1] = key;
  165. ++node->keynum;
  166.  
  167. // 写入磁盘
  168. disk_write(node);
  169. }
  170.  
  171. // 节点是内部节点
  172. else {
  173. /* 查找插入的位置*/
  174. i = node->keynum - 1;
  175. while (i >= 0 && key < node->key[i]) {
  176. --i;
  177. }
  178.  
  179. ++i;
  180.  
  181. // 从磁盘读取孩子节点
  182. disk_read(&node->child[i]);
  183.  
  184. // 如果该孩子节点已满,分裂调整值
  185. if (node->child[i]->keynum == (ORDER-1)) {
  186. BTree_split_child(node, i, node->child[i]);
  187. // 如果待插入的关键字大于该分裂结点中上移到父节点的关键字,在该关键字的右孩子结点中进行插入操作。
  188. if (key > node->key[i]) {
  189. ++i;
  190. }
  191. }
  192. BTree_insert_nonfull(node->child[i], key);
  193. }
  194. }
  195.  
  196. void BTree_insert(BTree* tree, KeyType key)
  197. {
  198. #ifdef DEBUG_BTREE
  199. printf("BTree_insert:\n");
  200. #endif
  201. BTNode* node;
  202. BTNode* root = *tree;
  203.  
  204. // 树为空
  205. if (NULL == root) {
  206. root = (BTNode*)calloc(sizeof(BTNode), 1);
  207. if (!root) {
  208. printf("Error! out of memory!\n");
  209. return;
  210. }
  211. root->isLeaf = true;
  212. root->keynum = 1;
  213. root->key[0] = key;
  214.  
  215. *tree = root;
  216.  
  217. // 写入磁盘
  218. disk_write(root);
  219.  
  220. return;
  221. }
  222.  
  223. // 根节点已满,插入前需要进行分裂调整
  224. if (root->keynum == (ORDER-1)) {
  225. // 产生新节点当作根
  226. node = (BTNode*)calloc(sizeof(BTNode), 1);
  227. if (!node) {
  228. printf("Error! out of memory!\n");
  229. return;
  230. }
  231.  
  232. *tree = node;
  233. node->isLeaf = false;
  234. node->keynum = 0;
  235. node->child[0] = root;
  236.  
  237. BTree_split_child(node, 0, root);
  238.  
  239. BTree_insert_nonfull(node, key);
  240. }
  241.  
  242. // 根节点未满,在当前节点中插入 key
  243. else {
  244. BTree_insert_nonfull(root, key);
  245. }
  246. }
  247. // 对 tree 中的节点 node 进行合并孩子节点处理.
  248. // 注意:孩子节点的 keynum 必须均已达到下限,即均等于 BTree_D - 1
  249. // 将 tree 中索引为 index 的 key 下移至左孩子结点中,
  250. // 将 node 中索引为 index + 1 的孩子节点合并到索引为 index 的孩子节点中,右孩子合并到左孩子结点中。
  251. // 并调相关的 key 和指针。
  252. void BTree_merge_child(BTree* tree, BTNode* node, int index)
  253. {
  254. #ifdef DEBUG_BTREE
  255. printf("BTree_merge_child!\n");
  256. #endif
  257. assert(tree && node && index >= 0 && index < node->keynum);
  258.  
  259. int i;
  260.  
  261. KeyType key = node->key[index];
  262. BTNode* leftChild = node->child[index];
  263. BTNode* rightChild = node->child[index + 1];
  264.  
  265. assert(leftChild && leftChild->keynum == BTree_D - 1
  266. && rightChild && rightChild->keynum == BTree_D - 1);
  267.  
  268. // 将 node中关键字下标为index 的 key 下移至左孩子结点中,该key所对应的右孩子结点指向node的右孩子结点中的第一个孩子。
  269. leftChild->key[leftChild->keynum] = key;
  270. leftChild->child[leftChild->keynum + 1] = rightChild->child[0];
  271. ++leftChild->keynum;
  272.  
  273. // 右孩子的元素合并到左孩子结点中。
  274. for (i = 0; i < rightChild->keynum; ++i) {
  275. leftChild->key[leftChild->keynum] = rightChild->key[i];
  276. leftChild->child[leftChild->keynum + 1] = rightChild->child[i + 1];
  277. ++leftChild->keynum;
  278. }
  279.  
  280. // 在 node 中下移的 key后面的元素前移
  281. for (i = index; i < node->keynum - 1; ++i) {
  282. node->key[i] = node->key[i + 1];
  283. node->child[i + 1] = node->child[i + 2];
  284. }
  285. node->key[node->keynum - 1] = 0;
  286. node->child[node->keynum] = NULL;
  287. --node->keynum;
  288.  
  289. // 如果根节点没有 key 了,并将根节点调整为合并后的左孩子节点;然后删除释放空间。
  290. if (node->keynum == 0) {
  291. if (*tree == node) {
  292. *tree = leftChild;
  293. }
  294.  
  295. free(node);
  296. node = NULL;
  297. }
  298.  
  299. free(rightChild);
  300. rightChild = NULL;
  301. }
  302.  
  303. void BTree_recursive_remove(BTree* tree, KeyType key)
  304. {
  305. // B-数的保持条件之一:
  306. // 非根节点的内部节点的关键字数目不能少于 BTree_D - 1
  307.  
  308. int i, j, index;
  309. BTNode *root = *tree;
  310. BTNode *node = root;
  311.  
  312. if (!root) {
  313. printf("Failed to remove %c, it is not in the tree!\n", key);
  314. return;
  315. }
  316.  
  317. // 结点中找key。
  318. index = 0;
  319. while (index < node->keynum && key > node->key[index]) {
  320. ++index;
  321. }
  322.  
  323. /*======================含有key的当前结点时的情况====================
  324. node:
  325. index of Key: i-1 i i+1
  326. +---+---+---+---+
  327. * key *
  328. +---+---+---+---+---+
  329. / \
  330. index of Child: i i+1
  331. / \
  332. +---+---+ +---+---+
  333. * * * *
  334. +---+---+---+ +---+---+---+
  335. leftChild rightChild
  336. ============================================================*/
  337. /*一、结点中找到了关键字key的情况.*/
  338. BTNode *leftChild, *rightChild;
  339. KeyType leftKey, rightKey;
  340. if (index < node->keynum && node->key[index] == key) {
  341. /* 1,所在节点是叶子节点,直接删除*/
  342. if (node->isLeaf) {
  343. for (i = index; i < node->keynum-1; ++i) {
  344. node->key[i] = node->key[i + 1];
  345. //node->child[i + 1] = node->child[i + 2];叶子节点的孩子结点为空,无需移动处理。
  346. }
  347. node->key[node->keynum-1] = 0;
  348. //node->child[node->keynum] = NULL;
  349. --node->keynum;
  350.  
  351. if (node->keynum == 0) {
  352. assert(node == *tree);
  353. free(node);
  354. *tree = NULL;
  355. }
  356.  
  357. return;
  358. }
  359. /*2.选择脱贫致富的孩子结点。*/
  360. // 2a,选择相对富有的左孩子结点。
  361. // 如果位于 key 前的左孩子结点的 key 数目 >= BTree_D,
  362. // 在其中找 key 的左孩子结点的最后一个元素上移至父节点key的位置。
  363. // 然后在左孩子节点中递归删除元素leftKey。
  364. else if (node->child[index]->keynum >= BTree_D) {
  365. leftChild = node->child[index];
  366. leftKey = leftChild->key[leftChild->keynum - 1];
  367. node->key[index] = leftKey;
  368.  
  369. BTree_recursive_remove(&leftChild, leftKey);
  370. }
  371. // 2b,选择相对富有的右孩子结点。
  372. // 如果位于 key 后的右孩子结点的 key 数目 >= BTree_D,
  373. // 在其中找 key 的右孩子结点的第一个元素上移至父节点key的位置
  374. // 然后在右孩子节点中递归删除元素rightKey。
  375. else if (node->child[index + 1]->keynum >= BTree_D) {
  376. rightChild = node->child[index + 1];
  377. rightKey = rightChild->key[0];
  378. node->key[index] = rightKey;
  379.  
  380. BTree_recursive_remove(&rightChild, rightKey);
  381. }
  382. /*左右孩子结点都刚脱贫。删除前需要孩子结点的合并操作*/
  383. // 2c,左右孩子结点只包含 BTree_D - 1 个节点,
  384. // 合并是将 key 下移至左孩子节点,并将右孩子节点合并到左孩子节点中,
  385. // 删除右孩子节点,在父节点node中移除 key 和指向右孩子节点的指针,
  386. // 然后在合并了的左孩子节点中递归删除元素key。
  387. else if (node->child[index]->keynum == BTree_D - 1
  388. && node->child[index + 1]->keynum == BTree_D - 1){
  389. leftChild = node->child[index];
  390.  
  391. BTree_merge_child(tree, node, index);
  392.  
  393. // 在合并了的左孩子节点中递归删除 key
  394. BTree_recursive_remove(&leftChild, key);
  395. }
  396. }
  397.  
  398. /*======================未含有key的当前结点时的情况====================
  399. node:
  400. index of Key: i-1 i i+1
  401. +---+---+---+---+
  402. * keyi *
  403. +---+---+---+---+---+
  404. / | \
  405. index of Child: i-1 i i+1
  406. / | \
  407. +---+---+ +---+---+ +---+---+
  408. * * * * * *
  409. +---+---+---+ +---+---+---+ +---+---+---+
  410. leftSibling Child rightSibling
  411. ============================================================*/
  412. /*二、结点中未找到了关键字key的情况.*/
  413. else {
  414. BTNode *leftSibling, *rightSibling, *child;
  415. // 3. key 不在内节点 node 中,则应当在某个包含 key 的子节点中。
  416. // key < node->key[index], 所以 key 应当在孩子节点 node->child[index] 中
  417. child = node->child[index];
  418. if (!child) {
  419. printf("Failed to remove %c, it is not in the tree!\n", key);
  420. return;
  421. }
  422. /*所需查找的该孩子结点刚脱贫的情况*/
  423. if (child->keynum == BTree_D - 1) {
  424. leftSibling = NULL;
  425. rightSibling = NULL;
  426.  
  427. if (index - 1 >= 0) {
  428. leftSibling = node->child[index - 1];
  429. }
  430.  
  431. if (index + 1 <= node->keynum) {
  432. rightSibling = node->child[index + 1];
  433. }
  434. /*选择致富的相邻兄弟结点。*/
  435. // 3a,如果所在孩子节点相邻的兄弟节点中有节点至少包含 BTree_D 个关键字
  436. // 将 node 的一个关键字key[index]下移到 child 中,将相对富有的相邻兄弟节点中一个关键字上移到
  437. // node 中,然后在 child 孩子节点中递归删除 key。 请看M
  438. if ((leftSibling && leftSibling->keynum >= BTree_D)
  439. || (rightSibling && rightSibling->keynum >= BTree_D)) {
  440. int richR = 0;
  441. if(rightSibling) richR = 1;
  442. if(leftSibling && rightSibling) {
  443. richR = cmp(rightSibling->keynum,leftSibling->keynum);
  444. }
  445. if (rightSibling && rightSibling->keynum >= BTree_D && richR) {
  446. //相邻右兄弟相对富有,则该孩子先向父节点借一个元素,右兄弟中的第一个元素上移至父节点所借位置,并进行相应调整。
  447. child->key[child->keynum] = node->key[index];
  448. child->child[child->keynum + 1] = rightSibling->child[0];
  449. ++child->keynum;
  450.  
  451. node->key[index] = rightSibling->key[0];
  452.  
  453. for (j = 0; j < rightSibling->keynum - 1; ++j) {//元素前移
  454. rightSibling->key[j] = rightSibling->key[j + 1];
  455. rightSibling->child[j] = rightSibling->child[j + 1];
  456. }
  457. rightSibling->key[rightSibling->keynum-1] = 0;
  458. rightSibling->child[rightSibling->keynum-1] = rightSibling->child[rightSibling->keynum];
  459. rightSibling->child[rightSibling->keynum] = NULL;
  460. --rightSibling->keynum;
  461. }
  462. else {//相邻左兄弟相对富有,则该孩子向父节点借一个元素,左兄弟中的最后元素上移至父节点所借位置,并进行相应调整。
  463. for (j = child->keynum; j > 0; --j) {//元素后移
  464. child->key[j] = child->key[j - 1];
  465. child->child[j + 1] = child->child[j];
  466. }
  467. child->child[1] = child->child[0];
  468. child->child[0] = leftSibling->child[leftSibling->keynum];
  469. child->key[0] = node->key[index - 1];
  470. ++child->keynum;
  471.  
  472. node->key[index - 1] = leftSibling->key[leftSibling->keynum - 1];
  473.  
  474. leftSibling->key[leftSibling->keynum - 1] = 0;
  475. leftSibling->child[leftSibling->keynum] = NULL;
  476.  
  477. --leftSibling->keynum;
  478. }
  479. }
  480. /*相邻兄弟结点都刚脱贫。删除前需要兄弟结点的合并操作,*/
  481. // 3b, 如果所在孩子节点相邻的兄弟节点都只包含 BTree_D - 1 个关键字,
  482. // 将 child 与其一相邻节点合并,并将 node 中的一个关键字下降到合并节点中,
  483. // 再在 node 中删除那个关键字和相关指针,若 node 的 key 为空,删之,并调整根为合并结点。
  484. // 最后,在相关孩子节点child中递归删除 key。
  485. else if ((!leftSibling || (leftSibling && leftSibling->keynum == BTree_D - 1))
  486. && (!rightSibling || (rightSibling && rightSibling->keynum == BTree_D - 1))) {
  487. if (leftSibling && leftSibling->keynum == BTree_D - 1) {
  488.  
  489. BTree_merge_child(tree, node, index - 1);//node中的右孩子元素合并到左孩子中。
  490.  
  491. child = leftSibling;
  492. }
  493.  
  494. else if (rightSibling && rightSibling->keynum == BTree_D - 1) {
  495.  
  496. BTree_merge_child(tree, node, index);//node中的右孩子元素合并到左孩子中。
  497. }
  498. }
  499. }
  500.  
  501. BTree_recursive_remove(&child, key);//调整后,在key所在孩子结点中继续递归删除key。
  502. }
  503. }
  504.  
  505. void BTree_remove(BTree* tree, KeyType key)
  506. {
  507. #ifdef DEBUG_BTREE
  508. printf("BTree_remove:\n");
  509. #endif
  510. if (*tree==NULL)
  511. {
  512. printf("BTree is NULL!\n");
  513. return;
  514. }
  515.  
  516. BTree_recursive_remove(tree, key);
  517. }
  518.  
  519. //=====================================search====================================
  520.  
  521. BTNode* BTree_recursive_search(const BTree tree, KeyType key, int* pos)
  522. {
  523. int i = 0;
  524.  
  525. while (i < tree->keynum && key > tree->key[i]) {
  526. ++i;
  527. }
  528.  
  529. // Find the key.
  530. if (i < tree->keynum && tree->key[i] == key) {
  531. *pos = i;
  532. return tree;
  533. }
  534.  
  535. // tree 为叶子节点,找不到 key,查找失败返回
  536. if (tree->isLeaf) {
  537. return NULL;
  538. }
  539.  
  540. // 节点内查找失败,但 tree->key[i - 1]< key < tree->key[i],
  541. // 下一个查找的结点应为 child[i]
  542.  
  543. // 从磁盘读取第 i 个孩子的数据
  544. disk_read(&tree->child[i]);
  545.  
  546. // 递归地继续查找于树 tree->child[i]
  547. return BTree_recursive_search(tree->child[i], key, pos);
  548. }
  549.  
  550. BTNode* BTree_search(const BTree tree, KeyType key, int* pos)
  551. {
  552. #ifdef DEBUG_BTREE
  553. printf("BTree_search:\n");
  554. #endif
  555. if (!tree) {
  556. printf("BTree is NULL!\n");
  557. return NULL;
  558. }
  559. *pos = -1;
  560. return BTree_recursive_search(tree,key,pos);
  561. }
  562.  
  563. //===============================create===============================
  564. void BTree_create(BTree* tree, const KeyType* data, int length)
  565. {
  566. assert(tree);
  567.  
  568. int i;
  569.  
  570. #ifdef DEBUG_BTREE
  571. printf("\n 开始创建 B-树,关键字为:\n");
  572. for (i = 0; i < length; i++) {
  573. printf(" %c ", data[i]);
  574. }
  575. printf("\n");
  576. #endif
  577.  
  578. for (i = 0; i < length; i++) {
  579. #ifdef DEBUG_BTREE
  580. printf("\n插入关键字 %c:\n", data[i]);
  581. #endif
  582. int pos = -1;
  583. BTree_search(*tree,data[i],&pos);//树的递归搜索,查看data[i]是否在树中,在树里,pos改为0。
  584. if (pos!=-1)
  585. {
  586. printf("this key %c is in the B-tree,not to insert.\n",data[i]);
  587. }else{
  588. BTree_insert(tree, data[i]);//插入元素到BTree中。
  589. }
  590.  
  591. #ifdef DEBUG_BTREE
  592. BTree_print(*tree);//树的深度遍历。
  593. #endif
  594. }
  595.  
  596. printf("\n");
  597. }
  598. //===============================destroy===============================
  599. void BTree_destroy(BTree* tree)
  600. {
  601. int i;
  602. BTNode* node = *tree;
  603.  
  604. if (node) {
  605. for (i = 0; i <= node->keynum; i++) {
  606. BTree_destroy(&node->child[i]);
  607. }
  608.  
  609. free(node);
  610. }
  611.  
  612. *tree = NULL;
  613. }
  614.  
  615. //测试order序(阶)的B-TREE结构基本操作。
  616. //查找:search,插入:insert,删除:remove。
  617. //创建:create,销毁:destory,打印:print。
  618.  
  619. #include <stdio.h>
  620. #include "btree.h"
  621.  
  622. void test_BTree_search(BTree tree, KeyType key)
  623. {
  624. int pos = -1;
  625. BTNode* node = BTree_search(tree, key, &pos);
  626. if (node) {
  627. printf("在%s节点(包含 %d 个关键字)中找到关键字 %c,其索引为 %d\n",
  628. node->isLeaf ? "叶子" : "非叶子",
  629. node->keynum, key, pos);
  630. }
  631. else {
  632. printf("在树中找不到关键字 %c\n", key);
  633. }
  634. }
  635.  
  636. void test_BTree_remove(BTree* tree, KeyType key)
  637. {
  638. printf("\n移除关键字 %c \n", key);
  639. BTree_remove(tree, key);
  640. BTree_print(*tree);
  641. printf("\n");
  642. }

  

test.c

  1. #include "btree.h"
  1. void test_btree()
  2. {
  3.  
  4. KeyType array[] = {
  5. 'G','G', 'M', 'P', 'X', 'A', 'C', 'D', 'E', 'J', 'K',
  6. 'N', 'O', 'R', 'S', 'T', 'U', 'V', 'Y', 'Z', 'F', 'X'
  7. };
  8. //KeyType array[] = {'A','B','C','D','E','F','G','H','I','J'};
  9. const int length = sizeof(array)/sizeof(KeyType);
  10. BTree tree = NULL;
  11. BTNode* node = NULL;
  12. int pos = -1;
  13. KeyType key1 = 'R'; // in the tree.
  14. KeyType key2 = 'B'; // not in the tree.
  15.  
  16. // 创建
  17. BTree_create(&tree, array, length);
  18.  
  19. printf("\n=== 创建 B- 树 ===\n");
  20. BTree_print(tree);
  21. printf("\n");
  22.  
  23. // 查找
  24. test_BTree_search(tree, key1);
  25. printf("\n");
  26. test_BTree_search(tree, key2);
  27.  
  28. // 移除不在B树中的元素
  29. test_BTree_remove(&tree, key2);
  30. printf("\n");
  31.  
  32. // 插入关键字
  33. printf("\n插入关键字 %c \n", key2);
  34. BTree_insert(&tree, key2);
  35. BTree_print(tree);
  36. printf("\n");
  37.  
  38. test_BTree_search(tree, key2);
  39.  
  40. // 移除关键字
  41. test_BTree_remove(&tree, key2);
  42. test_BTree_search(tree, key2);
  43. BTree_print(tree);
  44.  
  45. key2 = 'M';
  46. test_BTree_remove(&tree, key2);
  47. test_BTree_search(tree, key2);
  48. BTree_print(tree);
  49.  
  50. key2 = 'E';
  51. test_BTree_remove(&tree, key2);
  52. test_BTree_search(tree, key2);
  53. BTree_print(tree);
  54.  
  55. key2 = 'G';
  56. test_BTree_remove(&tree, key2);
  57. test_BTree_search(tree, key2);
  58. BTree_print(tree);
  59.  
  60. key2 = 'A';
  61. test_BTree_remove(&tree, key2);
  62. test_BTree_search(tree, key2);
  63. BTree_print(tree);
  64.  
  65. key2 = 'D';
  66. test_BTree_remove(&tree, key2);
  67. test_BTree_search(tree, key2);
  68. BTree_print(tree);
  69.  
  70. key2 = 'K';
  71. test_BTree_remove(&tree, key2);
  72. test_BTree_search(tree, key2);
  73. BTree_print(tree);
  74.  
  75. key2 = 'P';
  76. test_BTree_remove(&tree, key2);
  77. test_BTree_search(tree, key2);
  78. BTree_print(tree);
  79.  
  80. key2 = 'J';
  81. test_BTree_remove(&tree, key2);
  82. test_BTree_search(tree, key2);
  83. BTree_print(tree);
  84.  
  85. key2 = 'C';
  86. test_BTree_remove(&tree, key2);
  87. test_BTree_search(tree, key2);
  88. BTree_print(tree);
  89.  
  90. key2 = 'X';
  91. test_BTree_remove(&tree, key2);
  92. test_BTree_search(tree, key2);
  93. BTree_print(tree);
  94.  
  95. key2 = 'O';
  96. test_BTree_remove(&tree, key2);
  97. test_BTree_search(tree, key2);
  98. BTree_print(tree);
  99.  
  100. key2 = 'V';
  101. test_BTree_remove(&tree, key2);
  102. test_BTree_search(tree, key2);
  103. BTree_print(tree);
  104.  
  105. key2 = 'R';
  106. test_BTree_remove(&tree, key2);
  107. test_BTree_search(tree, key2);
  108. BTree_print(tree);
  109.  
  110. key2 = 'U';
  111. test_BTree_remove(&tree, key2);
  112. test_BTree_search(tree, key2);
  113. BTree_print(tree);
  114.  
  115. key2 = 'T';
  116. test_BTree_remove(&tree, key2);
  117. test_BTree_search(tree, key2);
  118. BTree_print(tree);
  119.  
  120. key2 = 'N';
  121. test_BTree_remove(&tree, key2);
  122. test_BTree_search(tree, key2);
  123. BTree_print(tree);
  124.  
  125. key2 = 'S';
  126. test_BTree_remove(&tree, key2);
  127. test_BTree_search(tree, key2);
  128. BTree_print(tree);
  129.  
  130. key2 = 'Y';
  131. test_BTree_remove(&tree, key2);
  132. test_BTree_search(tree, key2);
  133. BTree_print(tree);
  134.  
  135. key2 = 'F';
  136. test_BTree_remove(&tree, key2);
  137. test_BTree_search(tree, key2);
  138. BTree_print(tree);
  139.  
  140. key2 = 'Z';
  141. test_BTree_remove(&tree, key2);
  142. test_BTree_search(tree, key2);
  143. BTree_print(tree);
  144. // 销毁
  145. BTree_destroy(&tree);
  146. }
  1.  
  2. int main()
  3. {
  4. test_btree();
  5.  
  6. return 0;
  7. }

  

Btree算法的C语言实现的更多相关文章

  1. 魔方阵算法及C语言实现

    1 魔方阵概念 填充的,每一行.每一列.对角线之和均相等的方阵,阶数n = 3,4,5….魔方阵也称为幻方阵. 例如三阶魔方阵为: 魔方阵有什么的规律呢? 魔方阵分为奇幻方和偶幻方.而偶幻方又分为是4 ...

  2. 一个UUID生成算法的C语言实现 --- WIN32版本 .

    一个UUID生成算法的C语言实现——WIN32版本   cheungmine 2007-9-16   根据定义,UUID(Universally Unique IDentifier,也称GUID)在时 ...

  3. 无限大整数相加算法的C语言源代码

    忙里偷闲,终于完成了无限大整数相加算法的C语言代码,无限大整数相加算法的算法分析在这里. 500位的加法运行1000次,不打印结果的情况下耗时0.036秒,打印结果的情况下耗时16.285秒. 下面是 ...

  4. 数据结构算法集---C++语言实现

    //数据结构算法集---C++语言实现 //各种类都使用模版设计,可以对各种数据类型操作(整形,字符,浮点) /////////////////////////// // // // 堆栈数据结构 s ...

  5. 1164: 零起点学算法71——C语言合法标识符(存在问题)

    1164: 零起点学算法71——C语言合法标识符 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 10 ...

  6. 【最全】经典排序算法(C语言)

    算法复杂度比较: 算法分类 一.直接插入排序 一个插入排序是另一种简单排序,它的思路是:每次从未排好的序列中选出第一个元素插入到已排好的序列中. 它的算法步骤可以大致归纳如下: 从未排好的序列中拿出首 ...

  7. PID算法(c 语言)(转)

    PID算法(c 语言)(来自老外) #include <stdio.h> #include<math.h> //定义PID 的结构体 struct _pid { int pv; ...

  8. 一个UUID生成算法的C语言实现——WIN32版本

    源: 一个UUID生成算法的C语言实现——WIN32版本

  9. 排序算法总结(C语言版)

    排序算法总结(C语言版) 1.    插入排序 1.1     直接插入排序 1.2     Shell排序 2.    交换排序 2.1     冒泡排序 2.2     快速排序 3.    选择 ...

随机推荐

  1. SpringBoot启动流程分析(二):SpringApplication的run方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  2. 使用chrome调试前端线上代码

    家都知道在前端开发过程中,为加快网站静态资源加载速度都会对js/css等静态资源进行压缩合并再部署到生产环境,而在实际开发过程中开发人员一般都是在开发环境进行源码文件开发调试的,当部署平台或部署人员将 ...

  3. Oracle SQL性能优化 - 根据大表关联更新小表

    需求: 小表数据量20w条左右,大表数据量在4kw条左右,需要根据大表筛选出150w条左右的数据并关联更新小表中5k左右的数据. 性能问题: 对筛选条件中涉及的字段加index后,如下常规的updat ...

  4. 在IDEA建立Maven的多模块Web项目

    由于要搭建的是Maven项目,考虑到后面可能会有扩展,因此项目搭建的分模块的. 下面一步一步的来搭建这个项目 打开IDEA集成开发环境,点击File ---> New ---> Proje ...

  5. linux SPI驱动——gpio模拟spi驱动(三)

    一:首先在我的平台注册platform_device,保证能让spi-gpio.c能执行到probe函数. 1: struct spi_gpio_platform_data { 2: unsigned ...

  6. maven nexus 搭建

    http://www.cnblogs.com/adolfmc/archive/2012/08/21/2648415.html http://www.cnblogs.com/dingyingsi/p/3 ...

  7. Option可选值可选值(二)

    //: Playground - noun: a place where people can play import Cocoa var str1 = "供选链接和强制拆包的不同. &qu ...

  8. pulsar学习笔记1:helloworld

    pulsar号称是下一代的消息系统,这二年风光无限,大有干掉kafka的势头,如果想快速体验下,可以按以下步骤在本地搭建一个单机版本:(mac环境+jdk8) 一. 下载 wget https://w ...

  9. (转)CentOS 5.5 64bit 编译安装Adobe FlashMediaServer 3.5

    http://download.macromedia.com/pub/flashmediaserver/updates/4_0_2/Linux_32bit/FlashMediaServer4.tar. ...

  10. python仪表盘

    1.在这里可以看到pyecharts中有定义好的各种图标类. 复制上面代码,会出现“ModuleNotFoundError: No module named 'pyecharts'”. pip ins ...