Ordenaçao externa multicaminhos utilizando metodo mergesort

1. Ordenaçao externa multicaminhos utilizando metodo mergesort

Bruno
uNclear

(usa Slackware)

Enviado em 09/03/2017 - 15:57h

Eu fiz um codigo de ordenaçao externa que separa a quantidade dos dados contidos no arquivo em 2, e começa a ordenar apatir dai como se fosse um mergesort, agora preciso fazer um codigo q utiliza multicaminhos, ou seja, que separa o arquivo em 3, 4 ou mais. Alguem ai sabe me falar se o codigo complica mt a cada vez que eu dividir mais o arquivo?

Espero ter sido claro.
Obrigado!


  


2. Re: Ordenaçao externa multicaminhos utilizando metodo mergesort

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/03/2017 - 16:17h

Nunca tive de fazer isso, mas não creio que fique muito mais difícil.

No caso específico do merge, a dificuldade será que você terá de comparar n valores, e escolher o menor (ou o maior) entre eles, em vez de comparar só dois. Será o clássico algoritmo de presumir que o valor a ser usado será o primeiro, e depois varrer os outros n-1 valores, sendo que a cada vez que um valor mais adequado for encontrado, você muda a sua presunção, até ter examinado todos os n, com a pequena dificuldade adicional de que qualquer um desses n pode, a qualquer momento, estar ausente (i.e. aquele ramo já esgotou todos os valores).


3. Ordenaçao externa multicaminhos utilizando metodo mergesort

Bruno
uNclear

(usa Slackware)

Enviado em 09/03/2017 - 16:21h

paulo1205 escreveu:

Nunca tive de fazer isso, mas não creio que fique muito mais difícil.

No caso específico do merge, a dificuldade será que você terá de comparar n valores, e escolher o menor (ou o maior) entre eles, em vez de comparar só dois. Será o clássico algoritmo de presumir que o valor a ser usado será o primeiro, e depois varrer os outros n-1 valores, sendo que a cada vez que um valor mais adequado for encontrado, você muda a sua presunção, até ter examinado todos os n, com a pequena dificuldade adicional de que qualquer um desses n pode, a qualquer momento, estar ausente (i.e. aquele ramo já esgotou todos os valores).



O meu merge esta terminando antes de ordenar todo o arquivo. Visto que, dividi o arquivo principal em 3, o laço que checa se os 3 chegaram ao fim esta terminando antes de efetuar todas as ordenaçoes. E parece que as comparaçoes estao corretas.
Uma das soluçoes que pensei que primeiro ordenar 2 partes e depois ordernar com a 3 parte, mas n sei se ficaria bom


4. Re: Ordenaçao externa multicaminhos utilizando metodo mergesort

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/03/2017 - 17:00h

Você pode sim, fazer um merge de 2, e depois fazer um merge desse resultado com um terceiro, mas eu acho que não é a melhor saída.

Você pode mostrar essa parte do código, para tentarmos ajudar a ver por que motivo está parando antes do fim?


5. Re: Ordenaçao externa multicaminhos utilizando metodo mergesort

Bruno
uNclear

(usa Slackware)

Enviado em 09/03/2017 - 17:11h

paulo1205 escreveu:

Você pode sim, fazer um merge de 2, e depois fazer um merge desse resultado com um terceiro, mas eu acho que não é a melhor saída.

Você pode mostrar essa parte do código, para tentarmos ajudar a ver por que motivo está parando antes do fim?




bool intercalaBloco(ifstream auxE[3], ofstream auxS[3], int passo, int saida){
//consideramos inicialmente que nao ia fazer nenhuma intercalaçao
bool intercalou = false;
Dado dados[3];

//posicao relativa de leitura em cada um dos arquivos
int pos[3] = {0, 0, 0};

//variavel para informar se os dados do arquivos sao validos (se foram lidos do arquivo de entrada e ainda nao gravados no arquivo de saida)
bool valido[3] = {false, false, false};

//em cada passo de tamanho n lemos n dados de cada arquivo e fazemos intercalaçao parcial em um novo bloco de tamanho 3*n no arquivo de saida utilizado
while( (pos[0] + pos[1] + pos[2]) < (3*passo) ){
//inicialmente verificamos se ha dados para ler
if( (pos[0] < passo) && (!valido[0]) ){
//tentamos ler do arquivo, verificando se a leitura foi valida, leitura invalida -> final do arquivo
if(auxE[0].read((char*) &dados[0], sizeof(Dado)) ){
valido[0] = true;
} else{
//para encerrer o while e nao entrar no if novamente
pos[0] = passo;
}
}

// repetimos o processo para o segundo arquivo
if( (pos[1] < passo) && (!valido[1]) ){
if(auxE[1].read((char*) &dados[1], sizeof(Dado)) ){
valido[1] = true;
} else{
//para encerrer o while e nao entrar no if novamente
pos[1] = passo;
}
}

if( (pos[2] < passo) && (!valido[2]) ){
if(auxE[2].read((char*) &dados[2], sizeof(Dado)) ){
valido[2] = true;
} else{
//para encerrer o while e nao entrar no if novamente
pos[2] = passo;
}

}

//nesse momento temos dados lidos dos 3 arquivos a nao ser que um (ou ambos) tenha chegado ao fim

//1º caso, os dois dados sao validos
if( (valido[0] && valido[1] )&& valido[2] ){
//marca que intercalou
intercalou = true;
//gravamos o menor valor no arquivo de saida
if(dados[0].chave1 <= dados[1].chave1 && (dados[0].chave1 <= dados[2].chave1)){
auxS[saida].write( (char*) &dados[0], sizeof(Dado) );
//dado utilizado nao e mais valido, avança posiçao
valido[0] = false;
pos[0]++;
}else if(dados[1].chave1 <= dados[0].chave1 && (dados[1].chave1 <= dados[2].chave1)){
auxS[saida].write( (char*) &dados[1], sizeof(Dado) );
//dado utilizado nao e mais valido, avança posiçao
valido[1] = false;
pos[1]++;
}else if(dados[2].chave1 <= dados[0].chave1 && (dados[2].chave1 <= dados[1].chave1)){
auxS[saida].write( (char*) &dados[2], sizeof(Dado) );
//dado utilizado nao e mais valido, avança posiçao
valido[2] = false;
pos[2]++;
}
/*else{
auxS[saida].write( (const char*) &dados[1], sizeof(Dado) );
//dado utilizado nao e mais valido, avança posiçao
valido[1] = false;
pos[1]++;
}*/
}

//2º caso, apenas o primeiro dado e valido
else if(valido[0]){
//marca que intercalou
intercalou = true;
auxS[saida].write( (char*) &dados[0], sizeof(Dado) );
//dado utilizado nao e mais valido, avança posiçao
valido[0] = false;
pos[0]++;
}

//3º caso, apenas o segundo dado e valido
else if(valido[1]){
//marca que intercalou
intercalou = true;
auxS[saida].write( (char*) &dados[1], sizeof(Dado) );
//dado utilizado nao e mais valido, avança posiçao
valido[1] = false;
pos[1]++;
}
else if(valido[2]){
//marca que intercalou
intercalou = true;
auxS[saida].write( (char*) &dados[2], sizeof(Dado) );
//dado utilizado nao e mais valido, avança posiçao
valido[2] = false;
pos[2]++;
}
//se chegou aqui termina o while na proxima iteraçao
else {

}
}
return intercalou;
}

void mergeexterno(ifstream &arqEntrada, ofstream &arqSaida){
ofstream arqB1 ("arqB1.dat", ios::binary);
ofstream arqB2 ("arqB2.dat", ios::binary);
ofstream arqB3("arqB3.dat", ios::binary);

if((!arqB1) && (!arqB2) && (!arqB3)){
cerr << "Arquivos auxiliares nao puderam ser abertos (arqB1.dat ou arqB2.dat )" << endl;
exit(EXIT_FAILURE);
}

Dado umDado;

//posicionando ponteiro de leitura no final do arquivo
arqEntrada.seekg(0, ios::end);

//obtendo a posicao final do arquivo
int tamanho = arqEntrada.tellg();

//dado o tamanho do arquivo, sabe-se quantos registos ha no arquivo
int numRegistros = tamanho / sizeof(Dado);
cout << numRegistros << endl;
//metade do numero de registros (arredondado pra cima)
int metade = (numRegistros / 3) + 0.5;
cout << metade << endl;
//posicionando ponteiro de leitura no inicio do arquivo
arqEntrada.seekg(0, ios::beg);

//copiando dados para 3 arquivos auxiliares
for(int i = 0; i < metade; i++){
arqEntrada.read((char*) &umDado, sizeof(Dado) );
arqB1.write((char*) &umDado, sizeof(Dado) );
}
for(int i = metade; i < metade * 2; i++){
arqEntrada.read((char*) &umDado, sizeof(Dado) );
arqB2.write((char*) &umDado, sizeof(Dado) );
}
for(int i = metade * 2; i < numRegistros; i++){
arqEntrada.read((char*) &umDado, sizeof(Dado));
arqB3.write((char*) &umDado, sizeof(Dado));
}

//finalizaçao primeira etapa
arqB1.close();
arqB2.close();
arqB3.close();
arqEntrada.close();

//arquivos auxiliares
ifstream auxEntrada[3];
ofstream auxSaida[3];

//variaveis de controle
int passo = 1;
bool ida = true;
bool ultimo[3];

//laço principal
while(passo <= numRegistros){
if(ida){
auxEntrada[0].open("arqB1.dat", ios::binary);
auxEntrada[1].open("arqB2.dat", ios::binary);
auxEntrada[2].open("arqB3.dat", ios::binary);
auxSaida[0].open("arqC1.dat", ios::binary);
auxSaida[1].open("arqC2.dat", ios::binary);
auxSaida[2].open("arqC3.dat", ios::binary);
}else{
auxEntrada[0].open("arqC1.dat", ios::binary);
auxEntrada[1].open("arqC2.dat", ios::binary);
auxEntrada[2].open("arqC3.dat", ios::binary);
auxSaida[0].open("arqB1.dat", ios::binary);
auxSaida[1].open("arqB2.dat", ios::binary);
auxSaida[2].open("arqB3.dat", ios::binary);
}

if( (!auxEntrada[0]) || (!auxEntrada[1]) || (!auxSaida[0]) || (!auxSaida[1]) || (!auxEntrada[2]) || (!auxSaida[2]) ){
cerr << "Arquivos auxiliares nao podem ser abertos (arqB1.dat ou arqB2.dat ou arqC1.dat ou arqC2.dat)" << endl;
exit(EXIT_FAILURE);
}

//enquanto nao chegar ao final dos arquivos de entrada, vai intercalando os blocos
while( (!auxEntrada[0].eof()) && (!auxEntrada[1].eof()) && (!auxEntrada[2].eof()) ){
ultimo[0] = intercalaBloco(auxEntrada, auxSaida, passo, 0);
ultimo[1] = intercalaBloco(auxEntrada, auxSaida, passo, 1);
ultimo[2] = intercalaBloco(auxEntrada, auxSaida, passo, 2);
}

//fecha arquivos para permitir troca escrita <-> leitura, na proximo interaçao
auxEntrada[0].close();
auxEntrada[1].close();
auxEntrada[2].close();
auxSaida[0].close();
auxSaida[1].close();
auxSaida[2].close();

ida = !ida;
passo *= 3;
}

//merge terminado, agora lemos do arquivo auxiliar para arquivo de saida
ifstream auxEnt;

//identifique o arquivo auxiliar com dados ordenados
if(ida){
if(ultimo[0]){
auxEnt.open("arqB1.dat", ios::binary);
}else if(ultimo[1]){
auxEnt.open("arqB2.dat", ios::binary);
}else if(ultimo[2]){
auxEnt.open("arqB3.dat", ios::binary);
}
}else{
if(ultimo[0]){
auxEnt.open("arqC1.dat", ios::binary);
}else if(ultimo[1]){
auxEnt.open("arqC2.dat", ios::binary);
}else if(ultimo[2]){
auxEnt.open("arqC3.dat", ios::binary);
}
}

if(!auxEnt){
cerr << "Arquivo auxiliar nao pode ser aberto" << endl;
exit(EXIT_FAILURE);
}

while(auxEnt.read((char*) &umDado, sizeof(Dado)) ){
arqSaida.write((const char*) &umDado, sizeof(Dado) );
}

auxEnt.close();

//apagar arquivos auxiliares
remove("arqB1.dat");
remove("arqB2.dat");
remove("arqC1.dat");
remove("arqC2.dat");
remove("arqC3.dat");
remove("arqB3.dat");

}

Obrigado mais uma vez pela ajuda o/


6. Re: Ordenaçao externa multicaminhos utilizando metodo mergesort

Paulo
paulo1205

(usa Ubuntu)

Enviado em 10/03/2017 - 11:11h

Olha, eu não olhei muito profundamente, mas acho que a a função intercalaBloco() pode ficar mais simples e, ao mesmo tempo, mais genérica.

Sem querer implementar uma substituição pronta, deixe-me mostrar um esquema de como poderia ficar.

/*
Lê um elemento do tipo Dado a partir da posição corrente de um stream de entrada.
*/
std::istream &operator>>(std::istream &source, Dado &d){
// Não tenta ler se o stream já estiver marcado com falha.
if(source){
/*
Implemente de acordo com o tipo de dados “Dado”. Se ele for
um POD, pode ser que um simples

source.read(reinterpret_cast<char *>(&d), sizeof d);

baste. Mas se for um tipo mais complexo, você pode ter de ler
membro a membro a partir de source.
*/
}
return source;
}

/*
Lê n elementos do tipo Dado para uma fila de elementos desse tipo, a qual
serve como buffer. Assume o tamanho default da fila com 8 elementos.
*/
unsigned leBufDados(std::istream &source, std::deque<Dado> &queue, unsigned n=8){
Dado d;
unsigned i;
for(i=0; i<n && (source >> d); i++)
queue.push_back(std::move(d)); // Se Dado for um POD, remova a chamada a std::move(), deixando só d.
return i;
}

/*
Função que faz o merge externo a partir de um vetor de arquivos (via ponteiros para
streams) de entrada para um arquivo de saída. Retorna um flag indicando se a saída
foi gravada com sucesso e se chegou ao fim de todos os arquivos de entrada.
*/
bool intercalaBloco(std::vector<std::istream *> &v_in, std::ostream &out){
unsigned N=v_in.size();
std::vector<std::deque<Dado>> buffer(N); // Cria vetor de buffers, um para cada arquivo.

// Se o stream de saída não for válido, interrompe o merge.
while(out){
unsigned n;
for(n=0; n<N; n++)
if(buffer[n].size()>0 || leBufDados(*v_in[n], buffer[n]))
break; // Acho dado no primeiro arquivo que ainda não tiver acabado.
if(n==N)
break; // Fim de todos os arquivos de entrada: sai do loop de merge.

// Se chegou a este ponto, n indica o primeiro arquivo/buffer que tem dados.

// Assume que o dado desse arquivo é o próximo que tem de ir para a saída.
auto menor=&buffer[n];

/*
Examina os demais arquivos, para ver se algum deles ainda tem dados e se
esse dado é menor do que o escolhido até o momento.

EM TEMPO: note que eu comparo com “<” em lugar de “<=”. Fazendo com “<”,
eu garanto ordenação estável, ou seja, que registros com duas chaves
idênticas dispostas relativamente numa determinada ordem no arquivo
original aparecerão na mesma ordem relativa no arquivo de saída. Essa é
uma propriedade do Merge Sort que frequentemente é desejada, especial-
mente quando o arquivo é ordenado sucessivamente com diferentes chaves,
mas que você acabou desprezando ao fazer com “<=”.
*/
for(; n<N; n++)
if(
(buffer[n].size()>0 || leBufDados(*v_in[n], buffer[n])) &&
buffer[n].front().chave1 < menor->front().chave1
)
menor=&buffer[[n];

// Grava o menor no arquivo de saída e retira-o do seu buffer de entrada.
out << menor->front();
menor->pop_front();
}

for(n=0; n<N; n++)
if(!v_in[n].eof())
return false;
return out;
}



7. Re: Ordenaçao externa multicaminhos utilizando metodo mergesort

Bruno
uNclear

(usa Slackware)

Enviado em 10/03/2017 - 11:25h

paulo1205 escreveu:

Olha, eu não olhei muito profundamente, mas acho que a a função intercalaBloco() pode ficar mais simples e, ao mesmo tempo, mais genérica.

Sem querer implementar uma substituição pronta, deixe-me mostrar um esquema de como poderia ficar.



Vou dar uma matutada nesse código e ver o que consigo assimilar, mas pela a passada rápida que dei nele, parece que o problema do meu código esta na comparação das chaves para descobrir quem e a menor, visto que no código que você apresentou ele joga os valores para um fila para comparar. Estou correto?


8. Re: Ordenaçao externa multicaminhos utilizando metodo mergesort

Paulo
paulo1205

(usa Ubuntu)

Enviado em 10/03/2017 - 13:54h

Estou tentando pensar melhor sobre o problema. Está me parecendo mais complicado agora do que na primeira olhada.


9. Re: Ordenaçao externa multicaminhos utilizando metodo mergesort

Bruno
uNclear

(usa Slackware)

Enviado em 11/03/2017 - 00:59h

paulo1205 escreveu:

Estou tentando pensar melhor sobre o problema. Está me parecendo mais complicado agora do que na primeira olhada.


Eu to apanhando demais pra esse código, ja debuguei ele varias vezes e foi meu professor que fez a base do merge externo com 2 arquivos e mandou modificar pra mais 3, eu cheguei em várias conclusões diferentes. Mas a que me convence mais e que a lógica pra 2 arquivos não serve pra 3. Eu acho que o problema está no passo, o passo nao deveria aumentar so porque a quantidade de arquivos aumentou eu acho.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts