#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
struct nod
{
void *info;
struct nod *ant, *prox;
};
typedef struct nod Nod;
struct listad
{
Nod *ini;
Nod *fim;
};
typedef struct listad Listad;
struct pagina
{
bool folha;
int qtdeChaves;
struct pagina *pai;
Listad *listaChaves;
struct pagina *direita;
};
struct chave
{
int valorChave;
struct pagina *filho;
};
struct arvoreb
{
struct pagina *raiz;
int ordem;
int altura;
};
typedef struct pagina Pagina;
typedef struct chave Chave;
typedef struct arvoreb Arvoreb;
Listad *cria_listad()
{
Listad
*L
= (Listad
*)malloc(sizeof(Listad
)); L->fim = L->ini = NULL;
return L;
}
Nod *cria_nod(void *info)
{
Nod
*novo
= (Nod
*)malloc(sizeof(Nod
)); novo->ant = novo->prox = NULL;
novo->info = info;
return novo;
}
Listad *insere_inicio_listad(Listad *L, void *info)
{
Nod *novo = cria_nod(info);
if (L == NULL)
{
L = cria_listad();
L->ini = L->fim = novo;
}
else
{
if (L->ini == NULL)
L->ini = L->fim = novo;
else
{
novo->prox = L->ini;
L->ini->ant = novo;
L->ini = novo;
}
}
return L;
}
Listad *insere_fim_listad(Listad *L, void *info)
{
Nod *novo = cria_nod(info);
if (L == NULL)
{
L = cria_listad();
L->ini = L->fim = novo;
}
else
{
if (L->ini == NULL)
L->ini = L->fim = novo;
else
{
novo->ant = L->fim;
L->fim->prox = novo;
L->fim = novo;
}
}
return L;
}
Nod *remove_inicio_listad(Listad *L)
{
Nod *aux = NULL;
if (L != NULL && L->fim != NULL) // caso haja elemento
{
aux = L->ini;
if (L->ini == L->fim)
{
L->ini = L->fim = NULL;
}
else
{
L->ini = L->ini->prox;
L->ini->ant = NULL;
}
}
return aux;
}
Nod *remove_fim_listad(Listad *L)
{
Nod *aux = NULL;
if (L != NULL && L->fim != NULL) // caso haja elemento
{
aux = L->fim;
if (L->ini == L->fim)
{
L->ini = L->fim = NULL;
}
else
{
L->fim = L->fim->ant;
L->fim->prox = NULL;
}
}
return aux;
}
Listad *libera_listad(Listad *L)
{
Nod *aux;
while (L->ini != NULL)
{
aux = L->ini;
L->ini = L->ini->prox;
}
L->fim = NULL;
return NULL;
}
Listad *divide_lista(Listad *L, int qtde)
{
Listad *nova_lista = cria_listad();
Nod *aux;
int i;
for (i = 0, aux = L->ini;
i < qtde;
i++, aux = aux->prox)
;
nova_lista->ini = aux;
nova_lista->fim = L->fim;
L->fim = aux->ant;
aux->ant = NULL;
L->fim->prox = NULL;
return nova_lista;
}
Arvoreb *cria_arvoreb(int ordem)
{
Arvoreb
*T
= malloc(sizeof(Arvoreb
)); T->altura = 0;
T->ordem = ordem;
T->raiz = NULL;
return T;
}
Pagina *cria_pagina()
{
Pagina
*nova
= malloc(sizeof(Pagina
)); nova->folha = true; // se é ou não uma folha
nova->qtdeChaves = 0;
nova->pai = NULL;
nova->direita = NULL;
nova->listaChaves = cria_listad();
return nova;
}
Chave *cria_chave(int nova_chave)
{
Chave
*nova
= malloc(sizeof(Chave
)); nova->filho = NULL;
nova->valorChave = nova_chave;
return nova;
}
Chave *getChave(Nod *aux)
{
return (aux->info);
}
Pagina *encontra_folha(Arvoreb *T, int nova_chave)
{
Pagina *aux_pg = T->raiz;
Nod *aux_no = NULL;
while (!aux_pg->folha) //(aux_pg->folha == 0) //nao é folha
{
aux_no = aux_pg->listaChaves->ini;
while (aux_no != NULL && nova_chave > getChave(aux_no)->valorChave)
aux_no = aux_no->prox;
if (aux_no == NULL)
aux_pg = aux_pg->direita;
else
aux_pg = getChave(aux_no)->filho;
}
return aux_pg;
}
Pagina *insere_chave_na_pagina(Pagina *pagina1, Chave *nova_chave)
{
if (pagina1 == NULL)
{
pagina1 = cria_pagina();
}
Nod *aux = pagina1->listaChaves->ini;
if (aux == NULL)
{
pagina1->listaChaves = insere_inicio_listad(pagina1->listaChaves, nova_chave);
}
else
{
if (nova_chave->valorChave < getChave(aux)->valorChave)
{
pagina1->listaChaves = insere_inicio_listad(pagina1->listaChaves, nova_chave);
}
else if (nova_chave->valorChave > getChave(pagina1->listaChaves->fim)->valorChave)
{
pagina1->listaChaves = insere_fim_listad(pagina1->listaChaves, nova_chave);
}
else // inserir ordenado
{
while (nova_chave->valorChave > getChave(aux)->valorChave)
{
aux = aux->prox;
}
Nod *novo_no = cria_nod(nova_chave);
novo_no->prox = aux;
novo_no->ant = aux->ant;
aux->ant->prox = novo_no;
aux->ant = novo_no;
}
}
pagina1->qtdeChaves++;
return pagina1;
}
Pagina *cria_nova_raiz(Chave *chave_subir, Pagina *filho_esq, Pagina *filho_dir)
{
Pagina *nova_raiz = cria_pagina();
nova_raiz = insere_chave_na_pagina(nova_raiz, chave_subir);
chave_subir->filho = filho_esq;
nova_raiz->direita = filho_dir;
filho_dir->pai = filho_esq->pai = nova_raiz;
nova_raiz->folha = false;
return nova_raiz;
}
Pagina *divide_pagina(Pagina *pagina_inserir)
{
Nod *aux_no;
Pagina *pai;
Pagina *nova_pagina = cria_pagina();
int qtde_chaves_lista
= ceil(pagina_inserir
->qtdeChaves
/ 2.0);
// atualizar a nova pagina
nova_pagina->listaChaves = divide_lista(pagina_inserir->listaChaves, qtde_chaves_lista);
nova_pagina->folha = pagina_inserir->folha;
nova_pagina
->qtdeChaves
= floor(pagina_inserir
->qtdeChaves
/ 2.0); nova_pagina->direita = pagina_inserir->direita;
nova_pagina->pai = pagina_inserir->pai;
// atualizar pagina dividida
pagina_inserir->qtdeChaves = qtde_chaves_lista;
pai = pagina_inserir->pai;
// quem vai apontar para a nova página
if (pagina_inserir->pai != NULL)
{
aux_no = pai->listaChaves->ini;
while (aux_no != NULL && getChave(aux_no)->filho != pagina_inserir)
aux_no = aux_no->prox;
if (aux_no == NULL)
pai->direita = nova_pagina;
else
getChave(aux_no)->filho = nova_pagina;
}
if (!nova_pagina->folha)
{
aux_no = nova_pagina->listaChaves->ini;
while (aux_no != NULL)
{
getChave(aux_no)->filho->pai = nova_pagina;
aux_no = aux_no->prox;
}
nova_pagina->direita->pai = nova_pagina;
// a direita da página que foi dividida
// precisa apontar para o mesmo lugar que
// a chave anterior a ela aponta
pagina_inserir->direita = getChave(pagina_inserir->listaChaves->fim)->filho;
}
// chave a subir, mudar filho
getChave(pagina_inserir->listaChaves->fim)->filho = pagina_inserir;
return nova_pagina;
}
bool direita_da_pag(Pagina *pagina_inserir, int ordem)
{
bool deu = true;
if (pagina_inserir->pai->listaChaves->fim != NULL)
{
Nod *aux_no = pagina_inserir->pai->listaChaves->fim;
if (getChave(aux_no)->filho->qtdeChaves < ordem - 1)
{
Nod *removido = remove_inicio_listad(pagina_inserir->listaChaves);
insere_fim_listad(getChave(aux_no)->filho->listaChaves, removido->info);
int aux = getChave(getChave(aux_no)->filho->listaChaves->fim)->valorChave;
int aux2 = getChave(aux_no)->valorChave;
getChave(getChave(aux_no)->filho->listaChaves->fim)->valorChave = aux2;
getChave(aux_no)->valorChave = aux;
pagina_inserir->qtdeChaves--;
getChave(aux_no)->filho->qtdeChaves++;
deu = false;
}
}
return deu;
}
bool direita_normal(Pagina *pagina_inserir, int ordem, Nod *aux_no)
{
bool deu = true;
if (getChave(aux_no->prox)->filho->qtdeChaves < ordem - 1)
{
Nod *fim = remove_fim_listad(pagina_inserir->listaChaves);
insere_inicio_listad(getChave(aux_no->prox)->filho->listaChaves, fim->info);
int aux = getChave(aux_no)->valorChave;
int aux2 = getChave(getChave(aux_no->prox)->filho->listaChaves->ini)->valorChave;
getChave(aux_no)->valorChave = aux2;
getChave(getChave(aux_no->prox)->filho->listaChaves->ini)->valorChave = aux;
pagina_inserir->qtdeChaves--;
getChave(aux_no->prox)->filho->qtdeChaves++;
deu = false;
}
return deu;
}
bool direita_geral(Pagina *pagina_inserir, int ordem, Nod *aux_no)
{
bool deu = true;
if (pagina_inserir->pai->direita->qtdeChaves < ordem - 1)
{
Nod *fim = remove_fim_listad(pagina_inserir->listaChaves);
insere_inicio_listad(pagina_inserir->pai->direita->listaChaves, fim->info);
int aux = getChave(pagina_inserir->pai->direita->listaChaves->ini)->valorChave;
int aux2 = getChave(aux_no)->valorChave;
getChave(pagina_inserir->pai->direita->listaChaves->ini)->valorChave = aux2;
getChave(aux_no)->valorChave = aux;
pagina_inserir->qtdeChaves--;
pagina_inserir->pai->direita->qtdeChaves++;
deu = false;
}
return deu;
}
bool esquerda_normal(Pagina *pagina_inserir, int ordem, Nod *aux_no)
{
bool deu = true;
if (getChave(aux_no->ant)->filho->qtdeChaves < ordem - 1 && aux_no->ant != NULL)
{
Nod *inicio = remove_inicio_listad(pagina_inserir->listaChaves);
insere_fim_listad(getChave(aux_no->ant)->filho->listaChaves, inicio->info);
int aux = getChave(getChave(aux_no->ant)->filho->listaChaves->fim)->valorChave;
int aux2 = getChave(aux_no->ant)->valorChave;
getChave(getChave(aux_no->ant)->filho->listaChaves->fim)->valorChave = aux2;
getChave(aux_no->ant)->valorChave = aux;
pagina_inserir->qtdeChaves--;
getChave(aux_no->ant)->filho->qtdeChaves++;
deu = false;
}
return deu;
}
bool confere_filhos(Pagina *pagina_inserir, int ordem)
{
Nod *aux_no = pagina_inserir->pai->listaChaves->ini;
bool confere = false;
while (aux_no != NULL && getChave(aux_no)->filho != pagina_inserir)
aux_no = aux_no->prox; // achou o pai
if (aux_no == NULL)
{ // esta na direita da pagina
confere = direita_da_pag(pagina_inserir, ordem);
}
else
{
if (aux_no->prox != NULL) // insere na direita
confere = direita_normal(pagina_inserir, ordem, aux_no);
if (!confere)
{ // esquerda ou direita geral e nao deu certo na direita normal
if (aux_no->prox == NULL)
{ // direita geral
confere = direita_geral(pagina_inserir, ordem, aux_no);
}
else if (aux_no->ant != NULL)
{ // esquerda
confere = esquerda_normal(pagina_inserir, ordem, aux_no);
}
}
}
return confere;
}
Arvoreb *insere_arvoreb(Arvoreb *T, int nova_ch, int *qnt_divisao)
{
bool tem_chave_para_inserir = true;
Pagina *nova_pagina;
Chave *nova_chave = cria_chave(nova_ch), *chave_subir;
Nod *aux;
bool confere = false;
// arvore for vazia
if (T == NULL || T->raiz == NULL)
{
T = cria_arvoreb(T->ordem);
T->raiz = insere_chave_na_pagina(T->raiz, nova_chave);
}
else
{
Pagina *pagina_inserir = encontra_folha(T, nova_ch);
while (tem_chave_para_inserir)
{
pagina_inserir = insere_chave_na_pagina(pagina_inserir, nova_chave);
// Chave *ch_subir = chave que vai subir
if (pagina_inserir->qtdeChaves < T->ordem) // nao estorou
{
tem_chave_para_inserir = false;
}
else // estorou
{
if (pagina_inserir->folha && pagina_inserir->pai != NULL)
tem_chave_para_inserir = confere_filhos(pagina_inserir, T->ordem);
if (tem_chave_para_inserir) // se nao conseguiu inserir na direita ou na esquerda divide
{
nova_pagina = divide_pagina(pagina_inserir);
(*qnt_divisao)++;
aux = remove_fim_listad(pagina_inserir->listaChaves);
pagina_inserir->qtdeChaves--;
chave_subir = aux->info;
if (pagina_inserir->pai == NULL) // folha é a raiz
{
T->raiz = cria_nova_raiz(chave_subir, pagina_inserir, nova_pagina);
T->altura++;
tem_chave_para_inserir = false;
}
else
{
pagina_inserir = pagina_inserir->pai;
nova_chave = chave_subir;
}
}
}
}
}
return T;
}
void em_ordem(Pagina *raiz)
{
Nod *aux;
if (raiz != NULL)
{
aux = raiz->listaChaves->ini;
while (aux != NULL)
{
em_ordem(getChave(aux)->filho);
printf("%d ", getChave
(aux
)->valorChave
); aux = aux->prox;
}
em_ordem(raiz->direita);
}
}
void libera_arvore(Pagina *raiz)
{
Nod *aux;
if (raiz != NULL)
{
aux = raiz->listaChaves->ini;
while (raiz->listaChaves->ini != NULL)
{
em_ordem(getChave(aux)->filho);
aux = raiz->listaChaves->ini;
raiz->listaChaves->ini = raiz->listaChaves->ini->prox;
}
raiz->listaChaves->fim = NULL;
em_ordem(raiz->direita);
}
}
int main()
{
Arvoreb *arvore = NULL;
Arvoreb *arvore_normal = NULL;
int ordem ;
int entrada;
int qnt_divisao = 0;
int qnt_divisao_normal = 0;
arvore = cria_arvoreb(ordem);
arvore_normal = cria_arvoreb(ordem);
while (entrada != -1)
{
if (entrada != -1)
{
arvore = insere_arvoreb(arvore, entrada, &qnt_divisao);
}
}
printf("%d %d\n", qnt_divisao
, arvore
->altura
); return 0;
}