circulo.cpp

// $Id$

/* COMIENZO DE DESCRIPCION 

  __USE_WIKI__
  Coloquemos #n# n\'umeros enteros positivos alrededor de una 
  circunferencia inicial. Construyamos ahora sucesivas 
  circunferencias conc\'entricas {\it hacia el exterior}, de igual 
  cantidad de elementos, los cuales son obtenidos restando (en valor 
  absoluto) pares consecutivos de la \'ultima circunferencia 
  exterior. 
  Entonces, dada una lista #L = [ x_0, x_1, ..., x_{n-1} ]# de #n#
  n\'umeros enteros que representan los valores iniciales alrededor de
  la circunferencia inicial, escribir una funci\'on 
  #int circulo(list<int> &L);# 
  que ejecuta esta tarea y devuelva adem\'as
  el n\'umero de circunferencias iteradas #p#
  [Tomado en el 1er parcial del 21/4/2005].
  keywords: lista

   FIN DE DESCRIPCION */

/* 
  Coloquemos $ n $ n\'umeros enteros positivos alrededor de una 
  circunferencia inicial. Construyamos ahora sucesivas 
  circunferencias conc\'entricas {\it hacia el exterior}, de igual 
  cantidad de elementos, los cuales son obtenidos restando (en valor 
  absoluto) pares consecutivos de la \'ultima circunferencia 
  exterior. Entonces, puede verificarse que si $n=2^k$ en alguna 
  iteraci\'on $p$ aparecer\'an $ n $ n\'umeros iguales. En ese 
  momento se detiene la iteraci\'on. Por ejemplo, supongamos 
  $ k = 2 $, ($n=4$) y que la circunferencia inicial sea
  $ C_0 = (8,2,5,7) $, entonces iteramos y obtendremos sucesivamente,
  $ C_1 = (6,3,2,1) $,
  $ C_2 = (3,1,1,5) $,
  $ C_3 = (2,0,4,2) $,
  $ C_4 = (2,4,2,0) $ y
  $ C_5 = (2,2,2,2) $, por lo que el n\'umero de circunferencias
  iteradas es $ p = 5 $.  
  Entonces, dada una lista $ L = [ x_0, x_1, ..., x_{n-1} ] $ de $ n $
  n\'umeros enteros que representan los valores iniciales alrededor de
  la circunferencia inicial, escribir una funci\'on {\tt int
  circulo(list<int> \& L);} que ejecuta esta tarea y devuelva adem\'as
  el n\'umero de circunferencias iteradas $ p $. 
  \emph{Restricci\'on:} el algoritmo debe ser {\it in place}. 
  \emph{Ayuda:} Pensar a la lista en un \emph{``sentido circular''}. 
  Tener cuidado al generar la diferencia correspondiente al extremo.
  [Tomado en el 1er parcial del 21/4/2005].

   FIN DE DESCRIPCION */
// -----------------------------------------------------------------
#include <iostream>
#include <list>
#include <map>
#include "./util.h"
using namespace std ;

//--------------------------------------------------------------------
// imprime lista y el contador del circulo
void imprime (list <int> & L, int k) {
  list <int> :: iterator p, z;
  cout << endl ;
  cout << "nro de circulo ; k = " << k << endl ;
  cout << "lista L : " ; 
  p = L.begin ();
  z = L.end ();
  while (p != z) cout << *p++ << " " ;
  cout << endl ;
}

//--------------------------------------------------------------------
// imprime lista
void imprime (list <int> & L) {
  list <int> :: iterator p, z;
  cout << "lista L: " ; 
  p = L.begin ();
  z = L.end ();
  while (p != z) cout << *p++ << " " ;
  cout << endl ;
}

//--------------------------------------------------------------------
// imprime mapeo
void imprime (map <int,int> & M) {
  map <int,int> :: iterator p;
  int x_dominio ;
  int y_rango;
  cout << endl ;
  cout << "mapeo actual (x_dominio, y_rango):" << endl ;
  p = M.begin ();
  while (p != M.end () ) {
    x_dominio = p->first;
    y_rango   = p->second;
    cout << "x_dominio = "     <<    x_dominio  << "  " ;
    cout << "M [x_dominio] = " << M [x_dominio] << endl ;
    p++;
  } // end while
}

//--------------------------------------------------------------------
// "utilitario" (o sea NO hace falta verla): 
// genera  en forma aleatoria una lista de permutacion de "n" enteros 
// en el intervalo [0,n)

// -----------------------------------------------------------------
void  random_shuffle (list<int> &L) {
  list<int>::iterator p,z; 
  list<int> q;
  int k,n;
  // Cuenta el numero de elementos en la lista L
  n=0;
  p=L.begin();
  while (p++!=L.end()) n++;
  // En cada iteracion del lazo se saca un elemento
  // al azar de la lista L y se lo inserta en la cola Q
  for (int h=n;h>0;h--) {
    // A esta altura la lista L tiene "h" elementos
    // asi que generamos un entero "k" entre 0 y h-1
    k = irand (h);
    // nos posicionamos en el elemento "k" en la lista L
    p=L.begin();
    for (int j=0;j<h-1;j++) p++;
    // inserta el elemento "k" de la lista L al final de la cola Q
    // y lo elimina de la lista L
    q.insert(q.end(),*p);
    L.erase(p);
  } // end h
  // Vuelve a copiar todos los elementos de la cola a la lista
  z=q.begin();
  while (z!=q.end()) {
    L.insert(L.end(),*z);
    z=q.erase(z);
  } // end while
} 


//--------------------------------------------------------------------
// "auxiliar" (conveniente para la consigna del ejercicio):
// funcion booleana que devuelve True si la lista "L" es constante.
// version 1: con iteradores sobre lista
bool es_constante1 (list <int> & L) {
  list <int> :: iterator p, q;
  p = L.begin ();
  q = p;
  while (q != L.end () && *p == *q) q++; 
  if (q == L.end ()) return true ; 
  else               return false ;
}

//--------------------------------------------------------------------
// "auxiliar" (conveniente para la consigna del ejercicio):
// funcion booleana que devuelve True si la lista "L" es constante.
// version 2: con un mapeo y notacion mas detallada
bool es_constante2 (list <int> & L) {
  map <int,int> M ;
  map <int,int> :: iterator q;
  list <int> :: iterator p;
  int x, y = 1 ;
  p = L.begin ();
  while ( p != L.end () ) {
    x = *p;
    q = M.find (x);               // busca el item "x"
    if (q == M.end ()) M [x] = y; // entonces NO esta en el mapeo "M"
    p++;                          // avanzamos en "M"
  } // end while
  return M.size() == 1 ;          // si es True entonces "L" es cte
}

//--------------------------------------------------------------------
// "auxiliar" (conveniente para la consigna del ejercicio):
// funcion booleana que devuelve True si la lista "L" es constante.
// version 3: con un mapeo pero menos eficiente y notacion "criptica"
bool es_constante3 (list <int> & L) {
  map <int,int> M ;
  list <int> :: iterator p = L.begin ();
  while ( p != L.end () ) M [*p++] = 1 ;
  return M.size() == 1 ;
}

//--------------------------------------------------------------------
// aunque "irrelevante" para este parcial, verlo para "practicar": 
// funcion que devuelve el maximo de una lista de enteros
int maximo (list <int> & L) {
  list <int> :: iterator p;
  int kmax = 0 ;
  p = L.begin (); 
  while (p != L.end ()) {
    if (*p >= kmax) kmax = *p; 
    p++ ;
  } // end while
  return kmax ;
}

//--------------------------------------------------------------------
int circulo (list <int> & L) {
  list <int> :: iterator p, r, q ;
  int k, n;
  int x, y;
  //
  // iteracion 0: circulo inicial
  k = 0 ;
  imprime (L,k) ; // circulo dato : es el circulo numero "0"
  //
  // mientras queden elementos diferentes
  while ( !es_constante1 (L) ) {
    k++;
    cout << "nro de circulo ; k = " << k << endl ;
    p = L.begin ();        // re-empezamos de nuevo a revisar "L"
    while ( p != L.end () ) {
      // "q" es el siguiente de "p" (para restar "hacia adelante")
      q = p ; q++;
      // como es "in place" hay que recordar el original en L.begin
      if (p == L.begin ()) y = *p;
      // si "q" NO es fin de lista entonces
      if (q != L.end ())   // puede restar "hacia adelante"  
        x = abs (*p - *q); //
      else {               // sino hay que restar con el "recordado"
        x = abs (*p - y);  // que estaba en L.begin (lista circular)
      } // end if
      p = L.erase (p);     // suprime en la posicion "p" y la refresca
      L.insert (p,x);      // inserta diferencia "x" en posicion "p"
    } // end while
    // imprime (L,k) ;     // imprime circulo iterado
  } // end while
  // imprime (L,k) ;       // imprime circulo final
  return k ;
}

//--------------------------------------------------------------------
int circula (list <int> & L) {
  int k, n;
  // controla que n sea una potencia de 2
  n = L.size ();
  k = n & (n - 1);
  if (k != 0) { 
     cout << endl ;
     cout << "n = " << n << endl << endl ;
     cout << "ERROR: n debe ser una potencia de 2 !! " << endl ; 
     return 0 ; }
  else {
     return circulo (L);
  }
}

//--------------------------------------------------------------------
int main() {
  list <int> L ;
  int  v [] = {8,2,5,7,-1};
  int  e ;
  bool z ;
  char *c ;
  int kaso = 2;

  if      (kaso == 1) {
    // construye una lista prefijada
    cout << endl;
    cout << "Lista prefijada (su longitud es 1 potencia de 2):" << endl;
    L.clear ();
    insertl (L,v,-1); 
    cout << "lista L: "; printl (L);
    e = circula (L);
    cout << "nro de circulas crecientes (L) = " << e << endl; 
    z = es_constante3 (L);
    cout << endl;
    cout << "es_constante (L) = " << z << endl;
  } // end elseif
  else if (kaso == 2) {
    // construye una lista aleatoria en [0,n), 
    int m = 33 ; 
    int n =  8 ; // cantidad de elementos (UNA POTENCIA DE 2 !!)
    L.clear ();
    for  (int k=0;k<n;k++) L.insert(L.end(),irand(m)); 
    cout << endl;
    cout << "nro de elementos ; n = " << n << endl; 
    cout << "Antes de random_shuffle  : ";
    printl (L);
    random_shuffle (L);
    cout << endl;
    cout << "Despues de random_shuffle: ";
    printl (L);
    // cout << endl << "pausa ... " ; cin.getline (c,1);
    // cout << "pausa .. " ; cin >> e ; cout << endl ;
    e = circula (L);
    // cout << "nro de circulos crecientes (L) = " << e << endl; 
    z = es_constante3 (L);
    cout << endl;
    cout << "es_constante (L) = " << z << endl;
  } // end elseif
  else {
    cout << endl;
    cout << "nothing to do " << endl;
  } // end else
  cout << endl;
  return 0;
}
// -----------------------------------------------------------------
// 

Generated by GNU Enscript 1.6.6.