Arvore de pesquisa binaria [RESOLVIDO]

1. Arvore de pesquisa binaria [RESOLVIDO]

Jose Rogerio Almeida Junior
almeidajr

(usa Ubuntu)

Enviado em 31/05/2017 - 10:50h

Estou com dificuldades em criar uma arvore binaria, se alguém puder me ajudar.
Meu código até o momento:


#include <iostream>
#include <ctype.h>
#include <cstring>

using namespace std;

struct arvore
{
char nome[20];
int chave;
arvore *esq, *dir;
};

void inserir (arvore *raiz, char name[], int key)
{
if (raiz == NULL)
{
arvore *aux;
aux = new (arvore);

strcpy (raiz->nome, name);
aux->chave = key;
aux->dir = NULL;
aux->dir = NULL;

raiz = aux;
}
else
{
if (key > raiz->chave)
{
inserir (raiz->dir, name, key);
}
else
{
inserir (raiz->esq, name, key);
}
}

}

int main ()
{
arvore *raiz;
int i, key[8] = {5, 8, 1, 3, 4, 0, 6, 2};
char name[8][20] = {"Ana", "Pedro", "Andre", "Maria", "Paulo", "Carla", "Julia", "Marcos"};

raiz = NULL;

cout<<"Insercao em uma arvore binaria dos valores:\n(Ana, 5); (Pedro, 8); (Andre, 1); (Maria, 3);\n(Paulo, 4); (Carla, 0); (Julia, 6); (Marcos, 2);";

for (i = 0; i < 8; i++)
{
inserir (raiz, name[i], key[i]);
}

return 0;
}




  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 01/06/2017 - 13:46h

almeidajr escreveu:

Eu deveria criar então:
void inserir (arvore **raiz, char name[], int key) 


É o mais comum, especialmente para quem vem do C. Mas uma alternativa seria fazer do seguinte modo.

void inserir(arvore * &raiz, const char *name, int key) 


raiz é uma referência para ponteiro para arvore. O compilador cuida de criar a passagem por referência, sem que você tenha de obter explicitamente o endereço do objeto a ser alterado. Já o atributo const, aplicado ao nome, é para deixar claro que a função não vai modificar o conteúdo apontado pelo ponteiro recebido pelo parâmetro name.

Na hora de chamar a função que recebe a referência, eis como poderia ficar.

arvore *raiz;
char nome[20];
int chave;
/* ... */
inserir(raiz, nome, chave); // Note que eu NÃO disse “&raiz”.


Também, no corpo da função, você não precisaria se preocupar com o duplo grau de ponteiros, pois a referência abstrai isso para você, de modo que o parâmetro raiz se comporta como se fosse um simples ponteiro para arvore.

{	
if (*raiz == NULL)
{
arvore *aux;
aux = new (arvore);

strcpy (*raiz->nome, name);
aux->chave = key;
aux->dir = NULL;
aux->dir = NULL;

*raiz = aux;
}


Não precisa da variável auxiliar; você poderia operar diretamente sobre o ponteiro recebido.

if(raiz==nullptr)
return; // Com ponteiro de ponteiro, é importante garantir que o ponteiro mais externo é valido.
if(*raiz==nullptr){
*raiz=new arvore; // Sem parênteses desnecessários (e potencialmente perigosos).
// É necessário usar parênteses em volta de “*raiz” porque o operador “->” tem precedência maior
// que o operador unário “*”.
(*raiz)->chave=key;
strncpy((*raiz)->nome, name, 19); // Garante que nome não vai exceder tamanho máximo.
(*raiz)->nome[19]='\0'; // E garante a presença do terminador da string nesse nome.
(*raiz)->dir=(*raiz)->esq=nullptr;
}


Se, contudo, você adotar a versão com referência, o primeiro teste se torna desnecessário (uma referência terá sempre um objeto associado, nunca será um ponteiro nulo), e a sintaxe do restante fica bem mais simples.

if(raiz==nullptr){
raiz=new arvore;
raiz->chave=key;
strncpy(raiz->nome, name, 19);
raiz->nome[19]='\0';
raiz->dir=raiz->esq=nullptr;
}


	else
{
if (key > *raiz->chave)
{
inserir (*raiz->dir, name, key);
}
else
{
inserir (*raiz->esq, name, key);
}
}


As invocações acima estão erradas. O certo seria o seguinte.

else if(key > (*raiz)->chave)
inserir(&(*raiz)->dir, name, key); // Operador de obtenção de endereço é “&”, não “*”.
else
inserir(&(*raiz)->esq, name, key);


Se você preferir fazer com referência com o parâmetro, de novo as ocorrências de “(*raiz)” se tornam apenas “raiz”, e o “&” some.

else if(key > raiz->chave)
inserir(raiz->dir, name, key); // Operador de obtenção de endereço é “&”, não “*”.
else
inserir(raiz->esq, name, key);


}  


E dentro da função principal chamar a função como:

for (i = 0; i < 8; i++)
{
inserir (&raiz, name[i], key[i]);
}



OK aí, a não ser que você decida usar o parâmetro como referência para ponteiro. Nesse caso, a chamada a inserir ficaria do seguinte modo.

    inserir(raiz, name[i], key[i]); 



De novo, porém, eu convido você a tratar seus dados como objetos.

Tome os passos necessários para inicializar um nó dentro de um construtor do tipo arvore, como eu mostrei na primeira mensagem (o único erro daquele mensagem foi não ter percebido que o primeiro parâmetro de inserir() estava sendo passado por valor — aliás, eu editei aquela postagem para mostrar o recebimento do parâmetro por referência). Fazendo isso, veja como inserir() ficou enxuta.

3. Re: Arvore de pesquisa binaria

Paulo
paulo1205

(usa Ubuntu)

Enviado em 31/05/2017 - 13:16h

Numa olhada rápida, não vi erro nenhum que saltasse aos olhos. Tem algum sintoma específico?

Permita-me fazer uma sugestão. Como você está usando C++, use um construtor para a classe que representa os nós da sua árvore. Por exemplo:

struct arvore
{
char nome[20];
int chave;
arvore *esq, *dir;

arvore(const char *_nome, inst _chave):
chave(_chave), esq(nullptr), dir(nullptr)
{
strncpy(nome, _nome, 19);
nome[19]='\0';
}
};


Assim, na hora de criar um elemento novo na sua raiz, você poderia fazer do seguinte modo.

void inserir(arvore * &raiz, const char *name, int key){
if(!raiz)
raiz=new arvore(name, key);
else if(key>raiz->chave)
inserir(raiz->dir, name, key);
else
inserir(raiz->esq, name, key);
}


EDIT (2017/06/01): Corrigi a implementação acima para receber raiz por referência.


4. Re: Arvore de pesquisa binaria [RESOLVIDO]

Jose Rogerio Almeida Junior
almeidajr

(usa Ubuntu)

Enviado em 31/05/2017 - 13:30h

paulo1205 escreveu:

Numa olhada rápida, não vi erro nenhum que saltasse aos olhos. Tem algum sintoma específico?

Permita-me fazer uma sugestão. Como você está usando C++, use um construtor para a classe que representa os nós da sua árvore. Por exemplo:

struct arvore
{
char nome[20];
int chave;
arvore *esq, *dir;

arvore(const char *_nome, inst _chave):
chave(_chave), esq(nullptr), dir(nullptr)
{
strncpy(nome, _nome, 19);
nome[19]='\0';
}
};


Assim, na hora de criar um elemento novo na sua raiz, você poderia fazer do seguinte modo.

if(!raiz)
raiz=new arvore(name, key);
else if(key>raiz->chave)
inserir(raiz->dir, name, key);
else
inserir(raiz->esq, name, key);


No momento em que compilo para fazer um teste se esta tudo ok nessa parte do código, não acorre nem um erro do compilação.
No entanto, o programa entra em loop e me retorna um erro.

Ainda estou no começo da matéria estou aprendendo ainda, então não entendi muito bem do seu código e o que eu teria que mudar exatamente, mas obrigado.



5. Re: Arvore de pesquisa binaria [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 31/05/2017 - 14:27h

Caramba! Não sei como não vi antes, mas ficou muito claro quando você descreveu o sintoma.

O problema é que você está alterando os ponteiros dos parâmetros da função, que são meras cópias dos valores que deveriam realmente ser modificados.

Quando você diz, por exemplo, insere(raiz, nome, chave), você quer que o valor que raiz tem fora da função seja alterado pela função. Para tanto, o primeiro argumento tem de ser passado à função por referência, não por (cópia de) valor, que é o modo padrão do C ou do C++.




6. Re: Arvore de pesquisa binaria [RESOLVIDO]

Jose Rogerio Almeida Junior
almeidajr

(usa Ubuntu)

Enviado em 31/05/2017 - 22:36h

paulo1205 escreveu:

Caramba! Não sei como não vi antes, mas ficou muito claro quando você descreveu o sintoma.

O problema é que você está alterando os ponteiros dos parâmetros da função, que são meras cópias dos valores que deveriam realmente ser modificados.

Quando você diz, por exemplo, insere(raiz, nome, chave), você quer que o valor que raiz tem fora da função seja alterado pela função. Para tanto, o primeiro argumento tem de ser passado à função por referência, não por (cópia de) valor, que é o modo padrão do C ou do C++.



Eu deveria criar então:
void inserir (arvore **raiz, char name[], int key)
{
if (*raiz == NULL)
{
arvore *aux;
aux = new (arvore);

strcpy (*raiz->nome, name);
aux->chave = key;
aux->dir = NULL;
aux->dir = NULL;

*raiz = aux;
}
else
{
if (key > *raiz->chave)
{
inserir (*raiz->dir, name, key);
}
else
{
inserir (*raiz->esq, name, key);
}
}
}


E dentro da função principal chamar a função como:

for (i = 0; i < 8; i++)
{
inserir (&raiz, name[i], key[i]);
}




7. Re: Arvore de pesquisa binaria [RESOLVIDO]

Jose Rogerio Almeida Junior
almeidajr

(usa Ubuntu)

Enviado em 06/06/2017 - 08:37h

Muito obrigado por sua ajuda consegui entender meu erro.
Demorei a voltar, por estar em semana de provas na faculdade.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts