0% encontró este documento útil (0 votos)
3 vistas26 páginas

Guía C++ para programadores Java

Guia de C++ para maratonistas que conocen acerca de Java
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
3 vistas26 páginas

Guía C++ para programadores Java

Guia de C++ para maratonistas que conocen acerca de Java
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Guia de C++ para maratonistas Java

Gerson Lázaro

2016
Nota del autor (​
​ )
CC BY-SA 4.0​

Esta obra se comparte bajo licencia Creative Commons Atribución - CompartirIgual 4.0 Internacional (CC BY-SA 4.0), lo cual le permite:

● Compartir​— copiar y redistribuir el material en cualquier medio o formato


● Adaptar​— remezclar, transformar y crear a partir del material
● Para cualquier propósito, incluso comercialmente
El licenciante no puede revocar estas libertades en tanto usted siga los términos de la licencia

Bajo las siguientes condiciones:

● Atribución​ — Usted debe darle crédito a esta obra d​e manera adecuada​ , proporcionando un enlace a la licencia, e i​
ndicando si se han
realizado cambios​ . Puede hacerlo en cualquier forma razonable, pero no de forma tal que sugiera que usted o su uso tienen el apoyo del
licenciante.
● CompartirIgual​ — Si usted mezcla, transforma o crea nuevo material a partir de esta obra, usted podrá distribuir su contribución siempre que
utilice la ​
misma licencia​que la obra original.

Gerson Lázaro - 2016

1
Contenido

1. Para empezar
1.1. ¿Que es esta guia?
1.2. Estructura de la guía
2. Aspectos Básicos
2.1. Consideraciones iniciales
2.2. Estructura y Hola Mundo
2.3. Tipos de datos
2.4. Entrada y salida
3. Estructuras de datos
3.1. ArrayList - Vector
3.2. TreeSet - Set
3.3. TreeMap - Map
3.4. Stack
3.5. Queue
3.6. Priority Queue
3.7. Deque
4. Utilidades de C++ vs. Java
4.1. Matemáticas
4.2. Búsqueda y Ordenamiento
5. Utilidades de C++ ausentes en Java
5.1. Bitset
5.2. Pair
6. Utilidades de Java ausentes en C++
7. Navaja Suiza: Optimizar trabajo en C++

2
7.1. bits/stdc++.h
7.2. Acortar nombre de los tipos de datos (typedef)
7.3. Definir datos globales (define)
7.4. Redefinir instrucciones (define)
7.5. Llenar arreglos o matrices (o inicializarlos)
7.6. Optimizar entradas y salidas
7.7. Un ejemplo completo: Java vs. C++

3
1. Para empezar

1.1. ¿Que es esta guia?


Esta guía no es un libro para aprender a programar, ni tampoco un tutorial extensivo sobre C++. Es un manual rápido para competencias de
programación de tipo ICPC, donde se muestran las equivalencias entre diferentes instrucciones, estructuras de datos y prácticas de java y C++, para
facilitar la adaptación a C++ a aquellos que se inician en este lenguaje.

Por supuesto, son dos lenguajes diferentes, con una idea diferente, y no todo lo que haga en uno, tendrá una equivalencia exacta en el otro, por lo
cual en algunos aspectos he recurrido a buscar soluciones que cumplan la misma función, aunque se realicen de formas diferentes; aun así, el proceso
de aprendizaje de un lenguaje conlleva prueba y error, por lo que si en algún punto no te sientes conforme con la equivalencia planteada, siempre
puedes revisar en la documentación del lenguaje, en StackOverflow o en el todopoderoso Google. Y si crees que tu solución es mejor que la
equivalencia que yo he planteado, ¡házmelo saber!.

Antes de empezar con el código puro y duro, pido un favor adicional: Si encuentras un error ya sea en la escritura, en el código o las equivalencias,
infórmame para corregirlo (​
gersonlazaro@[Link]​ ).

1.2. Estructura de la guía


Cada sección de la guía presenta código en java en la parte izquierda y su correspondiente forma de realizarlo en C++ en la parte derecha. Las
explicaciones generales se añaden a manera de párrafo, mientras explicaciones específicas estarán como comentarios en el mismo código.

4
2. Aspectos Básicos

2.1. Consideraciones iniciales


● En java, la clase y el archivo deben recibir el mismo nombre, y debo coincidir con el basename dado por la plataforma de juzgamiento. En C++
no hay problema con esto, el archivo es independiente de clase, y puede llevar cualquier nombre.
● La extensión del archivo c++ es .cpp

2.2. Estructura y Hola Mundo

Hola Mundo
import​java​
.​
io​
.*; #include​​
<​
bits​
/​
stdc​
++.​
h>

public​​
class​​
Main​{ using​​
namespace​std;

public​​
static​​
void​main ​
(​
String​
[]​args​
)​{ int​main​
()​{
System​
.​
out​
.​
println​
(​
"Hola Mundo"​
); cout ​
<<​​
"Hola Mundo :)" << endl;
} return​​
0;
} }

● El #include de c++ cumple la misma función del import de java. Su sintaxis es:

#include​​
<nombreLibreria>

5
Pueden incluirse una a una las librerías que van a usarse. Sin embargo, en el ejemplo puede leerse #include <bits/stdc++.h>, un macro que se
encarga de incluir todo lo necesario sin que debas hacerlo manualmente. Usando esta linea, no debes preocuparte por ningún otro include1 .
● Si bien no entraré en detalle en “using namespace std”, es importante definirlo siempre al inicio, pues indica que usaremos el espacio de
nombres std, y esto nos evitará estar escribiendo “std::” en el resto del programa.
● En java, el método main es void, mientras en c++ es int. Por lo tanto, requiere retornar algo. Por esta razón, añadimos al final del main return
0, que indica éxito (cualquier número diferente a 0 indica error).

2.3. Tipos de datos

Tipos de datos (Java vs. C++)


byte​a;
short​b; short​b;
int​c; int​c​
,​​
long​c​
;​​
//En c++, el long tiene la misma capacidad
del int. Para números de 8 bytes, usar long long, o long
long int
long​d; long​​
long​d​
,​​
long​​
long​​
int​d;
float​e; float​e;
double​f; double​f;
char​g; char​g;
boolean​h; bool​h;
String​i; string​i​
;​​
//con s minúscula

//Arreglos //Arreglos
int​arreglo​
[]​​
=​​
new​​
int​
[​
100​
]; int​arreglo​
[​
100​
];

1
Mas información sobre como funciona <bits/stdc++.h> en la sección 7.1
6
2.4. Entrada y salida

Entrada y Salida
Scanner​sc ​
=​​
new​​
Scanner​
(​
System​
.​
in​
); int​a;
int​a ​
=​sc​
.​
nextInt​
(); string​c;
String​c ​
=​sc​
.​
next​
(); //MODO 1
System​
.​
out​
.​
println​
(​
a​+​​
"​​
"​​
+​c​
); cin ​
>>​a ​
>>​c​
;​​
//Lee un entero y un string desde consola
cout ​
<<​a ​
<<​​
" "​​
<<​c ​
<<​endl​
;​​
//Imprime en pantalla
//MODO 2
scanf​
("%​
d​
",​​
&​
a​
);​​
//Lee un entero
printf​
("%​
d\n​
",​a​
);

//Leer una línea entera //Leer una línea enter


c​​
=​sc​
.​
nextLine​
(); getline​
(​
cin​
,​c​
);

7
3. Estructuras de datos

3.1. ArrayList - Vector

ArrayList (Java) - Vector (C++)


//Declaración e inicialización //Declaración (inicializa automáticamente)
ArrayList​
<​
Integer​
>​a ​
=​​
new​​
ArrayList​
<>(); vector​
<int>​a;
//Inserción //Inserción
a​
.​
add​
(​
32​
); a​
.​
push_back​
(​
32​
);
//Obtener valor en un índice dado //Obtener valor en un índice dado
a​
.​
get​
(​
1​
); a​
[​
1​
];
//Modificar el elemento dado (0) con el valor dado (25) //Modificar el elemento dado (0) con el valor dado (25)
a​
.​
set​
(​
0​
,​​
25​
); a​
[​
0​
]​​
=​​
25;
//Borrar valor en un índice dado //Borrar valor (recibe un iterador al elemento a borrar)
a​
.​
remove​
(​
1​
); a​
.​
erase​
(​
it​
);
//Borrar todo //Borrar todo
a​
.​
clear​
(); a​
.​
clear​
();
//Obtener tamaño //Obtener tamaño
a​
.​
size​
(); a​
.​
size​
();

3.2. TreeSet - Set

TreeSet (Java) - Set (C++)


//Declaración e inicialización //Declaración (inicializa automáticamente)
TreeSet​
<​
Integer​
>​t ​
=​​
new​​
TreeSet​
<​
Integer​
>​
(); set<int> t;
//Inserción //Inserción
t​
.​
add​
(​
32​
); t​
.​
insert​
(​
32​
);
//Verificar si un elemento existe //Verificar si un elemento existe
t​
.​
contains​
(​
32​
); t​
.​
count​
(​
32​
);
//Verificar si el TreeSet está vacío //Verificar si el set está vacío
t​
.​
isEmpty​
(); t​
.​
empty​
();

8
//Borrar valor //Borrar valor
t​
.​
remove​
(​
25​
); t​
.​
erase​
(​
25​
);
//Borrar todo //Borrar todo
t​
.​
clear​
(); t​
.​
clear​
();
//Obtener tamaño //Obtener tamaño
t​
.​
size​
(); t​
.​
size​
();

Recorrer treeset con un for: TreeSet (Java) - Set (C++)


TreeSet​
<​
Integer​
>​t ​
=​​
new​​
TreeSet​
<​
Integer​
>​
(); set​
<int>​t;
for​
(​
Iterator​
<​
Integer​
>​it ​
=​t​
.​
iterator​
();​it​
.​
hasNext​
();)​{ for​
(​
set​
<int>​
::​
iterator it ​
=​t​
.​
begin​
();​it ​
!=​t​
.​
end​
();​it​
++){
System​
.​
out​
.​
println​
(​
it​
.​
next​
()); cout ​
<<​​
*​
it ​
<<​endl;
} }
//[Link]() y [Link]() son iteradores al inicio y al fin del
set t. En c++, los operadores pueden compararse con == o !=
y pueden aumentarse o disminuirse con ++ y ­­. Para acceder
al valor del iterador, se escribe un asterisco antes de su
nombre (*it).

Recorrer treeset con un while: TreeSet (Java) - Set (C++)


TreeSet​
<​
Integer​
>​t ​
=​​
new​​
TreeSet​
<​
Integer​
>​
(); set​
<int>​t​
;
Iterator​
<​
Integer​
>​it ​
=​t​
.​
iterator​
() set​
<int>​
::​
iterator it ​
=​t​
.​
begin​
();
while​
(​
it​
.​
hasNext​
())​​
{ while​
(​
it++ ​
!=​t​
.​
end​
()){
System​
.​
out​
.​
println​
(​
it​
.​
next​
()); cout ​
<<​​
*​
it ​
<<​endl​
;
} }

3.3. TreeMap - Map

TreeMap (Java) - Map (C++)


//Declaración e inicialización //Declaración (inicializa automáticamente)
TreeMap​
<​
String​
,​​
Integer​
>​tm ​
=​​
new​​
TreeMap​
<>​
(); map​
<​
string​
,​​
int​
>​tm;
//Inserción //Inserción
tm​
.​
put​
("​
clave​
",​​
15​
); tm​
["​
clave​
"]​​
=​​
15;
//Verificar si un elemento existe //Verificar si un elemento existe

9
tm​
.​
containsKey​
("​
clave​
"); tm​
.​
count​
("​
clave​
");
//Obtener el valor asociado a una clave //Obtener el valor asociado a una clave
tm​
.​
get​
("​
clave​
") tm​
["​
clave​
"];
//Modificar un elemento (ej: sumar 2) //Modificar un elemento (ej: sumar 2)
tm​
.​
put​
("​
clave​
",​tm​
.​
get​
("​
clave​
")​​
+​​
2​​
); tm​
["​
clave​
"]​​
+=​​
2;
//Verificar si el TreeMap está vacío //Verificar si el map está vacío
tm​
.​
isEmpty​
(); tm​
.​
empty​
();
//Borrar valor //Borrar valor
tm​
.​
remove​
("​
clave​
); tm​
.​
erase​
("​
clave​
");
//Borrar todo //Borrar todo
tm​
.​
clear​
(); tm​
.​
clear​
();
//Obtener tamaño //Obtener tamaño
tm​
.​
size​
(); tm​
.​
size​
();

Recorrer treemap con un for: TreeMap (Java) - Map (C++)


TreeMap​
<​
String​
,​​
Integer​
>​tm ​
=​​
new​​
TreeMap​
<>(); map​
<​
string​
,​​
int​
>​tm​
;
for​​
(​
Map​
.​
Entry​
<​
String​
,​​
Integer​
>​entry ​
:​tm​
.​
entrySet​
())​​
{ for​
(​
map​
<​
string​
,​
int​
>::​
iterator it ​
=​tm​
.​
begin​
();​it ​
!=
System​
.​
out​
.​
println​
(​
entry​
.​
getKey​
()​​
+​​
" "​​
+ tm​
.​
end​
();​it​
++){
entry​
.​
getValue​
()); cout ​
<<​tm​
­>​
first ​
<<​​
"​​
"​​
<<​tm​
­>​
second ​
<<​endl​
;
} }

Recorrer treeset con un while: TreeMap (Java) - Map (C++)


TreeMap​
<​
String​
,​​
Integer​
>​tm ​
=​​
new​​
TreeMap​
<>(); map​
<​
string​
,​​
int​
>​tm;
Iterator​it ​
=​tm​
.​
keySet​
().​
iterator​
(); map​
<​
string​
,​​
int​
>::​
iterator it ​
=​tm​
.​
begin​
();
while​​
(​
it​
.​
hasNext​
())​{ while​
(​
it​
++​​
!=​tm​
.​
end​
()){
String​key ​
​ =​​
(​
String​
)​it​
.​
next​
(); cout ​
<<​it​
­>​
first ​
<<​​
"​​
"​​
<<​it​
­>​
second ​
<<​endl;
System​
​ .​
out​
.​
println​
(​
key ​
+​​
""​​
+​tm​
.​
get​
(​
key​
)); }
}

3.4. Stack

Stack (Java - C++)


//Declaración e inicialización //Declaración (inicializa automáticamente)
Stack​
<​
Integer​
>​s ​
=​​
new​​
Stack​
<​
Integer​
>​
(); stack​
<int>​s​
;
//Insertar en el tope //Insertar en el tope

10
s​
.​
push​
(​
15​
); s​
.​
push​
(15);
//Eliminar del tope y obtener el valor //Eliminar del tope (no obtiene, solo elimina)
s​
.​
pop​
(); s​
.​
pop​
();
//Obtener del tope sin eliminar //Obtener del tope sin eliminar
s​
.​
peek​
(); s​
.​
top​
();
//Verificar si el stack está vacío //Verificar si el stack está vacío
s​
.​
empty​
(); s​
.​
empty​
();

3.5. Queue

Queue (Java - C++)


//Declaración e inicialización //Declaración (inicializa automáticamente)
Queue​
<​
Integer​
>​q ​
=​​
new​​
LinkedList​
<​
Integer​
>​
(); queue​
<int>​q​
;
//Insertar en el final //Insertar en el final
s​
.​
add​
(​
15​
); s​
.​
push​
(​
15​
);
//Eliminar del tope y obtener el valor //Eliminar del tope (no obtiene, solo elimina)
s​
.​
poll​
(); s​
.​
pop​
();
//Obtener del tope sin eliminar //Obtener del tope sin eliminar
s​
.​
peek​
(); s​
.​
front​
();
//Verificar si la cola está vacío //Verificar si la cola está vacío
s​
.​
isEmpty​
(); s​
.​
empty​
();

3.6. Priority Queue

Priority Queue (Java - C++)


//Declaración e inicialización //Declaración (inicializa automáticamente)
PriorityQueue​
<​
Integer​
>​pq​
=​
new​​
PriorityQueue​
<​
Integer​
>​
(); priority_queue​
<int>​pq​
;
//Insertar en el final //Insertar en el final
s​
.​
add​
(​
15​
); s​
.​
push​
(​
15​
);
//Eliminar del tope y obtener el valor //Eliminar del tope (no obtiene, solo elimina)
s​
.​
poll​
(); s​
.​
pop​
();
//Obtener del tope sin eliminar //Obtener del tope sin eliminar
s​
.​
peek​
(); s​
.​
top​
();

11
//Verificar si la cola está vacío //Verificar si la cola está vacío
s​
.​
isEmpty​
(); s​
.​
empty​
();

3.7. Deque

Deque (Java - C++)


//Declaración e inicialización //Declaración (inicializa automáticamente)
Deque​
<​
Integer​
>​dq ​
=​​
new​​
ArrayDeque​
<​
Integer​
>​
(); deque​
<int>​dq​
;
//Insertar al final //Insertar al final
dq​
.​
add​
(​
15​
); dq​
.​
push_back​
(​
15​
);
//Insertar al inicio //Insertar al inicio
dq​
.​
addFirst​
(​
15​
); dq​
.​
push_front​
(​
15​
);
//Obtener y eliminar elemento del inicio //Eliminar elemento del inicio (no lo obtiene)
dq​
.​
pollFirst​
(); dq​
.​
pop_front​
();
//Obtener y eliminar elemento del final //Eliminar elemento del final (no lo obtiene)
dq​
.​
pollLast​
(); dq​
.​
pop_back​
();
//Obtener elemento del inicio //Obtener elemento del inicio
dq​
.​
peekFirst​
(); dq​
.​
front​
();
//Obtener elemento del final //Obtener elemento del final
dq​
.​
peekLast​
(); dq​
.​
back​
();

12
4. Utilidades de C++ vs. Java

4.1. Matemáticas

Math (Java) vs. cmath (C++)


//C++ no trae constantes por defecto. Pueden definirse justo
después de los includes con las siguientes líneas:
#define​E ​
2.718281828459045
#define​PI ​
3.141592653589793
//Una vez definidas, para usarlas es tan simple como:
//Constante PI //Constante PI
Math​
.​
PI​
; PI​
;
//Constante E //Constante E
Math​
.​
E; E;

Todas las principales funciones matemáticas se encuentran tanto en C++ como en java con el mismo nombre, con la única diferencia que en Java se invoca
mediante “Math.NOMBRE_FUNCION()” y en C++ solo “NOMBRE_FUNCION()”.

4.2. Búsqueda y Ordenamiento

Búsqueda y Ordenamiento
ArrayList​
<​
Integer​
>​AR ​
=​​
new​​
ArrayList​
<>(); vector​
<int>​AR​
;
//Ordenamiento //Ordenamiento
Collections​
.​
sort​
(​
AR​
); sort​
(​
AR​
.​
begin​
(),​AR​
.​
end​
());
//Verificar si contiene un elemento //Verificar si contiene un elemento
AR​
.​
contains​
(​
13​
);​​
//Retorna true o false count​
(​
AR​
.​
begin​
(),​AR​
.​
end​
(),​​
13​
);​​
//Retorna el número de
veces que se encontró el elemento
//Búsqueda binaria //Búsqueda binaria
Collections​
.​
binarySearch​
(​
AR​
,​​
13​
);​​
//Retorna el indice binary_search​
(​
AR​
.​
begin​
(),​AR​
.​
end​
(),​​
13​
);​​
//Retorna un bool

13
5. Utilidades de C++ ausentes en Java
Algunas utilidades de C++ no tienen un equivalente preconstruido en Java, aunque bien pueden construirse fácilmente. En esta sección se presentan
estas utilidades, como podrían construirse en java, y cómo se utiliza la implementación definida en C++.

5.1. Bitset
El bitset emula un array de elementos booleanos, pero optimizados para la asignación de espacio: generalmente cada elemento ocupa solo un bit
(que en muchos sistemas es ocho veces menor que el tipo de dato elemental mas pequeño: char.2

Bitset
//En java no existe un bitset como tal. Por lo tanto,
debemos implementar el típico array de booleans, aunque como
se explicó en la definición, ocupa mucho mas espacio.
boolean​bs​
[]​​
=​​
new​​
boolean​
[​
100​
]; bitset​
<​
100​
>​bs​
;
//Declarar una posición como true //Declarar una posición como true
bs​
[​
13​
]​​
=​​
true​
; bs​
.​
set​
(​
13​
);
//Declarar una posición como falsa //Declarar una posición como false
bs​
[​
13​
]​​
=​​
false​
; bs​
.​
unset​
(​
13​
);
//Invertir el valor de una posición //Invertir el valor de una posición
bs​
[​
13​
]​​
=​​
!​
bs​
[​
13​
]; bs​
.​
flip​
(​
13​
);
//Contar cuantas posiciones están en true //Contar cuantas posiciones están en true
int​posiciones ​
=​​
0​
; bs​
.​
count​
();
for​
(​
int​i ​
=​​
0​
;​i ​
<​bs​
.​
length​
;​i​
++)​​
{
if​
​ (​
bs​
[​
i​
])​posiciones​
++;
}
//Verificar si existe al menos una posición en true //Verificar si existe al menos una posición en true
bool​existe ​
=​​
false​
; bs​
.​
any​
();
for​
(​
int​i ​
=​​
0​
;​i ​
<​bs​
.​
length​
;​i​
++)​​
{
if​
​ (​
bs​
[​
i​
])​​
{
existe ​
=​​
true​
;
break​
​ ;

}
}

2
Definición tomada de ​
[Link]
14
5.2. Pair
El pair es una estructura que permite guardar dos elementos de diferente tipo en una sola unidad.

Pair
//Java no cuenta con una estructura pair (clave­valor)
predefinida. En cierta manera puede utilizarse [Link], o
bien, construir una clase simple para esta labor. A
continuación se presenta una clase simple, pero en la
practica puede ser necesario crear mas métodos para dotarla
de una verdadera funcionalidad
static​​
class​​
Pair​
<​
T​
,​U​
>{
public​T first​
;
public​U second​
;

public​​
Pair​
(​
T t​
,​U u​
)​​
{
this​
.​
first ​
=​t​
;
this​
.​
second ​
=​u​
;
}
}

//Declaración //Declaración e inicialización


Pair​
<​
Integer​
,​​
String​
>​par ​
=​​
new​​
Pair​
<>(​
13​
,​​
"Hola"​
); pair​
<​
int​
,​​
string​
>​par ​
=​make_pair​
(​
13​
,​​
"hola"​
);
//Primer elemento //Primer elemento
par​
.​
first​
; par​
.​
first​
;
//Segundo elemento //Segundo elemento
par​
.​
second; par​
.​
second​
;

15
6. Utilidades de Java ausentes en C++
Existen sin duda alguna muchas utilidades que facilitan el trabajo en uno u otro lenguaje. Ya vimos algunas de las utilidades de C++ que no están
presentes en java (Solo un par, son muchas mas), y ahora es el turno de hablar de aquellas que están en Java pero no en C++. Si bien pueden ser
muchisimas, existen 3 en especifico que son de suma utilidad en competencias de programación:

● BigInteger
● BigDecimal
● Geometry

No existen librerías propias de C++ que suplan estas necesidades. Existen por supuesto, muchas utilidades creadas por terceros que llenan estas
falencias, pero en competencias no es posible importar librerías que no hacen parte del std de C++. Está la opción también de construir durante
competencia nuestras propias librerías que emulen estas características (o mejor aún, llevarlas impresas para copiarlas en competencia en caso de ser
necesario), pero esto siempre conlleva un tiempo considerable, por lo que la mejor recomendación es utilizar Java cuando un ejercicio requiera
estrictamente estas utilidades.

Aún así, es importante verificar que estas librerías sean realmente necesarias. Muchos ejercicios que parecieran manejar BigInteger pueden resolverse
con simples Strings, o aritmética modular. Del mismo modo, muchos ejercicios en esencia geométricos, son en realidad resolubles con matemática
básica. Y en cualquiera de estos casos, sí que podemos trabajar C++ en vez de Java.

16
7. Navaja suiza: Optimizar trabajo en C++

Existen muchas utilidades pequeñas que pueden hacer mas fácil la manera de trabajar en C++, dando versatilidad al lenguaje. Estas utilidades no son
de obligatorio uso, y existen pros y contras en su utilización. Aquí se presentan sin tomar partido a favor o en contra, y es responsabilidad de cada
quien incluirlos o no en su código.

7.1. bits/stdc++.h
Al principio de la guía, se utilizó #include <bits/stdc++.h>. De no haber usado esta línea, sería necesario hacer un include en una línea por cada
librería utilizada: #include <vector>, #include <stack>, #include <iostream>, etc. Sin embargo, al incluir bits/stdc++.h no es necesario hacer ningún
otro include.

¿Cómo funciona? Este es un header que incluye todas las demás librerías necesarias. Esto bajo muchos enfoques puede ser negativo, pues
posiblemente aumente el tiempo de compilación y el tamaño del programa compilado. Sin embargo, en competencia, donde cada segundo es
importante, puede tener una enorme utilidad reduciendo el tiempo de escritura de código. No se debe confundir el tiempo de compilación con el
tiempo de ejecución, motivo por el cual usar bits/stdc++.h de ninguna manera provocará tiempos límites excedidos.

Otro punto a tener en cuenta es que no es un estándar del lenguaje, motivo por el cual solo funciona en el compilador GNU C++ (gcc++). La buena
noticia es que la gran mayoría de jueces de programación competitiva (de hecho, todos los jueces que conozco) usan gcc++.

17
7.2. Acortar nombre de los tipos de datos (typedef)
Crear una instancia de una estructura de datos en C++ es algo corto (de hecho, es mas corto que en Java dado que no es necesaria la inicialización).
Aún así, puede acortarse aún mas si tu lo quieres. Para esto existe el typedef, que permite llamar a los tipos de datos como tu quieras.

Si por ejemplo, tienes un map (TreeMap) que guarda parejas de enteros con vectores de enteros, la declaración sería así:

map​
<​
int​
,​vector​
<int> ​
>​nombreMap;

Sí esta declaración te parece muy larga, complicada, o simplemente crees que hace ver el código enredado, puedes crear un sobrenombre para esta
declaración, y ubicarlo justo después de using namespace std; Este typedef consiste de solo una línea así:

typedef​nombreDeTipoExistente sobrenombre;

Para este caso sería:

typedef​map​
<​
int​
,​vector​
<int>​​
>​vii;

Después de eso, cada vez que quieras crear un mapa de entero - vector de enteros, simplemente tienes que hacer:

vii nombreDelMapa;

Lo cual simplifica mucho la instrucción. ¿Cuando usar typedef? Esto queda a consideración de cada persona. Muchos competidores tienen una lista de
typedef impresos, y al iniciar la competencia lo escriben en un archivo de texto, copiandolo después en todos los códigos que hagan durante la
competencia. Otros lo usan únicamente cuando durante el programa van a utilizar algún tipo que se torna complejo (Ej: set<map<pair<int, string>,
<vector<int> > > >) o bien, cuando algún tipo se repite muchas ocasiones durante el codigo.

A continuación se presentan algunos typedef que son comunes entre muchos competidores:

18
typedef ​
long ​
long ll​
;​//Paraprogramadoresjavaacostumbradosalong,longlongpuedesermuylargo.
Podemos reducirlo a ll
typedef​vector​
<int>​vi​
;
typedef​pair​
<​
int​
,​​
int​
>​ii​
;
typedef vector​
<ii> vii​
;​//Puede usarse un sobrenombre definido en un typedef (ii) enladeclaración
de otro typedef
typedef​​
set​
<int>​si​
;
typedef​map​
<​
string​
,​​
int​
>​msi;

7.3. Definir datos globales (define)


#define nos permite definir ”macros” que serán reemplazados por una secuencia de valores/instrucciones. En otras palabras, permiten escribir
palabras definidas por nosotros (macros), que cada vez que se encuentren en el código serán reemplazadas por la secuencia indicada en la definición.
En esta sección veremos un uso básico, y en la siguiente un uso mas completo de esta utilidad.

Existen constantes matemáticas que C++ no trae por defecto, pero que podemos definir desde un inicio para su uso en el programa. Por ejemplo,
podríamos incluir justo después de los typedef o del using namespace std las siguientes líneas:

● #define​E ​
2.718281828459045
● #define​PI ​
3.141592653589793
● #define​INF ​
1000000000​​
//Infinito arbitrario
● #define​EPS ​
1e­9

Cada vez que en el código encuentre un llamado a E, PI, INF o EPS inmediatamente lo reemplazará por el valor definido en esta sección.

19
7.4. Redefinir instrucciones (define)
#define sirve no solo para definir constantes numéricas como se vió en la sección anterior, sino para redefinir cualquier tipo de instrucciones. Por
ejemplo, una de las instrucciones mas comunes en la programación es un ciclo que vaya desde cero hasta un número dado, aumentando de uno en
uno. Es decir:

for​
(​
int​i ​
=​​
0​
;​i ​
<​a​
;​i​
++)

Si durante tu código esta instrucción aparece muchas veces, o simplemente quieres hacerla mas sencilla de escribir, puedes crear un define de la
siguiente manera:

#define​f​
(​
a​
)​ ​
for​
(​
int​i ​
=​​
0​
;​i ​
<​a​
;​
i​
++)

Ahora puedes escribir un for desde cero hasta 100 tan simple como:

f​
(​
100​
){
cout ​
<<​i ​
<<​endl;
}

En este ejemplo, he pasado directamente un valor numérico (100), perfectamente habría podido pasar una variable previamente definida, como
f(nombreVariable) con el mismo resultado.

Si bien esto aporta gran flexibilidad y puede reducir enormemente las líneas de código, también hace que el código final sea algo mas inentendible
que código sin macros; cualquier persona que tenga conceptos en programación entenderá un for. Pero alguien que no conoce el define que creamos
previamente, no sabrá qué significa f(100), por lo tanto debe usarse con precaución. Mi recomendación es que si se van a usar estas instrucciones en
competencia, se estudien y definan con anterioridad y sean un estándar entre los integrantes del equipo en caso de competencias grupales. La idea es
que durante la competencia, los integrantes del grupo conozcan que #define’s usan, y no tengan que revisar la declaración de cada #define para
entender el código, pues el tiempo que se gana en escritura, se pierde en mayor cantidad en revisión.

20
Algunos de los #define’s mas comunes en competencias de programación son:

● #define​f​
(​
a​
)​ ​
for​
(​
int​i ​=​​
0​
;​i ​
<​a​
;​
i​
++)
● #define​​
foreach​
(​
v​
,​c​
)​ ​ for​
(​
typeof​
((​
c​
).​
begin​
())​v ​
=​​
(​
c​
).​
begin​
();​ v ​
!=​​
(​
c​
).​
end​
();​​
++​
v)
● #define all​
(​
a​
) a​ .​
begin​
(), a​.​
end​
() ​
//Métodos como sort, requieren como parámetros un iterador
al inicio y un iterador al [Link]ámetrosconuna
simple palabra "all".
● #define add push_back ​ //Para programadores java mas acostumbrados al add que al push_back,
bien pueden reemplazar la palabra sin problema
● #define​fill​
(​
a​
,​
v​
)​memset​(​
a​
,​v​
,​​
sizeof​a​
)​​
//Se verá a fondo en la siguiente sección

7.5. Llenar arreglos o matrices (o inicializarlos)


En Java, al crear un arreglo de booleans en el main cada posición inicia en false. Si el arreglo es de cualquier tipo numérico inicia en 0. En C++ en
cambio no se asigna un valor por defecto y esto puede dar lugar a errores. Hacer un for que recorra todo el arreglo dando un valor a cada posición es
algo tedioso. En vez de eso, en C++ tenemos la instrucción memset, la cual nos permite editar directamente la memoria para llenar el arreglo con su
valor inicial. La instrucción es simple:

memset​
(​
nombreArreglo​
,​valorInicial​
,​tamañoArreglo​
);

Sin embargo el tamaño del arreglo debe manejarse con cuidado, pues no es el número de elementos que contiene sino la cantidad de memoria que
ocupa (es decir, el número de elementos multiplicado por la memoria que ocupa cada elemento). El cálculo puede hacerse a mano, pero C++ resuelve
esto automáticamente con la función sizeof, la cual retorna el tamaño de cualquier tipo de dato. Si tenemos un arreglo de enteros llamado “a”, y
queremos inicializar todas sus casillas a cero, podemos hacer:

memset​
(​
a​
,​​
0​
,​​
sizeof​
(​
a​
));
Y de esta manera, todo el arreglo se inicializa.

21
Con las matrices varía un poco. El sizeof de una matriz no devuelve exactamente el tamaño de una matriz. La solución en este caso es tomar el
tamaño (sizeof) de una casilla específica de la matriz, y multiplicarlo por el número de filas y de columnas. Por ejemplo:

int​b​
[​
100​
][​
200​
];
memset​
(​
b​
,​​
0​
,​​
sizeof​
(​
b​
[​
0​
][​
0​
])​​
*​​
100​​
*​​
200​
);

Si la matriz es de mas de dos dimensiones, se sigue el mismo principio, multiplicando por cada una de sus dimensiones.

Del mismo modo, reutilizando lo visto en la sección anterior, podemos crear #define’s que nos simplifiquen este trabajo

#define​fill​
(​
a​
)​memset​
(​
a​
,​0​
,​​
sizeof​a​
) //Llenar arreglos de una dimensión

7.6. Optimizar entradas y salidas


En la sección entradas y salidas se mostraron dos formas diferentes de leer entradas y salidas:

● cin/cout, fácil de usar


● scanf/printf, mas versátil (printf permite imprimir con formato de forma idéntica a como lo hace [Link]() en java.

C++ es un derivado de C, y en C el mecanismo estándar es scanf/printf. C++ trae su propio mecanismo por defecto para operaciones de entrada/salida,
que es cin/cout, pero aún, podemos usar cualquiera de los dos mecanismos.

Contrario a la creencia popular, cin/cout NO es mas lento que scanf/printf. Lo que ocurre es que cin/cout se sincroniza internamente con scanf/printf
para que puedas utilizar ambos mecanismos en el mismo programa, y esta sincronización es la que causa cierta lentitud. Por lo tanto la
recomendación es: NO MEZCLAR AMBOS MECANISMOS. O utilizamos únicamente scanf/printf, o utilizamos cin/cout. Si elegimos scanf/printf, no hay
ningún problema, el I/O está optimizado. Si elegimos cin/cout, debemos desactivar la sincronización añadiendo esta linea al inicio del main:

22
ios_base​
::​
sync_with_stdio​
(​
false​
);​
cin​
.​
tie​
(​
NULL​
);

Una cosa mas a tener en cuenta: Al realizar una impresión con cout, podemos provocar un salto de línea con “endl”:

cout ​
<<​​
"​
linea de texto​
"​​
<<​endl;

Sin embargo se recomienda utilizar “\n” en lugar de endl, pues endl provoca un flush inmediato innecesario. De esta forma la linea quedaria:

cout ​
<<​​
"linea de texto"​​
<<​​
"\n"​
;​​
//o bien
cout ​
<<​​
"​
linea de texto\n​
";

¿Entonces, usar cin/cout o scanf/printf? En realidad esto depende de cada uno, el cin/cout correctamente optimizado es tan rapido como scanf/printf
(o incluso ligeramente mas rápido). En cualquier caso, los dos son radicalmente mas rápidos que el Scanner de java (incluso si no hemos optimizado
cin/cout). Mi recomendación es utilizar cin/cout salvo cuando la salida deba tener un formato específico (como por ejemplo doubles con un
determinado número de cifras decimales).

7.7. Un ejemplo completo: Java vs. C++


A continuación se muestra un problema real tomado de una competencia, resuelto en ambos lenguajes, para analizar las diferencias y semejanzas
entre ellos. La idea será la misma en ambos lenguajes: Leeremos desde la consola las notas de un salón de clases. La primera línea nos dará el
número n de estudiantes, y posteriormente recibiremos n líneas, cada una con una nota y el nombre de un estudiante. Un ejemplo de la entrada sería:

5
3.2 Juan
4.1 Luis
4.1 Pedro
1.2 Lucas
3.2 Mateo

23
A continuación, deben imprimirse los estudiantes agrupados por sus notas en orden ascendente (los estudiantes con la misma nota se muestran en el
orden de llegada) de la siguiente manera:

1.2:
Lucas
3.2:
Juan
Mateo
4.1:
Luis
Pedro

El procesamiento se hará de la siguiente manera: Se creará un mapa que para cada nota (double) guarda un vector (arraylist) con los estudiantes que
obtuvieron dicha nota.

Demostración
import​java​
.​
util​
.*; #include​​
<​
bits​
/​
stdc​++.​h>
import​java​
.​
lang​
.*; using​​
namespace​std;
import​java​
.​
io​
.*; int​main​
()​{
public​​
class​​
Main​{ ios_base​::​
sync_with_stdio​ (​false​);​
cin​.​
tie​(​
NULL​
);
public​​
​ static​​
void​main ​ (​
String​
[]​args​){ int​n​
;​​
//Número de estudiantes
Scanner​sc ​
​ =​​
new​​ Scanner​(​
System​.​
in​
); map​
<​
double​,​vector​ <string>​​ >​notas​;
TreeMap​
​ <​
Double​ ,​​
ArrayList​ <​
String​>​​
>​notas ​
=​​
new cin ​
>>​n;
TreeMap​
<>(); while​
(​
n​
­­​​>​​
0​)​{
int​n ​
​ =​sc​.​
nextInt​ (); double​nota;
while​
​ (​
n​
­­​​>​​
0​)​{ string​nombre;
double​nota ​
​ =​sc​.​
nextDouble​(); cin ​
>>​nota ​ >>​nombre;
String​nombre ​
​ =​sc​.​
next​
(); notas​[​
nota​].​push_back​ (​
nombre​);
ArrayList​
​ <​
String​ >​aux; }
if​
​ (​
notas​.​containsKey​ (​
nota​)){ for​
(​
map​
<​double​,​vector​ <string>​​ >::​
iterator it ​ =
aux ​=​notas​ .​
get​
(​
nota​); notas​
.​
begin​();​it ​ !=​notas​ .​
end​
();​it​ ++)​{
}​​
​ else​{ cout ​<<​it​­>​first ​<<​​":\n";
aux ​=​​new​​ArrayList​<​
String​>(); for​
(​
int​i ​ =​​0​
;​i ​ <​it​­>​
second​ .​
size​
();​i​
++)​{
} cout ​<<​it​­>​second​[​
i​
]​​<<​endl;
aux​
.​
add​(​
nombre​ ); }

24
notas​
.​
put​
(​
nota​
,​aux​
); }
} return​​
0;
for​​
​ (​
Map​
.​
Entry​
<​
Double​
,​​
ArrayList​
<​
String​
>​​
>​entry ​
: }
notas​
.​
entrySet​
())​{
System​
​ .​
out​
.​
println​
(​
entry​
.​
getKey​
()​​
+​​
":"​
);
for​
​ (​
int​i ​
=​​
0​
;​
i​<​entry​
.​
getValue​
().​
size​
();​i​
++){
System​
​ .​
out​
.​
println​
(​
entry​
.​
getValue​
().​
get​
(​
i​
));

}
}
}
}

25

También podría gustarte