En programación informática , el acto de intercambiar dos variables se refiere a intercambiar mutuamente los valores de las variables. Por lo general, esto se hace con los datos en la memoria . Por ejemplo, en un programa , dos variables pueden definirse así (en pseudocódigo ):
elemento de datos x := 1elemento de datos y := 0intercambiar (x, y);
Después de ejecutar swap(), x contendrá el valor 0 e y contendrá 1; sus valores se han intercambiado. Esta operación se puede generalizar a otros tipos de valores, como cadenas y tipos de datos agregados . Los ordenamientos por comparación utilizan intercambios para cambiar las posiciones de los datos.
En muchos lenguajes de programación , la función swap está incorporada. En C++ , se proporcionan sobrecargas que permiten que std::swap intercambie algunas estructuras grandes en tiempo O(1).
El método más simple y probablemente el más utilizado para intercambiar dos variables es utilizar una tercera variable temporal :
definir intercambio (x, y) temperatura := x x := y y := temperatura
Si bien esto es conceptualmente simple y en muchos casos la única forma conveniente de intercambiar dos variables, utiliza memoria adicional. Si bien esto no debería ser un problema en la mayoría de las aplicaciones, los tamaños de los valores que se intercambian pueden ser enormes (lo que significa que la variable temporal también puede ocupar mucha memoria) o la operación de intercambio puede tener que realizarse muchas veces, como en los algoritmos de ordenamiento.
Además, intercambiar dos variables en lenguajes orientados a objetos como C++ puede implicar una llamada al constructor y destructor de la clase para la variable temporal, y tres llamadas al constructor de copia . Algunas clases pueden asignar memoria en el constructor y desasignarla en el destructor, creando así llamadas costosas al sistema. Los constructores de copia para clases que contienen una gran cantidad de datos, por ejemplo en una matriz , pueden incluso necesitar copiar los datos manualmente.
El intercambio XOR utiliza la operación XOR para intercambiar dos variables numéricas. Generalmente se promociona como más rápido que el método ingenuo mencionado anteriormente; sin embargo, tiene desventajas . El intercambio XOR se utiliza generalmente para intercambiar tipos de datos de bajo nivel, como números enteros . Sin embargo, en teoría, es capaz de intercambiar dos valores cualesquiera que se puedan representar mediante cadenas de bits de longitud fija .
Este método intercambia dos variables sumando y restando sus valores. Este método rara vez se utiliza en aplicaciones prácticas, principalmente porque:
Los contenedores que asignan memoria del montón mediante punteros pueden intercambiarse en una sola operación, intercambiando únicamente los punteros. Esto suele ocurrir en lenguajes de programación que admiten punteros, como C o C++ . La biblioteca de plantillas estándar sobrecarga su función de intercambio incorporada para intercambiar el contenido de los contenedores de manera eficiente de esta manera. [1]
Como las variables de puntero suelen tener un tamaño fijo (por ejemplo, la mayoría de las computadoras de escritorio tienen punteros de 64 bits de longitud) y son numéricas, se pueden intercambiar rápidamente utilizando el intercambio XOR.
Algunos lenguajes, como Ruby o Python, admiten asignaciones paralelas , lo que simplifica la notación para intercambiar dos variables:
a, b = b, a
Esta es una forma abreviada de referirse a una operación que involucra una estructura de datos intermedia: en Python, una tupla; en Ruby, una matriz.
Javascript 6+ admite operadores de desestructuración que hacen lo mismo:
[a, b] = [b, a];
Aquí, dos variables de alcance global se pasan por valor a través de una función, lo que elimina la necesidad de una variable de almacenamiento temporal.
x = 1 ; y = 2 ; consola . log ( x + " " + y ); // salidas 1 2 función swap ( a , b ) { x = b ; y = a ; } intercambiar ( x , y ); consola . log ( x + " " + y ); // salidas 2 1
Debido a las muchas aplicaciones del intercambio de datos en las computadoras, la mayoría de los procesadores ahora brindan la capacidad de intercambiar variables directamente a través de instrucciones integradas. Los procesadores x86 , por ejemplo, incluyen una instrucción XCHG para intercambiar dos registros directamente sin necesidad de utilizar un tercer registro temporal. Incluso se proporciona una instrucción de comparación e intercambio en algunas arquitecturas de procesadores, que compara e intercambia condicionalmente dos registros. Esto se utiliza para admitir técnicas de exclusión mutua .
XCHG puede no ser tan eficiente como parece. Por ejemplo, en procesadores x86 , XCHG bloqueará implícitamente el acceso a cualquier operando en la memoria para garantizar que la operación sea atómica y, por lo tanto, puede no ser eficiente al intercambiar memoria. Este bloqueo es importante cuando se utiliza para implementar una sincronización segura para subprocesos, como en los mutex . Sin embargo, un XCHG suele ser la forma más rápida de intercambiar dos palabras del tamaño de una máquina que residen en registros . El cambio de nombre de registros también se puede utilizar para intercambiar registros de manera eficiente.
Con la llegada de la canalización de instrucciones en las computadoras modernas y los procesadores multinúcleo que facilitan la computación paralela , se pueden realizar dos o más operaciones a la vez. Esto puede acelerar el intercambio utilizando variables temporales y darle una ventaja sobre otros algoritmos. Por ejemplo, el algoritmo de intercambio XOR requiere la ejecución secuencial de tres instrucciones. Sin embargo, utilizando dos registros temporales, dos procesadores que se ejecutan en paralelo pueden intercambiar dos variables en dos ciclos de reloj:
Paso 1 Procesador 1: temp_1 := X Procesador 2: temp_2 := YPaso 2 Procesador 1: X := temp_2 Procesador 2: Y := temp_1
Se utilizan más registros temporales y se necesitan cuatro instrucciones en lugar de tres. En cualquier caso, en la práctica esto no se podría implementar en procesadores separados, ya que viola las condiciones de Bernstein para computación paralela. Sería inviable mantener los procesadores lo suficientemente sincronizados entre sí para que este intercambio tenga alguna ventaja significativa sobre las versiones tradicionales. Sin embargo, se puede utilizar para optimizar el intercambio para un solo procesador con múltiples unidades de carga/almacenamiento.