Advertisement
DaniDori

Btree.cpp

Nov 2nd, 2023
423
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.32 KB | None | 0 0
  1. #include "BTree.h"
  2. #include "BinaryFileManagement.h"
  3. #include <iostream>
  4. #include <fstream>
  5. using namespace std;
  6. //Конструктор, который создает дерево по вх данным
  7. BTreeNode::BTreeNode(int t1, bool leaf1, BTree* parent) {
  8.     t = t1;
  9.     leaf = leaf1;
  10.     this->parentTree = parent;
  11.     keys = new string[2 * t - 1];
  12.     positions = new long[2 * t - 1];
  13.     C = new BTreeNode * [2 * t];
  14.     n = 0;
  15. }
  16.  
  17. //построение дерева из файла
  18. void BTree::buildTreeFromFile(const string& binaryFileName) {
  19.     ifstream binaryFile(binaryFileName, ios::binary);
  20.     if (!binaryFile.is_open()) {
  21.         cerr << "Failed to open binary file for building B-Tree!" << endl;
  22.         return;
  23.     }
  24.  
  25.     long position = 0;
  26.     DictionaryEntry entry;
  27.     while (binaryFile.read(reinterpret_cast<char*>(&entry), sizeof(entry))) {
  28.         // Преобразовываем array<char, 50> в string
  29.         string key(entry.englishWord.data(), strlen(entry.englishWord.data()));
  30.         //вставляем в дерево
  31.         insert(key, position++);
  32.     }
  33.  
  34.     binaryFile.close();
  35. }
  36.  
  37. // Метод для вставки нового ключа в неполный узел
  38. void BTreeNode::insertNonFull(const string& k, long position) {
  39.     int i = n - 1;
  40.  
  41.     if (leaf == true) {
  42.         //все ключи и значения сдвинули на 1
  43.         while (i >= 0 && keys[i] > k) {
  44.             keys[i + 1] = keys[i];
  45.             positions[i + 1] = positions[i];
  46.             i--;
  47.         }
  48.         //на свободное место поставили новые значения
  49.         keys[i + 1] = k;
  50.         positions[i + 1] = position;
  51.         n = n + 1;
  52.     }
  53.     else {
  54.         while (i >= 0 && keys[i] > k) {
  55.             i--;
  56.         }
  57.         if (C[i + 1]->n == 2 * t - 1) {
  58.             splitChild(i + 1, C[i + 1]);
  59.             if (keys[i + 1] < k) {
  60.                 i++;
  61.             }
  62.         }
  63.         C[i + 1]->insertNonFull(k, position);
  64.     }
  65. }
  66.  
  67. // Вспомогательная функция для разделения дочернего элемента y этого узла.
  68. void BTreeNode::splitChild(int i, BTreeNode* y) {
  69.     // Создаем новый узел 'z' с определенными характеристиками, наследуя их от узла 'y'.
  70.     BTreeNode* z = new BTreeNode(y->t, y->leaf, parentTree);
  71.     z->n = t - 1;
  72.  
  73.  
  74.     // Копируем ключи и связанные с ними данные из узла 'y' в узел 'z'.
  75.     for (int j = 0; j < t - 1; j++) {
  76.         z->keys[j] = y->keys[j + t];
  77.         z->positions[j] = y->positions[j + t];
  78.     }
  79.  
  80.     // Если 'y' не является листовым узлом, копируем ссылки на дочерние узлы из 'y' в 'z'.
  81.     if (y->leaf == false) {
  82.         for (int j = 0; j < t; j++) {
  83.             z->C[j] = y->C[j + t];
  84.         }
  85.     }
  86.     // Устанавливаем количество ключей в 'y' на новое значение.
  87.     y->n = t - 1;
  88.  
  89.     // Двигаем ссылки на дочерние узлы в текущем узле, чтобы сделать место для 'z'.
  90.     for (int j = n; j >= i + 1; j--) {
  91.         C[j + 1] = C[j];
  92.     }
  93.     C[i + 1] = z;
  94.  
  95.     // Двигаем ключи и связанные с ними данные, чтобы сделать место для одного ключа из 'y'.
  96.     for (int j = n - 1; j >= i; j--) {
  97.         keys[j + 1] = keys[j];
  98.         positions[j + 1] = positions[j];
  99.     }
  100.  
  101.     // Помещаем один ключ из 'y' в текущий узел на позицию 'i'.
  102.     keys[i] = y->keys[t - 1];
  103.     positions[i] = y->positions[t - 1];
  104.  
  105.     // Увеличиваем количество ключей в текущем узле.
  106.     n = n + 1;
  107.  
  108.     // Возможно увеличение счетчика разделений в объекте, представляющем B-дерево.
  109.     parentTree->increaseSplitCount();
  110. }
  111.  
  112. // Метод для вставки ключа в дерево
  113. void BTree::insert(const string& k, long position) {
  114.     //создаем первую запись, если дерево пустое
  115.     if (root == NULL) {
  116.         root = new BTreeNode(t, true, this);
  117.         root->keys[0] = k;
  118.         root->positions[0] = position;
  119.         root->n = 1;
  120.     }
  121.     else {
  122.         if (root->n == 2 * t - 1) {
  123.             // Если корневой узел 'root' содержит максимальное количество ключей, необходимо выполнить разделение.
  124.             BTreeNode* s = new BTreeNode(t, false, this); // Создаем новый узел 's' и устанавливаем его как корневой узел.
  125.             s->C[0] = root; // Устанавливаем текущий корневой узел 'root' как дочерний узел для нового корневого узла 's'.
  126.             s->splitChild(0, root); // Выполняем операцию разделения узла.
  127.  
  128.             int i = 0;
  129.             if (s->keys[0] < k) {
  130.                 i++;
  131.             }
  132.             // Определяем, в какой дочерний узел должны вставить ключ 'k' и связанные с ним данные 'position'.
  133.             s->C[i]->insertNonFull(k, position);
  134.  
  135.             // Обновляем корневой узел, так как узел 'root' больше не является корневым.
  136.             root = s;
  137.         }
  138.         else {
  139.             // Если корневой узел 'root' имеет место для вставки ключа, выполняем операцию вставки в корневой узел.
  140.             root->insertNonFull(k, position);
  141.         }
  142.  
  143.     }
  144. }
  145.  
  146. // Метод поиска ключа в узле
  147. BTreeNode* BTreeNode::search(const string& k) {
  148.     // Находим первый ключ больше или равный k
  149.     int i = 0;
  150.     while (i < n && k > keys[i]) {
  151.         i++;
  152.     }
  153.  
  154.     // Если найденный ключ равен k, возвращаем этот узел
  155.     if (i < n && keys[i] == k) {
  156.         cout << "Ключ найден: " << k << ", позиция в файле: " << positions[i] << endl;
  157.         return this;
  158.     }
  159.  
  160.     // Если ключ не найден и этот узел листовой
  161.     if (leaf) {
  162.         cout << "Ключ не найден";
  163.         return nullptr;
  164.     }
  165.  
  166.     // Идем к соответствующему ребенку
  167.     return C[i]->search(k);
  168. }
  169.  
  170. // Функции для удаления ключа
  171. void BTreeNode::remove(const string& k) {
  172.     int idx = findKey(k);
  173.  
  174.     // Ключ k присутствует в этом узле
  175.     if (idx < n && keys[idx] == k) {
  176.         if (leaf) {
  177.             //если узел листовой - удаление его как листа
  178.             removeFromLeaf(idx);
  179.         }
  180.         else {
  181.             //Если не листовой - удаляем как не листовой
  182.             removeFromNonLeaf(idx);
  183.         }
  184.     }
  185.     else {
  186.         // Если этот узел листовой, то ключ отсутствует в дереве
  187.         if (leaf) {
  188.             cout << "Ключ \"" << k << "\" не существует в дереве\n";
  189.             return;
  190.         }
  191.  
  192.         // Флаг указывающий, находится ли ключ в поддереве, где последний узел находится на границе
  193.         bool flag = ((idx == n) ? true : false);
  194.  
  195.         // Если дочерний узел, где должен находиться ключ, имеет только t-1 ключей, заполняем этот узел
  196.         if (C[idx]->n < t) {
  197.             fill(idx);
  198.         }
  199.  
  200.         // Если последний дочерний узел был слиян, он должен быть объединен со своим предыдущим соседом, поэтому удаляем k из предыдущего узла
  201.         if (flag && idx > n) {
  202.             C[idx - 1]->remove(k);
  203.         }
  204.         else {
  205.             C[idx]->remove(k);
  206.         }
  207.     }
  208. }
  209.  
  210. //Удаление листа
  211. void BTreeNode::removeFromLeaf(int idx) {
  212.     // Смещаем все ключи после idx на один шаг назад
  213.     for (int i = idx + 1; i < n; ++i) {
  214.         keys[i - 1] = keys[i];
  215.         positions[i - 1] = positions[i];
  216.     }
  217.     n--;
  218. }
  219.  
  220. //Удаление не листа
  221. void BTreeNode::removeFromNonLeaf(int idx) {
  222.     string k = keys[idx];
  223.  
  224.     // Если дочерний узел, который предшествует k, имеет по крайней мере t ключей
  225.     if (C[idx]->n >= t) {
  226.         string pred = getPred(idx);
  227.         keys[idx] = pred;
  228.         C[idx]->remove(pred);
  229.     }
  230.     // Если узел C[idx] имеет менее t ключей, тогда ищем в C[idx+1]
  231.     else if (C[idx + 1]->n >= t) {
  232.         string succ = getSucc(idx);
  233.         keys[idx] = succ;
  234.         C[idx + 1]->remove(succ);
  235.     }
  236.     // Если оба C[idx] и C[idx+1] имеют t-1 ключей, объединяем их
  237.     else {
  238.         merge(idx);
  239.         C[idx]->remove(k);
  240.     }
  241. }
  242.  
  243. string BTreeNode::getPred(int idx) {
  244.     // Перемещаемся в самый правый узел, пока не достигнем листа
  245.     BTreeNode* cur = C[idx];
  246.     while (!cur->leaf) {
  247.         cur = cur->C[cur->n];
  248.     }
  249.     // Возвращаем последний ключ из листа
  250.     return cur->keys[cur->n - 1];
  251. }
  252.  
  253. string BTreeNode::getSucc(int idx) {
  254.     // Перемещаемся в самый левый узел, пока не достигнем листа
  255.     BTreeNode* cur = C[idx + 1];
  256.     while (!cur->leaf) {
  257.         cur = cur->C[0];
  258.     }
  259.     // Возвращаем первый ключ из листа
  260.     return cur->keys[0];
  261. }
  262.  
  263. void BTreeNode::fill(int idx) {
  264.     // Если предыдущий узел имеет более t-1 ключей, заимствуем ключ от него
  265.     if (idx != 0 && C[idx - 1]->n >= t)
  266.         borrowFromPrev(idx);
  267.     // Если следующий узел имеет более t-1 ключей, заимствуем ключ от него
  268.     else if (idx != n && C[idx + 1]->n >= t)
  269.         borrowFromNext(idx);
  270.     // Иначе объединяем children[idx] с соседом
  271.     else {
  272.         if (idx != n)
  273.             merge(idx);
  274.         else
  275.             merge(idx - 1);
  276.     }
  277. }
  278.  
  279. void BTreeNode::borrowFromPrev(int idx) {
  280.     BTreeNode* child = C[idx];
  281.     BTreeNode* sibling = C[idx - 1];
  282.  
  283.     // Перемещаем все ключи и дочерние элементы в child на один шаг вперед
  284.     for (int i = child->n - 1; i >= 0; --i)
  285.         child->keys[i + 1] = child->keys[i];
  286.     if (!child->leaf) {
  287.         for (int i = child->n; i >= 0; --i)
  288.             child->C[i + 1] = child->C[i];
  289.     }
  290.  
  291.     // Перемещаем ключ из sibling в child
  292.     child->keys[0] = keys[idx - 1];
  293.     if (!child->leaf)
  294.         child->C[0] = sibling->C[sibling->n];
  295.  
  296.     // Перемещаем ключ из sibling в текущий узел
  297.     keys[idx - 1] = sibling->keys[sibling->n - 1];
  298.  
  299.     child->n += 1;
  300.     sibling->n -= 1;
  301. }
  302.  
  303. void BTreeNode::borrowFromNext(int idx) {
  304.     BTreeNode* child = C[idx];
  305.     BTreeNode* sibling = C[idx + 1];
  306.  
  307.     // Перемещаем ключ из sibling в child
  308.     child->keys[child->n] = keys[idx];
  309.     if (!child->leaf)
  310.         child->C[child->n + 1] = sibling->C[0];
  311.  
  312.     // Первый ключ из sibling перемещается в keys
  313.     keys[idx] = sibling->keys[0];
  314.  
  315.     // Перемещаем все ключи в sibling на один шаг назад
  316.     for (int i = 1; i < sibling->n; ++i)
  317.         sibling->keys[i - 1] = sibling->keys[i];
  318.     if (!sibling->leaf) {
  319.         for (int i = 1; i <= sibling->n; ++i)
  320.             sibling->C[i - 1] = sibling->C[i];
  321.     }
  322.  
  323.     child->n += 1;
  324.     sibling->n -= 1;
  325. }
  326.  
  327. void BTreeNode::merge(int idx) {
  328.     BTreeNode* child = C[idx];
  329.     BTreeNode* sibling = C[idx + 1];
  330.  
  331.     // Вставляем ключ из текущего узла в child
  332.     child->keys[t - 1] = keys[idx];
  333.  
  334.     // Копируем ключи и дочерние узлы из sibling в child
  335.     for (int i = 0; i < sibling->n; ++i)
  336.         child->keys[i + t] = sibling->keys[i];
  337.     if (!child->leaf) {
  338.         for (int i = 0; i <= sibling->n; ++i)
  339.             child->C[i + t] = sibling->C[i];
  340.     }
  341.  
  342.     // Перемещаем все ключи после idx в текущем узле на один шаг назад
  343.     for (int i = idx + 1; i < n; ++i)
  344.         keys[i - 1] = keys[i];
  345.     for (int i = idx + 2; i <= n; ++i)
  346.         C[i - 1] = C[i];
  347.  
  348.     child->n += sibling->n + 1;
  349.     n--;
  350.  
  351.     // Удаляем sibling
  352.     delete sibling;
  353. }
  354.  
  355. int BTreeNode::findKey(const string& k) {
  356.     int idx = 0;
  357.     while (idx < n && keys[idx] < k) {
  358.         ++idx;
  359.     }
  360.     return idx;
  361. }
  362.  
  363. // Вспомогательные методы
  364. void BTreeNode::traverse() {
  365.     // Существует n ключей и n+1 детей, проходим через n ключей и первые n детей
  366.     int i;
  367.     for (i = 0; i < n; i++) {
  368.         // Если это не лист, то перед печатью keys[i], проходим его поддерево
  369.         if (!leaf) {
  370.             C[i]->traverse();
  371.         }
  372.         cout << " " << keys[i];
  373.     }
  374.  
  375.     // Печатаем поддерево последнего ребенка
  376.     if (!leaf) {
  377.         C[i]->traverse();
  378.     }
  379. }
  380.  
  381. void BTreeNode::printTree(int depth) {
  382.     // Вывод с отступом в зависимости от глубины узла
  383.     for (int i = 0; i < depth; i++) cout << "    ";
  384.     for (int i = 0; i < n; i++) {
  385.         cout << keys[i] << " ";
  386.     }
  387.     cout << "\n";
  388.  
  389.     // Рекурсивно выводим дочерние узлы
  390.     if (!leaf) {
  391.         for (int i = 0; i <= n; i++) {
  392.             if (C[i] != nullptr) {
  393.                 C[i]->printTree(depth + 1);
  394.             }
  395.         }
  396.     }
  397. }
  398.  
  399. void BTree::remove(const string& k) {
  400.     if (!root) {
  401.         cout << "Дерево пусто\n";
  402.         return;
  403.     }
  404.  
  405.     // Вызываем функцию удаления для корня
  406.     root->remove(k);
  407.  
  408.     // Если у корня не осталось ключей, делаем его первым ребенком новым корнем
  409.     if (root->n == 0) {
  410.         BTreeNode* tmp = root;
  411.         if (root->leaf)
  412.             root = nullptr;
  413.         else
  414.             root = root->C[0];
  415.  
  416.         // Удаляем старый корень
  417.         delete tmp;
  418.     }
  419. }
  420.  
  421. void BTree::clear(BTreeNode* node) {
  422.     if (!node)
  423.         return;
  424.  
  425.     // Очищаем дочерние узлы
  426.     if (!node->leaf) {
  427.         for (int i = 0; i <= node->n; ++i)
  428.             clear(node->C[i]);
  429.     }
  430.  
  431.     // Удаляем узел
  432.     delete node;
  433. }
  434.  
  435.  
  436. BTree::~BTree() {
  437.     clear(root);
  438.     root = nullptr;
  439. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement