[C con Clase] De José Enrique
Manuel L.
notret en gmx.es
Mie Oct 13 20:55:19 CEST 2010
Hola, José Enrique Hernández Ramírez:
P> ¿Cuál sería la idea a seguir para la implementación de algún método existente de ordenamiento aplicado a las listas y a los árboles? Si es posible.
La idea es siempre la misma: que se cumpla una relación de orden entre los elementos. La diferencia es que en la lista los elementos se disponen secuencialmente y por tanto la relación será binaria, mientras que en los árboles los elementos se disponen arborescentemente y, de ser binarios, la relación será ternaria. Respecto a las listas cualquier método de ordenación que haya visto es aplicable. Si la implementación de las listas permite acceso aleatorio en tiempo constante (la lista es estática o dinámica con sublistas estáticas, por ejemplo) entonces los métodos clásicos son directamente aplicables; si no deberá o plantearse usar otra implementación o bien transferir momentáneamente los elementos de la lista a un vector y realizar allí la ordenación. En caso de los árboles, piense en ordenaciones como los montículos, los árboles equilibrados (o balanceados)... recuerde que en la librería estándar de C++ la clase vector implementa objetos lista con acceso aleatorio y puede usarlo en el procedimiento sort contenido en la cabecera algorithm. Si únicamente desea conservar orden en listas quizás esta sea una implementación adecuada para su problema.
P> Cuando lo que se tienen son números la idea( o criterio ) del ordenamiento es sencilla(ya sea de mayor a menor o al revés. Corríjanme si estoy equivocado)¿Qué criterio se tiene en cuenta para ordenar objetos?
La idea es siempre la misma: que se cumpla una relación de orden entre los elementos. ¿Qué relación? ¡No importa! Puede ser efectivamente de mayor a menor, puede ser que los primos vayan primero y en lo demás de mayor a menor salvo el número 3 que es el mayor de todos... con los objetos sucede lo mismo, pero, naturalmente, el criterio que sirva para ordenar tendrá que adecuarse a la naturaleza del objeto. En cualquier caso: puede abstraer los criterios para la ordenación en objetos o en funciones (como prefiera) y definir un método de ordenación genérico que simplemente ordene los elementos atendiendo a la relación que el programador le brinde. En C típicamente se hace con punteros a funciones y el manejo de punteros a void; en C++, mediante objetos (como en la librería estándar de C++) o mediante punteros a funciones y plantillas de funciones. Como esta es una lista de C++ supondré que es C++ lo que pretende usar, y como una de las implementaciones mediante objetos ya la puede encontrar en la librería estándar le ejemplifico el uso de las plantillas de funciones:
***********************
* Fichero ejemplo.h *
***********************
/* EJEMPLO de como implementar una ordenacion con independencia de los objetos
a usar. Para ello se realizan tres ordenaciones: un vector de enteros de mayor
a menor, un vector de enteros de mayor a menor salvo que todo par es mayor que
cualquier impar, y un vector de objetos de la clase string de menor a mayor */
#include <string>
using std::string;
/* Plantilla de funcion para quicksort, para que el compilador sustituya donde
sea necesario T por el tipo de datos que sea necesario */
template <typename T>
void quicksort(T *v,int tamano,bool (*relacion)(const T &o1,const T &o2));
// Plantilla de funcion para imprimir cualquier tipo de vector
template <typename T>
void imprimirVector(const T *v,int tamano);
// Funcion que implementa la relacion de orden de menorQue en enteros
bool enteroMayorQueEntero(const int &e1,const int &e2);
// Funcion que implementa la segunda relacion de orden entre enteros descrita
bool enteroMayorQueEspecialEntero(const int &e1,const int &e2);
// Funcion que implementa la relacion de orden menorQue en objetos string
bool StringMenorQueString(const string &s1,const string &s2);
// Punto de entrada al programa
int main();
*************************
* Fichero ejemplo.cpp *
*************************
#include <algorithm>
using std::swap; // intercambia el contenido de dos variables
#include <iostream>
using std::cout;
#include "ejemplo.h"
template <typename T>
void quicksort(T *v,int tamano,bool (*relacion)(const T &o1,const T &o2))
{
int tamanoPrimeraParte = 0;
T pivote = *(v + tamano/2);
swap(*(v + tamano/2),*(v + tamano - 1)); // asi el pivote quedara de ultimo
T *pSegundaParte = v,*pTmp = v;
for(int i=tamano;i;--i)
{
if( (*relacion)(*pTmp,pivote) )
{
swap(*pSegundaParte,*pTmp);
++tamanoPrimeraParte;
++pSegundaParte;
}
++pTmp;
}
swap(*(v + tamano - 1),*pSegundaParte); // se coloca el pivote entre ambas partes
if(tamanoPrimeraParte > 1) quicksort(v,tamanoPrimeraParte,relacion);
if(tamano - tamanoPrimeraParte > 1) quicksort(++pSegundaParte,tamano-tamanoPrimeraParte-1,relacion);
}
template <typename T>
void imprimirVector(const T *v,int tamano)
{
--tamano;
for(int i=0;i<tamano;++i) cout << v[i] << ", ";
cout << v[tamano] << ";\n";
}
bool enteroMayorQueEntero(const int &e1,const int &e2) { return e1 > e2; }
bool enteroMayorQueEspecialEntero(const int &e1,const int &e2)
{
if(e1 % 2)
if(e2 % 2) return e1 > e2;
else return false;
else
if(e2 % 2) return true;
else return e1 > e2;
}
bool StringMenorQueString(const string &s1,const string &s2) { return s1 < s2; }
// Punto de entrada al programa
int main()
{
int v1[5] = { 4,1,8,3,2 };
cout << "\n\nv1 antes de la ordenacion:\n";
imprimirVector(v1,5);
quicksort(v1,5,enteroMayorQueEntero);
cout << "v1 despues de la ordenacion:\n";
imprimirVector(v1,5);
int v2[5] = { 4,1,8,3,2 };
cout << "\nv2 antes de la ordenacion:\n";
imprimirVector(v2,5);
quicksort(v2,5,enteroMayorQueEspecialEntero);
cout << "v2 despues de la ordenacion:\n";
imprimirVector(v2,5);
string v3[5] = { "util","esta","Ojala","considere","muestra" };
cout << "\nv3 antes de la ordenacion:\n";
imprimirVector(v3,5);
quicksort(v3,5,StringMenorQueString);
cout << "v3 despues de la ordenacion:\n";
imprimirVector(v3,5);
cout << "\n\n";
return 0;
}
Más información sobre la lista de distribución Cconclase