Par inverso de práctica de algoritmos

Par inverso de práctica de algoritmos

El orden inverso es muy clásico para el problema. El ataque de fuerza bruta más simple tiene una complejidad de tiempo de O (n 2 ), y el algoritmo con una complejidad de tiempo mayor que O (n 2 ) es muy malo, por lo que usamos el algoritmo de clasificación de fusión para cambiarlo. Obtenga el algoritmo O (nlogn).

Definición de par de orden inverso: Si i <j && arr [i]> arr [j] en la secuencia, entonces arr [i] y arr [j] son ​​un par de pares de orden inverso.

  • referencia de algoritmo java
// 逆序对个数
private static long ropCount = 0;

/**
 * 计算逆序对
 * 
 * @param arr
 * @param left
 * @param right
 */
public static void calcRop(int[] arr, int left, int right) {
    
    
	if (left >= right)
		return;
	int mid = (left + right) >>> 1;
	calcRop(arr, left, mid);
	calcRop(arr, mid + 1, right);
	calc(arr, left, mid, right);
}

/**
 * 一次计算
 * 
 * @param arr
 * @param left
 * @param mid
 * @param right
 */
public static void calc(int[] arr, int left, int mid, int right) {
    
    
	int i = left;
	int j = mid + 1;
	while (i < j && j <= right) {
    
    
		while (i < j && arr[i] <= arr[j])
			i++;
		ropCount += j - i;
		int temp = arr[j];
		System.arraycopy(arr, i, arr, i + 1, j - i);
		arr[i] = temp;
		i++;
		j++;
	}
}
  • Prueba de algoritmo

La prueba de corrección
tiene tan pocos conjuntos de datos

datos Número de pares inversos
{9, 8, 7, 5, 2, 4, 5, 6} 20
{7, 5, 5, 4, 3, 3, 5, 4, 4, 1, 6} 32
{9, 8, 7, 1, 2, 3, 4, 3, 2, 1} 33
{7, 5} 1
{5, 5} 0
{5} 0
{} 0

Después de ejecutar por separado, los resultados fueron todos correctos y no se encontraron datos que no coincidieran con los resultados.
Prueba de esfuerzo
Ejecute un millón de datos para ver cuánto tiempo lleva.

int[] arr = new int[1000*1000];
for (int i = 0; i < arr.length; i++) {
    
    
	arr[i] = (int)(Math.random()*100 + 1);
}
long start = System.currentTimeMillis();
calcRop(arr, 0, arr.length - 1);
System.out.println(ropCount);
long end = System.currentTimeMillis();
System.out.println("一百万条数据用时:" + (end-start)/1000 + "s");

Inserte la descripción de la imagen aquí
¡daño! Puede ser que mi propio algoritmo de fusión no sea bueno, y se necesita un minuto para un millón de datos. . .

Lo cambié de nuevo. El algoritmo de fusión de una sola vez anterior usa el tiempo para cambiar el espacio. Siempre se ha operado en arr y requiere un movimiento constante de elementos, por lo que lleva mucho tiempo.

La idea de mejora es cambiar el espacio por el tiempo, usar una matriz auxiliar que sea la misma que la matriz original y usar el método de poner en cola grandes y pequeñas para realizar una fusión.
El método mejorado de cálculo de combinación de una sola vez es el siguiente:

/**
* 一次计算
 * 
 * @param arr
 * @param left
 * @param mid
 * @param right
 */
public static void calc(int[] arr,int left,int mid,int right) {
    
    
	// 辅助数组 空间换时间
	int[] helper = new int[right-left+1];
	int i = left;
	int j = mid + 1;
	int index = 0;
	while (i <= mid && j <= right) {
    
    
		if(arr[i] <= arr[j]) {
    
    
			helper[index++] = arr[i];
			i++;
		}else {
    
    
			helper[index++] = arr[j];
			// 此时有mid-i+1个数比j位置的数大,即增加mid-i+1个逆序对
			ropCount += mid-i+1;
			j++;
		}
	}
	// 后半部分没搬完
	if(i > mid && j <= right) {
    
    
		System.arraycopy(arr, j, helper, index, right-j+1);
	}
	// 前半部分没搬完
	if(i <= mid && j > right) {
    
    
		System.arraycopy(arr, i, helper, index, mid-i+1);
	}
	System.arraycopy(helper, 0, arr, left, helper.length);
}

Pruébelo con un millón de datos:

Inserte la descripción de la imagen aquí
Mire, la velocidad ha mejorado cualitativamente, así que en la era del hardware avanzado, no sea tacaño y use el tiempo para el espacio. El uso adecuado del espacio auxiliar aumentará enormemente la velocidad del algoritmo.

¡Eso es, jaja, adiós!

Supongo que te gusta

Origin blog.csdn.net/L333333333/article/details/105253762
Recomendado
Clasificación