issublist.cpp

/* COMIENZO DE DESCRIPCION

   __USE_WIKI__
   Escribir una funcion #bool# #is_sublist(list<int> &L1,# #list<int> &L1,#
   #list<list<int>::iterator> &iters);# que dadas dos listas
   #list<int> L1,L2# determina si la lista #L2# es una sublista de
   #L1#, es decir que #L2# se puede obtener a partir de #L1# solo
   eliminando algunos de sus elementos.
   [Tomado en primer parcial 2011-09-13].
   keywords: lista

  FIN DE DESCRIPCION */
// -------------------------------------------------------------------

#include <cstdio>
#include <cassert>
#include <cmath>

#include <list>
#include <vector>
#include <map>
#include <algorithm>

#include "./util.h"

using namespace std;

// Funcion auxiliar para generar ejemplos.  Desordena
// aleatoriamente una lista, recursivamente.  Primero la
// descompone en dos listas L1, L2 de tamano n1, n2 aprox
// n/2, las desordena (con una llamada recusiva) y despues
// va tomando elementos de L1 y L2 con probabilidad n1 y n2
// respectivamente. Las probabilidades se van ajustando a
// medida que las longitudes de L1 y L2 van disminuyendo
void random_shuffle(list<int> &L) {
int n = int(L.size());
  // Corta recursion si es necesario
  if (n<2) return;
  // Calcula tamano inicial de las sublistas
  int n1 = n/2, n2= n-n1;
  // Split de L en L1, L2
  list<int> L1,L2;
  for (int j=0; j<n1; j++) {
    L1.push_back(L.front());
    L.erase(L.begin());
  }
  for (int j=0; j<n2; j++) {
    L2.push_back(L.front());
    L.erase(L.begin());
  }
  // Aplica recursivamente a L1, L2
  random_shuffle(L1);
  random_shuffle(L2);
  // Va tomando elementos aleatoriamente de L1, L2
  // con prob. proporcional a sus longitudes
  for (int j=0; j<n; j++) {
    int k = rand()%(n1+n2);
    list<int> *sbl_p;
    // sbl_p es un puntero a la L1 o L2 depende de donde se inserte
    if (k<n1) {
      sbl_p = &L1;
      n1--;
    } else {
      sbl_p = &L2;
      n2--;
    }
    // Extrae de L y apendiza en *sbl_p
    L.push_back(sbl_p->front());
    sbl_p->erase(sbl_p->begin());
  }
}

typedef list<int>::iterator iter_t;
bool is_sublist(list<int> &L1, list<int> &L2,list<iter_t> &iters) {
  iter_t p2 = L2.begin(),p1 = L1.begin();
  // p2 recorre L2, vamos viendo si encontramos el elemento *p2 a en L1
  // a partir de la ultima posicion p1
  while (p2!=L2.end()) {
    while (p1!=L1.end()) {
      // SI encuentra el elemento inserta el ITERADOR en `iters'
      // y pasa al siguiente elemento de L2
      if (*p1==*p2) {
        iters.push_back(p1);
        break;
      }
      p1++;
    }
    // Si llega al final de L1 quiere decir que no encontro el *p2
    // entonces ya sabemos que NO es sublista. Antes de salir
    // vaciamos `iters' 
    if (p1==L1.end()) {
      iters.clear();
      return false;
    }
    // *p2 fue encontrado, pasamos al siguiente
    p2++;
  }
  return true;
}

int main() {

  // Probamos con 10 listas aleatorias
  for (int k=0; k<10; k++) {
    list<int> L;
    // Ponemos `N' elementos en un vector auxiliar `v' y lo
    // desordenamos aleatoriamente
    int N=20;
    vector<int> v(N);
    for (int j=0; j<N; j++) v[j] = j;
    random_shuffle(v.begin(),v.end());
    // Ponemos todos los elementos de `v' en `L1' y
    // una fraccion del 50% (aleatoria) en `L2'
    list<int> L1,L2;
    list<iter_t> iters;
    for (int j=0; j<N; j++) {
      L1.push_back(v[j]);
      if (rand()%2) L2.push_back(v[j]);
    }
    
    // A esta altura L2 es una sublista de L1, 
    // pero ahora tira la moneda y en 50% de los casos desordena L2.
    // O sea que si shuffle==1 entonces L2 NO deberia ser sublista
    // y viceversa, si shuffle==0 SI debe ser sublista.
    // (OJO que en realidad existe una probabilidad MUY BAJA de que el shuffle
    // no haga nada.)
    int shuffle = rand()%2;
    if (shuffle) random_shuffle(L2);
    printf("================\nL1: ");
    printl(L1);
    printf("L2: ");
    printl(L2);
  
    int issbl = is_sublist(L1,L2,iters);
    printf("Is L2 sublist of L1? %d, shuffle %d\n",issbl,shuffle);
    if (issbl) {
      assert(L2.size()==iters.size());
      iter_t p = L2.begin();
      list<iter_t>::iterator q = iters.begin();
      while (p!=L2.end()) assert(*p++ == **q++);
    }
    // Hace chequeos
    if (!shuffle && !issbl) 
      printf("ERROR: L2 no fue mezclada y sin embargo no es sublista\n");
    if (shuffle && issbl) 
      printf("PROBABLE ERROR: L2 fue mezclada, pero es sublista (OJO puede estar OK!!)\n");
  }
  return 0;
}

Generated by GNU Enscript 1.6.6.