Una de las preguntas más difíciles que se hacen en una entrevista.
Intercambia los valores de dos variables como a=10
y b=15
.
Generalmente, para intercambiar dos valores de variables, necesitamos una tercera variable como:
temp=a;
a=b;
b=temp;
Ahora el requisito es intercambiar valores de dos variables sin usar la tercera variable.
Respuestas:
Usando el algoritmo de intercambio xor
¿Por qué la prueba?
La prueba es para asegurar que xey tengan diferentes ubicaciones de memoria (en lugar de valores diferentes). Esto se debe a que,
(p xor p) = 0
y si tanto x como y comparten la misma ubicación de memoria, cuando uno se establece en 0, ambos se establecen en 0. Cuando tanto * x como * y son 0, todas las demás operaciones xor en * x e * y serán iguales 0 (ya que son iguales), lo que significa que la función establecerá tanto * x como * y en 0.Si tienen los mismos valores pero no la misma ubicación de memoria, todo funciona como se esperaba
¿Debería usarse esto?
En casos generales, no. El compilador optimizará la variable temporal y dado que el intercambio es un procedimiento común, debería generar el código de máquina óptimo para su plataforma.
Tomemos, por ejemplo, este programa de prueba rápida escrito en C.
Compilado usando:
La versión xor lleva
Donde como toma la versión con la variable temporal:
fuente
la forma general es:
sin embargo, es posible que tenga cuidado con los desbordamientos y tampoco todas las operaciones tienen una inversa que esté bien definida para todos los valores que la operación está definida. p. ej. * y / trabajar hasta que A o B sea 0
xor es particularmente agradable ya que se define para todos los ints y es su propio inverso
fuente
fuente
a+b
desborda?int
,unsigned short
, ...), que todavía funciona en el final, incluso con desbordamiento, ya que si a + b desborda, entonces a - b se subdesbordamiento. Con estos tipos de enteros básicos, los valores simplemente se mueven.unsigned
tipos enteros está bien y siempre funciona. En tipos firmados, invocaría un comportamiento indefinido en caso de desbordamiento.Nadie ha sugerido usarlo
std::swap
todavía.No utilizo ninguna variable temporal y dependiendo del tipo
a
yb
la implementación puede tener una especialización que tampoco. La implementación debe escribirse sabiendo si un 'truco' es apropiado o no. No tiene sentido intentar adivinar.De manera más general, probablemente querría hacer algo como esto, ya que funcionaría para tipos de clases que permitan a ADL encontrar una mejor sobrecarga si es posible.
Por supuesto, la reacción del entrevistador a esta respuesta podría decir mucho sobre la vacante.
fuente
std::
, lasswap
implementaciones definidas por el usuario para los tipos definidos por el usuario también están disponibles para llamar (esto es lo que se entiende por "funcionaría para los tipos de clase que permitan a ADL encontrar una mejor sobrecarga si es posible").std::swap
utiliza memoria temporal adicional en su implementación ¿no? cplusplus.com/reference/utility/swapComo ya señaló manu, el algoritmo XOR es uno de los populares que funciona para todos los valores enteros (que incluye punteros, con algo de suerte y conversión). En aras de la integridad, me gustaría mencionar otro algoritmo menos poderoso con suma / resta:
Aquí debe tener cuidado con los desbordamientos / subdesbordamientos, pero de lo contrario, funciona igual de bien. Incluso puede probar esto en flotadores / dobles en el caso de que XOR no esté permitido en ellos.
fuente
std::swap()
? Claro, puede convertir punteros en números enteros y viceversa (asumiendo que hay un tipo de entero lo suficientemente grande, lo cual no está garantizado), pero eso no es lo que sugirió; insinuó que los punteros son números enteros, no que se puedan convertir en números enteros. Sí, la respuesta aceptada no funcionará para los punteros. La respuesta de Charles Bailey utilizandostd::swap
es realmente la única correcta.std::swap
se puede implementar sin usar una tercera variable.Las preguntas estúpidas merecen respuestas adecuadas:
El único buen uso de la
register
palabra clave.fuente
Intercambiar dos números usando la tercera variable sería así,
Intercambiar dos números sin usar la tercera variable
fuente
fuente
cout << "Enter the two no=:"
que esperaba leercout << "Now enter the two no in reverse order:"
a+b
oa-b
desbordamientos. Además,void main()
no es válido y<conio.h>
no es estándar.Dado que la solución original es:
Puede convertirlo en un delineador de dos usando:
Luego conviértalo en un delineador usando:
fuente
y
se lee y escribe en la misma expresión sin ningún punto de secuencia intermedio.Si cambia un poco la pregunta para preguntar sobre 2 registros de ensamblaje en lugar de variables, puede usar también la
xchg
operación como una opción y la operación de pila como otra.fuente
xchg
operación te refieres? La pregunta no especificó una arquitectura de CPU.Considere
a=10
,b=15
:fuente
a=10
yb=1.5
.Actualización: en esto estamos tomando la entrada de dos enteros del usuario. Entonces usamos la operación XOR bit a bit para intercambiarlos.
Digamos que tenemos dos enteros
a=4
yb=9
ya continuación:fuente
Aquí hay una solución más pero con un solo riesgo.
código:
cualquier valor en la ubicación a + 1 será anulado.
fuente
*(&a+1)
bien podría serb
.void main()
no es válido.<conio.h>
no es estándar (y ni siquiera lo usa).Por supuesto, la respuesta de C ++ debería ser
std::swap
.Sin embargo, tampoco existe una tercera variable en la siguiente implementación de
swap
:O, como una sola línea:
fuente
fuente
ese es el algoritmo de intercambio XOR correcto
debe asegurarse de que las ubicaciones de la memoria sean diferentes y también de que los valores reales sean diferentes porque A XOR A = 0
fuente
Puede hacerlo ... de manera fácil ... dentro de una línea Logic
o
fuente
b
se lee y modifica dentro de la misma expresión, sin un punto de secuencia intermedio.fuente
La mejor respuesta sería usar XOR y usarlo en una línea sería genial.
x, y son variables y la coma entre ellas introduce los puntos de secuencia para que no dependa del compilador. ¡Salud!
fuente
Veamos un ejemplo simple de c para intercambiar dos números sin usar la tercera variable.
programa 1:
Salida:
Antes del intercambio a = 10 b = 20 Después del intercambio a = 20 b = 10
Programa 2: Uso de * y /
Veamos otro ejemplo para intercambiar dos números usando * y /.
Salida:
Antes del intercambio a = 10 b = 20 Después del intercambio a = 20 b = 10
Programa 3: haciendo uso del operador XOR bit a bit:
El operador XOR bit a bit se puede utilizar para intercambiar dos variables. El XOR de dos números xey devuelve un número que tiene todos los bits como 1 siempre que los bits de xey difieran. Por ejemplo, XOR de 10 (en binario 1010) y 5 (en binario 0101) es 1111 y XOR de 7 (0111) y 5 (0101) es (0010).
Salida:
Después del intercambio: x = 5, y = 10
Programa 4:
Nadie ha sugerido usar std :: swap, todavía.
No utilizo ninguna variable temporal y, dependiendo del tipo de ayb, la implementación puede tener una especialización que tampoco. La implementación debe escribirse sabiendo si un 'truco' es apropiado o no.
Problemas con los métodos anteriores:
1) El método basado en la multiplicación y la división no funciona si uno de los números es 0, ya que el producto se convierte en 0 independientemente del otro número.
2) Ambas soluciones aritméticas pueden provocar un desbordamiento aritmético. Si xey son demasiado grandes, la suma y la multiplicación pueden salirse del rango de números enteros.
3) Cuando usamos punteros a una variable y hacemos un intercambio de función, todos los métodos anteriores fallan cuando ambos punteros apuntan a la misma variable. Echemos un vistazo a lo que sucederá en este caso si ambos apuntan a la misma variable.
// Método basado en XOR bit a bit
// Método basado en aritmética
Veamos el siguiente programa.
Salida :
Después del intercambio (& x, & x): x = 0
Es posible que sea necesario intercambiar una variable consigo misma en muchos algoritmos estándar. Por ejemplo, vea esta implementación de QuickSort donde podemos intercambiar una variable consigo misma. El problema anterior se puede evitar poniendo una condición antes del intercambio.
Salida :
Después del intercambio (& x, & x): x = 10
fuente
Quizás fuera del tema, pero si sabe lo que está intercambiando una sola variable entre dos valores diferentes, es posible que pueda hacer una lógica de matriz. Cada vez que se ejecuta esta línea de código, cambiará el valor entre 1 y 2.
fuente
Podrías hacerlo:
O use make_tuple cuando intercambie más de dos variables:
¡Pero no estoy seguro de si internamente std :: tie usa una variable temporal o no!
fuente
En javascript:
Tenga en cuenta el tiempo de ejecución de ambas opciones.
Al ejecutar este código, lo medí.
Como puede ver (y como muchos dijeron), el intercambio en el lugar (xor) toma mucho tiempo que la otra opción que usa la variable temporal.
fuente
A R le falta una asignación concurrente propuesta por Edsger W. Dijkstra en A Discipline of Programming , 1976, cap.4, p.29. Esto permitiría una solución elegante:
fuente
Es muy simple, pero puede generar una advertencia.
fuente
b=a
se realiza antes o despuésa + b
.solución de una sola línea para intercambiar dos valores en lenguaje c.
fuente
fuente