select_best: Otro algoritmo de partición -- ++ campo con algorithm campo con c++11 camp codereview Relacionados El problema

select_best: yet another partitioning algorithm


6
vote

problema

Español

El título es algo un nombre inapropiado; mis disculpas. El objetivo del procedimiento es particionar un rango de paymentId3 por paymentId4 para la postcondition

  paymentId5  

El código real ( paymentId6 ):

  paymentId7  

Funciona bien si no incumplí nada.

Preguntas:

  • buscando mejoras generales.
  • ¿Qué es un nombre correcto?
  • Actualmente paymentId8 . ¿Hay algo útil para volver?
  • No me gusta pasar a Lambda a paymentId9 . ¿Alguna sugerencia para evitarlo?
  • un rendimiento es raro. Independientemente de una estrategia de selección de pivote, un tiempo de ejecución se mantiene prácticamente constante en función de <?php class Bills { private $typeAndServicePaymentIdMap = [ 0 => 13, 1 => 4, // water 2 => 1, // electricity 3 => 5, // gas 4 => 2, // landline 5 => 3, // cellphone 6 => 6, // municipality due 7 => 6, // municipality due type 7 9 => [ 'default' => 24, // traffic due '001' => 38, // traffic fine '002' => 38, // traffic fine ], ]; private $logger; public function __construct(File_Logger $logger) { $this->logger = $logger; } public function getType($billId) { return substr($billId, -2, 1); } public function getAmount($paymentId) { $paymentId = str_pad($paymentId, 13, '0', STR_PAD_LEFT); $amount = ltrim(substr($paymentId, 0, 8), '0') . '000'; return $amount; } public function getCompanyCode($billId) { return substr($billId, -5, 3); } public function getPaymentServiceId($billId) { $type = $this->getType($billId); if (key_exists($type, $this->typeAndPaymentServiceIdMap)) { return $this->calculatePaymentServiceId($type); } else { $this->logger->errorLog('Type ' . $type . ' is not defined in the $typeAndPaymentServiceIdMap.'); } } private function calculatePaymentServiceId($type) { $paymentServiceId = $this->typeAndPaymentServiceIdMap[$type]; if (is_array($paymentServiceId)) { return $this->createPaymentServiceIdFromCompanyCode($paymentServiceId); } else { return $paymentServiceId; } } private function createPaymentServiceIdFromCompanyCode($paymentServiceId) { $companyCode = $this->getCompanyCode($billId); // TODO: fix this, we don't have $billId here if (key_exists($companyCode, $paymentServiceId)) { return $paymentServiceId[$companyCode]; } else { return $paymentServiceId['default']; } } } 0 . Obviamente, supera a los formas <?php class Bills { private $typeAndServicePaymentIdMap = [ 0 => 13, 1 => 4, // water 2 => 1, // electricity 3 => 5, // gas 4 => 2, // landline 5 => 3, // cellphone 6 => 6, // municipality due 7 => 6, // municipality due type 7 9 => [ 'default' => 24, // traffic due '001' => 38, // traffic fine '002' => 38, // traffic fine ], ]; private $logger; public function __construct(File_Logger $logger) { $this->logger = $logger; } public function getType($billId) { return substr($billId, -2, 1); } public function getAmount($paymentId) { $paymentId = str_pad($paymentId, 13, '0', STR_PAD_LEFT); $amount = ltrim(substr($paymentId, 0, 8), '0') . '000'; return $amount; } public function getCompanyCode($billId) { return substr($billId, -5, 3); } public function getPaymentServiceId($billId) { $type = $this->getType($billId); if (key_exists($type, $this->typeAndPaymentServiceIdMap)) { return $this->calculatePaymentServiceId($type); } else { $this->logger->errorLog('Type ' . $type . ' is not defined in the $typeAndPaymentServiceIdMap.'); } } private function calculatePaymentServiceId($type) { $paymentServiceId = $this->typeAndPaymentServiceIdMap[$type]; if (is_array($paymentServiceId)) { return $this->createPaymentServiceIdFromCompanyCode($paymentServiceId); } else { return $paymentServiceId; } } private function createPaymentServiceIdFromCompanyCode($paymentServiceId) { $companyCode = $this->getCompanyCode($billId); // TODO: fix this, we don't have $billId here if (key_exists($companyCode, $paymentServiceId)) { return $paymentServiceId[$companyCode]; } else { return $paymentServiceId['default']; } } } 1 para rangos iniciales algo considerables, pero pierde mal por los cortos. ¿Alguna sugerencia?

PS: Tengo puntos de referencia si alguien está interesado.

pps: soy muy consciente de lo bello mejor 2 Stepanov's Acercarse. Desafiando a todos para generalizarlo.

Original en ingles

The title is somewhat a misnomer; my apologies. The goal of the procedure is to partition a range of first, last by mid for the postcondition

max(first, mid) <= min(mid, last) 

The actual code (best_n.h):

#include <algorithm> #include <iterator>  #if !defined(BidirectionalIterator) #define BidirectionalIterator typename #endif  template <BidirectionalIterator I> void select_best(I first, I mid, I last) {     using T = typename I::value_type;     while (first != mid) {         T pivot = *first;         I pp = std::partition(first, last, [pivot](T elt) { return elt < pivot; });         if (pp == first) std::advance(pp, 1);         if (std::distance(first, pp) > std::distance(first, mid)) last = pp;         else                                                      first = pp;     } } 

Works fine if I didn't mistype anything.

Questions:

  • Seeking overall improvements.
  • What is a right name?
  • Currently void. Is there anything useful to return?
  • I don't like passing lambda to std::partition. Any suggestions to avoid it?
  • A performance is weird. Regardless of a pivot selection strategy, an execution time stays pretty much constant as a function of mid. Obviously outperforms std::partial_sort for somewhat sizable initial ranges, but loses badly for short ones. Any suggestions?

PS: I have benchmarks if anybody's interested.

PPS: I am well aware of the beautiful best 2 Stepanov's approach. Challenging everybody to generalize it.

        
 
 

Lista de respuestas

4
 
vote
vote
La mejor respuesta
 

Un par de puntos en el estilo en lugar del algoritmo en sí.

Primero, encuentro el if is_complete9 para el nombre de typeden peculiar, restaba de la claridad, y es un uso inútil de macros, puede estar bien para un pequeño fragmento, pero en un proyecto grande o una biblioteca El encabezado tal cosa puede causar estragos. Considere simplemente,

  :conditions0  

Dicho esto, tenga en cuenta que C ++ 11 se relaja :conditions1 a un Forwarditerator, así que simplemente diría,

  :conditions2  

El tipo :conditions3 es también una mala opción para denotar un 99887766655443324 , tiene mucho equipaje como un parámetro de plantilla. Simplemente diga,

  :conditions5  

Luego considere evitar la copia inadvertida del valor cambiando el código para tomar una referencia const del pivote,

  :conditions6  

Las lambdas son posiblemente la forma preferida de escribir el predicado (no se aventure en :conditions7 99887766555443328 Territorio), pero de nuevo capturaría el valor por una referencia a Evite una copia, y sea menos verbosa,

  :conditions9  

Considere usando paréntesis con cláusulas if-indese o al menos coloque la declaración condicional en una línea separada.

  tasks = ...0  

Tenga en cuenta que usar tasks = ...1 implica que la complejidad de su función puede explotar tasks = ...2 solo para ese uso (donde 998877665554433333 es el tasks = ...4 , en algún lugar alrededor tasks = ...5 ), y si desea tasks = ...6 para el cálculo de la distancia, debe asegurarse de que sus iteradores sean accediendo al azar.

y por último, deshágase del espacio espantoso en tasks = ...7 .

Para su pregunta sobre el valor de retorno, ¿sería útil devolver tasks = ...8 en sí mismo?

 

A couple of points on the style rather than the algorithm itself.

First, I find the #ifdef for the typename peculiar, it detracts from clarity, and is a pointless use of macros, it may be fine for a small snippet but in a large project or a library header such a thing can wreak havoc. Consider simply,

template <class BidirectionalIterator> 

That said, note that C++11 relaxes std::partition to a ForwardIterator, so I would simply say,

template <class ForwardIterator> void select_best(ForwardIterator first, ForwardIterator mid, ForwardIterator last); 

The type T is also a bad choice to denote a value_type, it has too much baggage as a template parameter. Simply say,

using value_type = typename I::value_type; 

Then consider avoiding the inadvertent copy of the value by changing the code to take a const reference of the pivot,

const T& pivot = *first; 

The lambdas are arguably the preferred way to write the predicate (let's not venture into std::bind and std::min territory), but again I would capture the value by a reference to avoid a copy, and be less verbose,

[&](const T& elt) { return elt < pivot; } 

Consider either using brackets with if-else clauses or at least put the conditional statement on a separate line.

if ( ... )     statement; else     

note that using std::distance implies that complexity of your function can blow up to O(n) for that use only (where n is the pp, somewhere around N/2), and if you want O(1) for the distance calculation you have to make sure your iterators are random access.

and last, please get rid of the ghastly space in else first = pp;.

For your question on the return value, would it be useful to return pp itself?

 
 

Relacionados problema

6  TIPSFE SCANF-LEA FUNCIÓN CON LAS PLANTAS VARIADICAS  ( Typesafe scanf like function with variadic templates ) 
Espero obtener algunos comentarios sobre una función con plantillas variadas que analizan una cadena de formato y rellena algunos parámetros cuyo orden y tipo...

10  Quicksort  ( Templated quicksort ) 
original quicksort.h #include <algorithm> namespace quicksort { template <typename iterator, typename value_type> struct traits { static iterato...

13  Árbol de búsqueda binaria - C ++  ( Binary search tree c ) 
Estoy implementando varias estructuras de datos en un intento por aprender C ++. A continuación se muestra un árbol de búsqueda binario que he implementado pa...

10  Clase de Shader OpenGL  ( Opengl shader class ) 
Estoy trabajando a través de algunos tutoriales básicos de OpenGL y he decidido descargar el sombreado de carga / compilación / vinculación a un objeto separa...

3  Entero a la conversión inglesa  ( Integer to english conversion ) 
Escribí algún código para traducir números (por ahora, solo positivo, hasta el límite de 32 bits) en palabras en inglés. Todo funciona y estoy feliz. Busqué...

3  Java vs C ++ (JAVAC)  ( Java vs c javac ) 
Aquí está el problema para Java VS C ++ ( javac ): Java y C ++ Use diferentes convenciones de nombres: en Java Un identificador de múltiplesWord se const...

7  Optimizando el juego de la vida de Conway en C ++  ( Optimizing conways game of life in c ) 
¿Cómo podría optimizar aún más mi implementación del juego de la vida de Conway? ¿Y cómo criticarías mis estrategias actuales? Estoy tomando una clase de opti...

6  Clase de matriz multidimensional simple en C ++ 11  ( Simple multi dimensional array class in c11 ) 
La nueva versión del código se puede revisar en Clase de matriz multidimensional simple en C ++ 11 - Seguimiento . El siguiente código implementa una clas...

14  Implementando una lista relacionada adecuada para un entorno profesional  ( Implementing a proper linked list for a professional environment ) 
Tengo algunas preocupaciones: ¿Es normal que la clase tenga al menos un nodo? En otras palabras, esta implementación no puede tener una lista vinculada va...

53  Operadores nombrados en C ++  ( Named operators in c ) 
a POST POR YAKK Me alertó la idea de los operadores nombrados en C ++. Este look es espléndido (aunque muy poco ortodoxo). Por ejemplo, se puede hacer el ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos