B_tree funcionando tudo certinho, mas quando voce busca e depois insere, é inserido um lixo no final. ela está tratando a incializacao.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "b_tree_atual.h"
int main() {
Chave chave, inicializadora;
short rrn, pos;
strcpy(inicializadora.chave, "SHE01\0");
BTPAGE page;
if (btopen()){ /* try to open btree.dat and get root */
root = getroot();
printf("Arquivo de índice aberto com sucesso!\n");
}
else
root = create_tree(inicializadora); /* if btree.dat not there, create it */
//Insercoes
strcpy(chave.chave, "BBB02\0");
chave.rrn_dados = 22;
insert(root, chave);
strcpy(chave.chave, "CCC02\0");
insert(root, chave);
strcpy(chave.chave, "DDD02\0");
insert(root, chave);
strcpy(chave.chave, "EEE02\0");
insert(root, chave);
strcpy(chave.chave, "FFF02\0");
insert(root, chave);
strcpy(chave.chave, "GGG02\0");
insert(root, chave);
strcpy(chave.chave, "HHH02\0");
insert(root, chave);
strcpy(chave.chave, "III02\0");
chave.rrn_dados = 32;
insert(root, chave);
strcpy(chave.chave, "JJJ02\0");
insert(root, chave);
strcpy(chave.chave, "KKK02\0");
insert(root, chave);
strcpy(chave.chave, "LLL02\0");
insert(root, chave);
strcpy(chave.chave, "MMM02\0");
insert(root, chave);
strcpy(chave.chave, "NNN02\0");
insert(root, chave);
strcpy(chave.chave, "OOO02\0");
insert(root, chave);
strcpy(chave.chave, "PPP02\0");
insert(root, chave);
strcpy(chave.chave, "QQQ02\0");
insert(root, chave);
strcpy(chave.chave, "RRR02\0");
insert(root, chave);
strcpy(chave.chave, "SSS02\0");
chave.rrn_dados = 45;
insert(root, chave);
strcpy(chave.chave, "TTT02\0");
insert(root, chave);
strcpy(chave.chave, "UUU02\0");
insert(root, chave);
strcpy(chave.chave, "VVV02\0");
insert(root, chave);
strcpy(chave.chave, "VVX02\0");
insert(root, chave);
strcpy(chave.chave, "VVW02\0");
insert(root, chave);
strcpy(chave.chave, "WWW02\0");
insert(root, chave);
strcpy(chave.chave, "WWY02\0");
insert(root, chave);
strcpy(chave.chave, "YYY02\0");
insert(root, chave);
strcpy(chave.chave, "XXX02\0");
insert(root, chave);
strcpy(chave.chave, "ZZZ02\0");
insert(root, chave);
printf("\n");
print_btree(root);
strcpy(chave.chave, "SSS02\0");
if (search_key_on_tree(root, chave, &rrn, &pos))
printf("RRN %d\n", rrn);
else
printf("Nao achouw\n");
// Removendo Chaves e usando print_btree pra visualizar e verificar
strcpy(chave.chave, "ZZZ02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
print_btree(root);
strcpy(chave.chave, "YYY02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
print_btree(root);
strcpy(chave.chave, "VVX02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
printf("\n\n");
print_btree(root);
strcpy(chave.chave, "PPP02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
printf("\n\n");
print_btree(root);
strcpy(chave.chave, "XXX02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
printf("\n\n");
print_btree(root);
strcpy(chave.chave, "UUU02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
strcpy(chave.chave, "VVV02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
printf("\n\n");
print_btree(root);
strcpy(chave.chave, "WWW02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
strcpy(chave.chave, "QQQ02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
strcpy(chave.chave, "RRR02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
strcpy(chave.chave, "VVW02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
strcpy(chave.chave, "WWY02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
printf("\n\n");
print_btree(root);
strcpy(chave.chave, "TTT02\0");
printf("\n\nREMOVENDO %s\n", chave.chave);
remove_key(root, chave);
printf("\n\n");
printf(" RAIZ %d\n", root);
print_btree(root);
//Procurando Chave
strcpy(chave.chave, "JJI02\0");
if (search_key_on_tree(root, chave, &rrn, &pos))
printf("RRN %d\n", rrn);
else
printf("Nao achouw\n");
btclose();
return 0;
}#ifndef INCLUDED_b_tree_atual
#define INCLUDED_b_tree_atual
#endif
//Constantes
#define MINKEYS 2
#define MAXKEYS 2*MINKEYS
#define NIL (-1)
#define NOKEY "#####"
#define NO 0
#define YES 1
//Declaração de estruturas
typedef struct Chave {
char chave[6];
long rrn_dados;
}Chave;
typedef struct BTPAGE{
short keycount; /* number of keys in page */
Chave key[MAXKEYS]; /* the actual keys */
long child[MAXKEYS + 1]; /* ptrs to rrns of descendants */
} BTPAGE;
#define PAGESIZE sizeof(BTPAGE)
//Variaveis globais
extern short root; /* rrn of root page */
extern FILE *btfd; /* file descriptor of btree file */
extern int infd; /* file descriptor of input file */
//Funcoes
void btclose();
int btopen();
BTPAGE btread(short rrn);
int btwrite(short rrn, BTPAGE *page_ptr);
short create_root(Chave key, short left, short right);
short create_tree();
short get_rrn_new_page();
short getroot();
void insert(short rrn, Chave key);
int recursive_insert(short rrn, Chave key, short *promo_r_child, Chave *promo_key);
void ins_in_page(Chave key, short r_child, BTPAGE *p_page);
void pageinit(BTPAGE *p_page);
void putroot(short root);
int search_node(Chave key, BTPAGE *p_page, short *pos);
void split(Chave key, short r_child, BTPAGE *p_oldpage, Chave *promo_key,
short *promo_r_child, BTPAGE *p_newpage);
int search_key_on_tree(short rrn, Chave key, short *found_rrn, short *found_pos);
void remove_key(short rrn, Chave key);
int recursive_remove_key(short rrn, Chave key, int *is_change, Chave *promo_key);
void fixup_page(short rrn, short pos, BTPAGE *page);
int redistribution(short rrn, short pos, Chave key, BTPAGE page);
void shellSort(Chave *vet, int size);
int concatenation(short rrn, short pos, Chave key, BTPAGE page);
void print_btree(short rrn);
void printPage(BTPAGE *page);#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stdio.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "b_tree_atual.h"
// Ponteiro Global do Arquivo de Indice e Raiz, usado em todas as funções praticamente
FILE *btfd; /* global file descriptor for "btree.dat" */
short root;
/* Funcao para abrir o arquivo de indices para leitura e escrita binaria
* Retorna 0 Senão existe, e 1 se existe
*/
int btopen() {
btfd = fopen("index.dat", "r+b");
if (!btfd)
return 0;
else
return 1;
}
// fecha o arquivo de índice
void btclose() {
putroot(root);
fclose(btfd);
}
/* Le o primeiro short do arquivo de indice que é a raiz e retorna o valor
* caso contrário ERRO
*/
short getroot() {
short root;
fseek(btfd, 0L, 0);
if (fread(&root, sizeof(short), 1, btfd) == 0) {
printf("Error: Unable to get root.\007\n");
exit(1);
}
return root;
}
/* Sempre que há mudança no nivel da arvore, eh criada uma nova
* raiz, assim a função escreve no arquivo no inicio a nova raiz
*/
void putroot(short root) {
fseek(btfd, 0L, 0);
fwrite(&root, sizeof (short), 1, btfd);
}
/* Se arvore nao existe, cria arquivo de indice, cria a pagina raiz e
* adiciona a primeria chave pra nao ficar vazia e retorna o RRN da raiz
*/
short create_tree(Chave key) {
btfd = fopen("index.dat", "a+b");
fclose(btfd); /* Have to close and reopen to insure */
btopen(); /* read/write access on many systems. */
return (create_root(key, NIL, NIL));
}
/* Funcao usada no split pra pegar o RRN da proxima pagina a ser adicionada
* no final do arquivo, retorna esse RRN
*/
short get_rrn_new_page() {
long addr;
fseek(btfd, 0L, SEEK_END);
addr = ftell(btfd);
return ((short) addr / PAGESIZE);
}
/* Retorna a pagina do arquivo de indice referente ao RRN passado
* como Paramentro
*/
BTPAGE btread(short rrn) {
BTPAGE page;
long addr;
addr = (long) rrn * (long) PAGESIZE + 2L;
fseek(btfd, addr, 0);
fread(&page, PAGESIZE, 1, btfd);
return page;
}
/* Escreve no arquivo a pagina passada como parametro
* e grava na posicao do RRN passado, retorna se escreveu ou se deu erro
*/
int btwrite(short rrn, BTPAGE *page_ptr) {
long addr;
addr = (long) rrn * (long) PAGESIZE + 2L;
fseek(btfd, addr, 0);
return (fwrite(page_ptr, PAGESIZE, 1, btfd));
}
/* Cria a pagina que será raiz e retorna o RRN dela
* e inicializa a pagina com pageinit()
*/
short create_root(Chave key, short left, short right) {
BTPAGE page;
short rrn;
rrn = get_rrn_new_page();
pageinit(&page);
page.key[0] = key;
page.child[0] = left;
page.child[1] = right;
page.keycount = 1;
btwrite(rrn, &page);
putroot(rrn);
return (rrn);
}
/* recebe uma pagina como referencia e inicializa setando os filhso pra -1
* e as chaves para NOKEY, no nosso caso #####
*/
void pageinit(BTPAGE *p_page) /* p_page: pointer to a page */ {
int j;
for (j = 0; j < MAXKEYS; j++) { //Inicializa a pg preenchendo os filhos e chaves com nil e #
strcpy(p_page->key[j].chave, NOKEY);
p_page->key[j].rrn_dados = NIL;
p_page->child[j] = NIL;
}
p_page->child[MAXKEYS] = NIL;
}
/* Funcao utilizada para procurar uma determinada chave numa pagina passada
* A referencia de *pos indica qual a posição eh ou deveria ocorrer a chave
* retorna se achou ou nao
*/
int search_node(Chave key, BTPAGE *p_page, short *pos)
/* pos: position where key is or should be inserted */ {
int i;
for (i = 0; i < p_page->keycount && strcmp(key.chave, p_page->key[i].chave) > 0; i++)
;
*pos = i;
if (*pos < p_page->keycount && strcmp(key.chave, p_page->key[*pos].chave)==0)
return (YES); /* key is in page */
else
return (NO); /* key is not in page */
}
/* Funcao que efetivamente insere uma chave numa pagina
* ordenando as chave r_child eh o novo filho dessa pagina se houver
*/
void ins_in_page(Chave key, short r_child, BTPAGE *p_page) {
int i;
for (i = p_page->keycount; strcmp(key.chave, p_page->key[i - 1].chave) < 0 && i > 0; i--) {
p_page->key[i] = p_page->key[i - 1];
p_page->child[i + 1] = p_page->child[i];
}
p_page->keycount++;
p_page->key[i] = key;
p_page->child[i + 1] = r_child;
}
/* Funcao para testes pessoais de projeto, nao utilizada
* no projeto efetivamente
*
void printPage(BTPAGE *page) {
printf("QNT chave: %d\n", page->keycount);
int i;
for (i = 0; i < MAXKEYS; i++) {
printf("<|%ld|>", page->child[i]);
printf(" %s ", page->key[i].chave);
}
printf("<|%ld|>", page->child[i]);
printf("\n");
}
*/
/* split ()
Arguments:
key: key to be inserted
promo_key: key to be promoted up from here
r_child: child rrn to be inserted
promo_r_child: rrn to be promoted up from here
p_oldpage: pointer to old page structure
p_newpage: pointer to new page structure
*/
/* Funcao split que separa chaves entre pagina antiga e nova
* e isso por referencia, pois o insert vai cuidar de escreve-las no arquivo
* Ela também escolhe quem será promovido por meido de *promo_key
*/
void split(Chave key, short r_child, BTPAGE *p_oldpage, Chave *promo_key,
short *promo_r_child, BTPAGE *p_newpage) {
int i;
short mid; /* tells where split is to occur */
Chave workkeys[MAXKEYS + 1]; /* temporarily holds keys, before split */
short workch[MAXKEYS + 2]; /* temporarily holds children, before split */
for (i = 0; i < MAXKEYS; i++) { /* move keys and children from */
workkeys[i] = p_oldpage->key[i]; /* old page into work arrays */
workch[i] = p_oldpage->child[i];
}
workch[i] = p_oldpage->child[i];
for (i = MAXKEYS; strcmp(key.chave, workkeys[i - 1].chave) < 0 && i > 0; i--) { /* insert new key */
workkeys[i] = workkeys[i - 1];
workch[i + 1] = workch[i];
}
workkeys[i] = key;
workch[i + 1] = r_child;
*promo_r_child = get_rrn_new_page(); /* create new page for split, */
pageinit(p_newpage); /* and promote rrn of new page */
*promo_key = workkeys[(int) (MAXKEYS + 1) / 2];
for (i = 0; i < MINKEYS; i++) { /* move first half of keys and */
p_oldpage->key[i] = workkeys[i]; /* children to old page, second */
p_oldpage->child[i] = workch[i]; /* half to new page */
p_newpage->key[i] = workkeys[i + 1 + MINKEYS];
p_newpage->child[i] = workch[i + 1 + MINKEYS];
strcpy(p_oldpage->key[i + MINKEYS].chave, NOKEY); /* mark second half of old */
p_oldpage->key[i + MINKEYS].rrn_dados = NIL;
p_oldpage->child[i + 1 + MINKEYS] = NIL; /* page as empty */
}
p_oldpage->child[MINKEYS] = workch[MINKEYS];
p_newpage->child[MINKEYS] = workch[i + 1 + MINKEYS];
p_newpage->keycount = MAXKEYS - MINKEYS;
p_oldpage->keycount = MINKEYS;
*promo_key = workkeys[MINKEYS]; /* promote middle key */
r_child = *promo_r_child;
key = *promo_key;
}
/* Funcão Driver que trata de setar a nova pagina raiz quando há split e
* uma nova pagina é criada
* Ela chama recursive_insert que vasculha e trata as possiveis ocorrencias e
* apenas retornara se houver promocao, caso contrario adiciona
* se chave jah existe nao adiciona, os parametros sao RRN da raiz e a Chave key
*/
void insert(short rrn, Chave key){
int promoted; /* boolean: tells if a promotion from below */
short promo_rrn; /* rrn promoted from below */
Chave promo_key; /* key promoted from below */
promoted = recursive_insert(rrn, key, &promo_rrn, &promo_key);
if (promoted)
root = create_root(promo_key, getroot(), promo_rrn);
}
// Insere recursivamente, retorna promocao ou nao pra insert()
int recursive_insert(short rrn, Chave key, short *promo_r_child, Chave *promo_key) {
BTPAGE page, /* current page */
newpage; /* new page created if split occurs */
int found, promoted; /* boolean values */
short pos,
p_b_rrn; /* rrn promoted from below */
Chave p_b_key; /* key promoted from below */
if (rrn == NIL) { /* past bottom of tree... "promote" */
*promo_key = key; /* original key so that it will be */
*promo_r_child = NIL; /* inserted at leaf level */
return (YES);
} else {
page = btread(rrn);
found = search_node(key, &page, &pos);
if (found) {
printf("Error: attempt to insert duplicate key: %s \n\007", key.chave);
return (0);
}
promoted = recursive_insert(page.child[pos], key, &p_b_rrn, &p_b_key);
if (!promoted) {
return (NO); /* no promotion */
} else if (page.keycount < MAXKEYS) {
ins_in_page(p_b_key, p_b_rrn, &page); /* OK to insert key and */
btwrite(rrn, &page); /* pointer in this page. */
return (NO); /* no promotion */
} else {
split(p_b_key, p_b_rrn, &page, promo_key, promo_r_child, &newpage);
btwrite(rrn, &page);
btwrite(*promo_r_child, &newpage);
return (YES); /* promotion */
}
}
}
/* Função de Busca que procura por chave na arvore de indices
* Caso encontra, retorna Verdadeiro e *found_rrn guarda o RRN do arquivo de dados
* da chave referente
* Caso nao encontra, retorna falso
*/
int search_key_on_tree(short rrn, Chave key, short *found_rrn, short *found_pos) {
BTPAGE page;
short pos;
int found;
if (rrn == NIL)
return (NO); //chave de busca não encontrada
else {
page = btread(rrn);
found = search_node(key, &page, &pos);
if (found) {
*found_rrn = page.key[pos].rrn_dados; //RRN corrente contém a chave
*found_pos = pos; //POS contém a posição da chave em PAGE
return (YES);
}//a chave de busca não foi encontrada,
else
//a chave de busca não foi encontrada, então se procura a chave no nó filho
return (search_key_on_tree(page.child[pos], key, found_rrn, found_pos));
}
}
/* Ordenacao utilizada na distribuicao e concatenação pra ordenar as paginas
* o vetor de chave eh passado por referência
*/
void shellSort(Chave *vet, int size) {
int i, j;
char value[6];
int gap = 1;
do {
gap = 3 * gap + 1;
} while (gap < size);
do {
gap /= 3;
for (i = gap; i < size; i++) {
strcpy(value, vet[i].chave);
j = i - gap;
while ((j >= 0) && (strcmp(value, vet[j].chave) < 0)) {
strcpy(vet[j + gap].chave, vet[j].chave);
j -= gap;
}
strcpy(vet[j + gap].chave, value);
}
} while (gap > 1);
}
/* Funcao pra organizar uma pagina quando uma chave é retirada
* As paginas que chegam aqui como referência sao rearranjadas de forma
* a retirar a chave da posicao pos e reagrupar chave e filhos
*/
void fixup_page(short rrn, short pos, BTPAGE *page) {
int i;
if (pos == (MAXKEYS - 1)) {
strcpy(page->key[pos].chave, NOKEY);
page->child[pos + 1] = -1;
} else {
page->key[pos] = page->key[pos + 1];
page->child[pos + 1] = page->child[pos + 2];
for (i = pos + 1; i < (MAXKEYS - 1); i++) {
if (page->key[i].chave != NOKEY) {
page->key[i] = page->key[i + 1];
page->child[i + 1] = page->child[i + 2];
}
}
strcpy(page->key[i].chave, NOKEY);
}
page->keycount--;
}
/* Função muito do mau pra fazer caras! Olha o tamanho desse trem, que bom que consegui, TENSO!
* Mas entao, ela recebe o RRN do PAI, a posicao do filho o qual teve underflow
* e a pagina pai por valor pra que eu nao precise carregar da memoria
* as filhas sao lidas do arquivo, eh escolhido a irma que servirá para dividir as chaves
* eh feita a divisão, alterações necessárias, e entao grava no arquivo o pai e as filhas
* Retorna sim se a distribuição eh possivel, pois se nao for, devo fazer um concatenação
* dai o remover cuida disso
*/
int redistribution(short rrn, short pos, Chave key, BTPAGE page) {
BTPAGE filha, irma_filha;
Chave workkeys[MAXKEYS + MINKEYS]; /* Guarda as chave para redistribuir entre filha e irma_filha */
short workch[MAXKEYS + MINKEYS + 1]; /* Guarda os filhos dessas chaves pra redistribuir */
int j = 0, i = 0, posicao_relativa_irma = 0; // Diz se a irma escolhida eh da direira ou esquerda 0 ESQ e 1 DIR
filha = btread(page.child[pos]);
if (pos == 0) {
irma_filha = btread(page.child[pos + 1]);
posicao_relativa_irma = 1;
} else if (pos == (MAXKEYS - 1))
irma_filha = btread(page.child[pos - 1]);
else {
irma_filha = btread(page.child[pos - 1]);
pos--;
if (irma_filha.keycount <= MINKEYS) {
pos++;
irma_filha = btread(page.child[pos + 1]);
posicao_relativa_irma = 1;
}
}
if (irma_filha.keycount > MINKEYS) {
while (strcmp(filha.key[i].chave, NOKEY) != 0) {
workkeys[i] = filha.key[i];
workch[i] = filha.child[i];
i++;
}
workkeys[i] = page.key[pos];
workch[i] = filha.child[i];
j = i + 1;
i = 0;
while ((strcmp(irma_filha.key[i].chave, NOKEY) != 0) && (j < MAXKEYS + MINKEYS)) {
workkeys[j] = irma_filha.key[i];
workch[j] = irma_filha.child[i];
i++;
j++;
}
workch[j] = irma_filha.child[i];
shellSort(&workkeys, MAXKEYS + MINKEYS);
if (posicao_relativa_irma == 0) { // Verifica se pagina irma eh da esquerda ou direita, pois muda a ordem de dsitribuicao
for (i = 0; i <= MINKEYS; i++) { /* Move filhos para a pagina filha, seus filhos tbm */
if (i < MINKEYS) {
irma_filha.key[i] = workkeys[i];
filha.child[MINKEYS + i] = workch[i];
filha.child[i] = workch[i + 1 + MAXKEYS];
}
irma_filha.child[i] = workch[i + MINKEYS];
filha.key[i] = workkeys[i + 1 + MINKEYS];
strcpy(irma_filha.key[i + MINKEYS - 1].chave, NOKEY);
}
filha.keycount = filha.keycount + irma_filha.keycount - MINKEYS;
irma_filha.keycount = MINKEYS;
btwrite(page.child[pos], &irma_filha);
btwrite(page.child[pos + 1], &filha);
} else {
for (i = 0; i <= MINKEYS; i++) {
if (i < 2)
filha.key[i] = workkeys[i];
filha.child[i] = workch[i];
irma_filha.key[i] = workkeys[i + 1 + MINKEYS];
irma_filha.child[i] = workch[i + 2 + MINKEYS];
strcpy(irma_filha.key[i + MINKEYS - 1].chave, NOKEY);
}
irma_filha.child[i] = workch[i];
irma_filha.keycount = irma_filha.keycount + filha.keycount - MINKEYS;
filha.keycount = MINKEYS;
btwrite(page.child[pos], &filha);
btwrite(page.child[pos + 1], &irma_filha);
}
page.key[pos] = workkeys[MINKEYS];
btwrite(rrn, &page);
return (YES);
} else
return (NO);
}
/* Essa funcao nao eh tao do mau quanto a Distribution porque a base dela vem da outra
* entao nao tive que começar do zero
* Entao, ela recebe o RRN do PAI, a posicao do filho o qual teve underflow
* e a pagina pai por valor pra que eu nao precise carregar da memoria
* as filhas sao lidas do arquivo, eh escolhido a irma que servirá para ceder suas chaves
* eh feita a junção da chave, alterações necessárias, e entao grava no arquivo o pai e a filha concatenada
* O retorno está comentado dentro da função no final
*/
int concatenation(short rrn, short pos, Chave key, BTPAGE page) {
BTPAGE filha, irma_filha;
Chave workkeys[MAXKEYS];
short workch[MAXKEYS + 1];
short pos_key;
int j = 0, i = 0, posicao_relativa_irma = 0; // Diz se a irma escolhida eh da direira ou esquerda 0 ESQ e 1 DIR
filha = btread(page.child[pos]);
if (pos == 0) {
irma_filha = btread(page.child[pos + 1]);
posicao_relativa_irma = 1;
} else if (pos == page.keycount)
irma_filha = btread(page.child[pos - 1]);
else {
irma_filha = btread(page.child[pos - 1]);
if (irma_filha.keycount < MINKEYS) {
irma_filha = btread(page.child[pos + 1]);
posicao_relativa_irma = 1;
}
}
if (irma_filha.keycount == MINKEYS) {
while (strcmp(filha.key[i].chave, NOKEY) != 0) {
workkeys[i] = filha.key[i];
workch[i] = filha.child[i];
i++;
}
if (!posicao_relativa_irma)
pos--;
workkeys[i] = page.key[pos];
workch[i] = filha.child[i];
j = i + 1;
i = 0;
while ((strcmp(irma_filha.key[i].chave, NOKEY) != 0) && (j < MAXKEYS)) {
workkeys[j] = irma_filha.key[i];
workch[j] = irma_filha.child[i];
i++;
j++;
}
workch[j] = irma_filha.child[i];
shellSort(&workkeys, MAXKEYS);
/* Gravando e zerando a Pagina que vai ficar vazia, pois RRN nao pode ser reutilizado
* e preciso verificar se a pagina eh da esquerda ou direita por conta de sempre gravar
* na filha esquerda da pagina, assim pos é recontado
*/
irma_filha.keycount = 0;
if (!posicao_relativa_irma) {
pos++;
btwrite(page.child[pos], &irma_filha);
pos--;
} else
btwrite(page.child[pos], &irma_filha);
// Fim do gravar pagina zerada devido a concatenacao ###############################
fixup_page(rrn, pos, &page);
for (i = 0; i < MAXKEYS; i++)
filha.key[i] = workkeys[i];
if (posicao_relativa_irma == 0) { // Verifica se irma da pagina eh a ersquerda ou direita, muda a atribuicao a ordem
for (i = 0; i <= MINKEYS; i++) {
filha.child[i] = workch[MINKEYS + i];
filha.child[MINKEYS + i + 1] = workch[i];
}
} else {
for (i = 0; i <= MAXKEYS; i++) {
filha.child[i] = workch[i];
}
}
filha.keycount = MAXKEYS;
btwrite(page.child[pos], &filha);
/*Gravando a irma que fica com 0 chaves, dai depende se é da esquerda ou direira,
* pois foi decrementado antes se fosse direita pra sempre gravar na esquerda
por conta dos irmao da pagina pderem ser deslocados*/
btwrite(rrn, &page);
}
/* Verifica se o underflow eh na raiz e se ela tem pelo menos uma chave, pois ela pode, caso contrario
* a Raiz tem 0 chaves e ocorre concatenacao no remocao recursivo, e o root recebe o rrn
* da nova raiz que eh a filha desse escopo
*/
if ((page.keycount == 1) && (rrn == root))
return (NO);
if ((page.keycount == 0) && (rrn == root)) {
root = page.child[pos];
return (YES);
}
//Retorna se deu underflow no pai, para fazer redistribuicao ou concatenacao
if ((page.keycount < MINKEYS))
return (YES);
return (NO);
}
/* Funcao Driver que chama a remoção recursiva
* recebe o RRN da Raiz e a chave a remover
* Caso de unerflow na raiz e ela fique com zero chave, eh setado no arquivo
* quer será a proxima raiz, assim a concatenação feita anteriormente eh a respectiva raiz
*/
void remove_key(short rrn, Chave key) {
int underflow, is_change = 0; /* Boolean pra underflow e int para eh troca ou nao */
Chave promo_key; /* Chave de troca entre pai e filho */
BTPAGE page;
page = btread(root);
underflow = recursive_remove_key(rrn, key, &is_change, &promo_key);
if (underflow)
putroot(root);
}
/* Ai tah a danada da remoção, Complicado viu, Graças a Deus que eu Consegui
* Ela recebe o RRN da pagina corrente onde tah buscando a chave a remover,
* a chave em sim, um int que verifica se esta havendo uma troca e por fim
* uma chave auxiliar que guarda a chave que sera trocada entre pai e filho
* Ela retorna recursivamente pra cada nivel se deu ou nao split, assim sao tratados
* os momentos de chamar a Distribuição e a remoção, lembrando que só Concateno quando
* nao eh possivel fazer a dsitribuição. Outros comentarios estao dentro.
*/
int recursive_remove_key(short rrn, Chave key, int *is_change, Chave * aux_key) {
BTPAGE page; /* Pagina corrente */
int found, underflow; /* Valores booleanos para underflow e chave encontrada */
short pos; /* Posicao de onde chave ocorre ou deveria ocorrer */
Chave p_b_key; /* Chave de troca entre pai e filho */
if (rrn == NIL) { /* Chegou no NIL, volta o nivel */
return (NO);
} else {
page = btread(rrn); // le a pagina do rrn corrente
if (!*is_change) // Verifica se eh troca
found = search_node(key, &page, &pos); // Caso nao seja troca, procura a chave na pagina
else {
pos = 0; // caso seja troca, vou pra esquerda a procura do sucessor
found = 1; // Pra isso entro no encotrado e faços a verificações, pois aqui ou encontra ou encontra
}
if (found) { // caso encontrado eu entro
if ((page.keycount > MINKEYS) || (page.child[pos] != -1)) { //Verifica qnt de chave ou se nao eh folha, no caso da troca de chave
if (page.child[pos] == -1) { // se for folha eu achei a chave que quero, seja pra troca ou remoção ela sera removida
*aux_key = page.key[pos]; // Guardo a chave pra trocar com o pai se for o caso
fixup_page(rrn, pos, &page); // Arrumo a folha sem a chave da posicao pos
btwrite(rrn, &page);
return (NO);
} else { // eh troca e nao eh folha, tenho que buscar a successora
*is_change = 1;
underflow = recursive_remove_key(page.child[pos + 1], key, is_change, &p_b_key);
page.key[pos] = p_b_key; // Depois de buscar a sucessora, seto ela para o pai
btwrite(rrn, &page);
if (underflow) { // Houve underflow na troca, eu tento distribuir, senao concatenar
if (redistribution(rrn, (pos + 1), key, page)) {
return (NO);
} else {
return (concatenation(rrn, (pos + 1), key, page)); // Concatenacao retorna se deu underflow no pai
}
}
*is_change = 0; // Aqui nao deu underflow, tah todo mundo feliz, volto a troca pra falso
return (NO);
}
} else { // quantidade de chave eh menor ou igual a minimo e eh pagina folha pra remover
if (*is_change) { // Verifico se eh troca, pois preciso guardar a chave de troca antes de excluir
if (page.child[pos] == -1) {
*aux_key = page.key[pos];
fixup_page(rrn, pos, &page);
btwrite(rrn, &page);
}
} else { // Nao eh troca eu removo normalmente
if (page.child[pos] == -1) {
fixup_page(rrn, pos, &page);
btwrite(rrn, &page);
}
}
return (YES); // retorna YES para underflow, pois como tinha o minimo de chave e eu removi mais uma, se deduz que...
}
} // Chave nao encotrada, dai eu busco na filha onde deveria ocorrer
underflow = recursive_remove_key(page.child[pos], key, is_change, &p_b_key);
if (underflow) { // Se deu underflow no pai e eh possivel de didistribuir eu o faço e retorno nao
if (redistribution(rrn, pos, key, page))
return (NO);
else /* caso nao de pra redistribuir, eu concateno e retorno o valor da concatenação, que indicará se de underflow na raiz */
return (concatenation(rrn, pos, key, page));
}
}
return (NO);
}
/* Imprime a arvore de indices em ordem de nivel,
* por exeplo, imprime a raiz, sua filha, sua neta, sua bisneta e vai indo, depois volta imprimindo
* as irmas da filha, da neta, da bisneta
* recebe o RRN da raiz
*/
void print_btree(short rrn) {
BTPAGE page;
int i;
page = btread(rrn);
//print pagina #
printf("RRN %d\t", rrn);
printf("Qtd Chave %d\t", page.keycount);
//print chave na pagina
for (i = 0; i < page.keycount; ++i)
printf("%s ", page.key[i].chave);
//adiciona espaços
for (i = page.keycount; i < MAXKEYS; ++i)
printf(" ");
printf("\t");
//print filhos da pagina
for (i = 0; i <= page.keycount; ++i)
printf("%ld ", page.child[i]);
printf("\n");
//print o nivel a baixo e proximo da recursivamente
for (i = 0; i <= page.keycount; ++i) {
if (page.child[i] != NIL)
print_btree(page.child[i]);
}
return;
}