3 8 9 2 7 5 6 4 El pivote es el 4. El índice i avanzaría hasta el 8 y el j hasta el 2.
3 8 9 2 7 5 6 4
Se intercambiarían ambos elementos:
3 2 9 8 7 5 6 4
Después el índice i avanzaría hasta el 9 y el j hasta el 3. Como en este caso los índices se cruzan, se sale del bucle principal. Al salir se coloca el pivote en su sitio (que será el punto señalado por el índice i. Es decir se intercambian el 4 y el 9:
3 2 4 8 7 5 6 9
Tras este paso se llamaría a la función usando el primer trozo: 3 2
Se empezaría el algoritmo. Y se colocaría el índice i sobre el elemento 3 (el j se saldría del array). Habría un intercambio entre el 2 y el 3. En la siguiente llamada recursiva, no ocurriría nada ya que se cruzan los índices. La otra llamada que falta es para el trozo: 8 7 5 6 9
Con el que se seguiría el proceso (el pivote es malo ya que es el 9, pero funcionaría). Hay versiones iterativas del algoritmo que mejoran su rendimiento, pero no se expondrán en estos apuntes.
arrays multidimensionales
En muchas ocasiones se necesitan almacenar series de datos que se analizan de forma tabular. Es decir en forma de tabla, con su fila y su columna. Por ejemplo:
columna 0 columna 1 columna 2 columna 3 columna 4 columna 5
fila 0 4 5 6 8 9 3
fila 1 5 4 2 8 5 8
fila 2 6 3 5 7 8 9
Si esos fueran los elementos de un array de dos dimensiones (por ejemplo el array a) el elemento resaltado sería el a[3][1] (cuyo valor es 8)
[111]
La declaración de arrays de dos dimensiones se realiza así: int a[3][6];
a es un array de tres filas y seis columnas. Otra forma de declarar es inicializar los valores:
int a[][]={{2,3,4},{4,5,2},{8,3,4},{3,5,4}}; En este caso a es un array de cuatro filas y tres columnas.
Al igual que se utilizan arrays de dos dimensiones se pueden declarar arrays de más dimensiones. Por ejemplo imaginemos que queremos almacenar las notas de 6 aulas que tienen cada una 20 alumnos y 6 asignaturas. Eso sería un array de una dimensión de 720 elementos, pero es más claro el acceso si hay tres dimensiones: la primera para el aula, la segunda para el alumno y la tercera para la asignatura.
En ese caso se declararía el array así: int a[6][20][6];
Y para colocar la nota en el aula cuarta al alumno cinco de la asignatura 3 (un ocho es la nota):
a[3][4][2]=8;
Cuando un array multidimensional se utiliza como parámetro de una función, entonces se debe especificar el tamaño de todos los índices excepto del primero. La razón está en que de otra forma no se pueden calcular los índices correspondientes por parte de la función. Es decir:
void funcion(int a[][]);
Eso es incorrecto, en cuanto hiciéramos uso de un acceso a a[2][3], por ejemplo, no habría manera de saber en qué posición de memoria está ese valor ya que sin saber cuántas columnas forman parte del array, es imposible determinar esa posición. Lo correcto es:
[112]
[6.3]
punteros
[6.3.1]
introducción
Se trata de una de las herramientas más importantes de C++. Los punteros (o apuntadores) son variables cuyo contenido es la dirección de otra variable. Es decir son variables que señalan al contenido de otras variables.
En general una variable contiene un valor que es con el que se opera, en el caso de los punteros no es un valor directo sino que es la dirección de memoria en la que se encuentra el valor.
26
X
120301
p
Si x es una variable normal y p es un puntero, 120301 será una dirección de memoria. Supongamos que esa dirección de memoria es la de la variable x. Entonces p apunta a x:
26
X p
Para esta labor se usan dos operadores: * Devuelve el contenido de un puntero & Devuelve la dirección de una variable
[6.3.2]
declaración de punteros
Un puntero señala a una dirección de memoria. Esa dirección contendrá valores de un determinado tipo. Por ello al declarar un puntero hay que indicar de qué tipo es el puntero; o, lo que es lo mismo, el tipo de valores a los que apunta. La sintaxis es:
tipo *nombrePuntero;
El asterisco es el que indica que lo que tenemos es un puntero. El tipo es el tipo de valores a los que señala el puntero. Ejemplo:
int *ptrSuma;
[113]
[6.3.3]
operaciones con punteros
Para asignar valores a un puntero muchas veces se utiliza el operador & (ya comentado en los temas anteriores) que sirve para obtener la dirección de una variable. Ejemplo:
int *ptrSuma, suma=18; ptrSuma=&suma;
Desde la última instrucción ptrSuma contendrá la dirección de la variable suma; o dicho de otra forma: ptrSuma apunta a la variable suma.
Cuando un puntero tiene un determinado valor (apunta a una determinada dirección), a menudo desearemos acceder al contenido de la dirección a la que apunta. Para ello se utiliza el operador “*”, que permite acceder al contenido del puntero.
Ejemplo:
int *ptrSuma, suma=18; ptrSuma=&suma;
cout<<*ptrSuma; //Escribe 18
Ese mismo operador se utiliza para cambiar el valor de la variable a la que apunta el puntero.
Ejemplo:
int *ptrSuma, suma=18; ptrSuma=&suma;
*ptrSuma=11;
cout<<suma; // Escribe 11, ahora suma vale 11
Esto es lo interesante de los punteros, a través de los punteros se modifican otras variables. Incluso sería válido:
cin>>*ptrSuma; //Lo que lea se almacena en suma
Cuando se desea que un puntero no señale a nada en particular, se puede asignar al valor NULL o al valor 0. El significado es el mismo. Por cierto, en C++ el valor 0 es el único entero que se puede asignar a un puntero (sin embargo en C sí era posible asignar a una dirección en concreto).