Algoritmo tipo 2 Insertar o Fusionar

Todas las tareas semanales y preguntas de pensamiento en video para respuestas y análisis ver  Preguntas de pensamiento sobre la estructura de datos de la Universidad de Zhejiang + Respuestas de práctica semanal

Título: Según Wikipedia:

La ordenación por inserción  itera, consumiendo un elemento de entrada cada repetición y haciendo crecer una lista de salida ordenada. Cada iteración, la ordenación por inserción elimina un elemento de los datos de entrada, encuentra la ubicación a la que pertenece dentro de la lista ordenada y lo inserta allí. Se repite hasta que no quedan elementos de entrada.

La ordenación por fusión  funciona de la siguiente manera: divide la lista sin ordenar en N sublistas, cada una con 1 elemento (una lista de 1 elemento se considera ordenada). Luego, combine repetidamente dos sublistas adyacentes para producir nuevas sublistas ordenadas hasta que solo quede 1 sublista.

Ahora, dada la secuencia inicial de enteros, junto con una secuencia que es el resultado de varias iteraciones de algún método de clasificación, ¿puede decir qué método de clasificación estamos usando?

Especificación de entrada:

Cada archivo de entrada contiene un caso de prueba. Para cada caso, la primera línea da un número entero positivo N (≤100). Luego, en la siguiente línea, se proporcionan N enteros como la secuencia inicial. La última línea contiene la secuencia parcialmente ordenada de los N números. Se supone que la secuencia objetivo siempre es ascendente. Todos los números en una línea están separados por un espacio.

Especificación de salida:

Para cada caso de prueba, imprima en la primera línea "Clasificación de inserción" o "Clasificación de combinación" para indicar el método utilizado para obtener el resultado parcial. Luego ejecute este método para una iteración más y muestre en la segunda línea la secuencia resultante. Se garantiza que la respuesta es única para cada caso de prueba. Todos los números en una línea deben estar separados por un espacio, y no debe haber espacio adicional al final de la línea.

Traducción:

Inserte la iteración de clasificación , reutilice un elemento de entrada cada vez y aumente la lista de salida ordenada. En cada iteración, la ordenación por inserción elimina un elemento de los datos de entrada, encuentra su posición en la lista ordenada y la inserta. Se repetirá hasta que no se retengan elementos de entrada.

El principio de funcionamiento de la clasificación por fusión es el siguiente: la lista sin clasificar se divide en N sublistas, y cada sublista contiene 1 elemento (una lista de 1 elementos se considera ordenada). Luego, combine repetidamente dos sublistas adyacentes para generar una nueva sublista ordenada hasta que solo quede una sublista.

Ahora, dada la secuencia inicial de enteros , más una secuencia, esta secuencia es el resultado de múltiples iteraciones de un método de clasificación , ¿puede decir qué método de clasificación estamos usando?

Especificaciones de entrada:

Cada archivo de entrada contiene un caso de prueba. Para cada caso, la primera línea da un número entero positivo N (≤100). En la siguiente línea, se usan N enteros como secuencia inicial. La última fila contiene una secuencia parcialmente ordenada de N números. Se supone que la secuencia objetivo siempre está aumentando. Todos los números en una línea están separados por espacios.

Especificaciones de salida:

Para cada caso de prueba, imprima "insertar ordenación" o "fusionar ordenación" en la primera línea para indicar el método utilizado para obtener resultados parciales. Luego ejecute este método nuevamente para una iteración, y muestre la secuencia de resultados en la segunda línea. Asegúrese de que la respuesta a cada caso de prueba sea única. Todos los números en una línea deben estar separados por espacios, y no debe haber espacios adicionales al final de la línea.

Entrada de muestra 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

Salida de muestra 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

Entrada de muestra 2:

10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6

Salida de muestra 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

Respuesta:

La dificultad radica en cómo encontrar para qué tipo se utiliza.

En primer lugar, sabemos que si el final de la segunda línea está fuera de orden y lo mismo que el final de la primera línea, debe insertarse sort. Debido a que el orden de inserción es de adelante hacia atrás, solo un número limitado de iteraciones no cambiará el orden que no se ha iterado más tarde. Y la primera parte de la segunda fila del orden de inserción ya debe estar ordenada.

Es decir, la secuencia después de que el algoritmo de clasificación de inserción itera un cierto número de veces es: la parte ya ordenada + la segunda mitad de la misma secuencia que la secuencia original.

Considere el orden de fusión nuevamente. El orden de fusión se ordena al menos en cada unidad pequeña. Por ejemplo, después de la primera iteración, cada dos debe ser de pequeño a grande, y después de la segunda iteración, cada cuatro debe ser de pequeño a Grande, pero ¿debemos encontrar la unidad pequeña más grande?

Primero determinemos si se trata de una inserción mediante la descripción anterior.

int ifInsertSort(ElementType ASource[], ElementType ASort[], int N) {
	int i = N - 1;
	for (;i >= 0;i--) {
		if (ASort[i] != ASource[i])break;
	}
	int j = 0;
	for (;j < N-1;j++) {
		if (ASort[j] > ASort[j + 1]) {
			break;
		}
	}
	if (j > i) {
		return 1;//是插入排序
	}
	else {
		return 0;//不是插入排序
	}
}

Pero teniendo en cuenta que la salida es el resultado de otra iteración , este método no es factible . Debido a que no podemos juzgar a partir de este método cómo se ve la iteración nuevamente.

Ahora solo podemos usar una forma estúpida: iterar de dos maneras por separado, y luego juzgar si es lo mismo que la salida cada vez.

Primero creamos tres matrices:

ElementType myArray[MaxVertexNum];//存原数据,插入排序用
ElementType myArray_1[MaxVertexNum];//存原数据,归并排序用
ElementType myArray2[MaxVertexNum];//存第二行数据

Para el tipo de inserción, juzgamos de esta manera:

void InsertionSort(ElementType A[], int N)
{ 
	// 插入排序 
	int P, i;
	ElementType Tmp;
	int flag = 0;
	for (P = 1; P<N; P++) {
		Tmp = A[P]; // 取出未排序序列中的第一个元素
		for (i = P; i>0 && A[i - 1]>Tmp; i--)
			A[i] = A[i - 1]; //依次与已排序序列中元素比较并右移
		A[i] = Tmp; // 放进合适的位置 
		if (flag == 1)break;
		if (isSame(A, myArray2, N)) {
			flag = 1;
			isInsertFlag = 1;
			cout << "Insertion Sort"<<endl;
		}
	}
}

Después de la ejecución, se juzga si la secuencia del orden actual es la misma que la secuencia de la segunda línea en la que leemos . Si la secuencia es la misma, la bandera se establece en 1. Al juzgar flag = 1, se repitió nuevamente, así que interrumpa.

Al mismo tiempo, también tenemos un indicador, isInsertFlag, para determinar si se trata de una ordenación por inserción. Si siempre es diferente, no es una ordenación por inserción .

	InsertionSort(myArray, N);//插入排序
	if (isInsertFlag) {	
		for (int i = 0;i < N - 1;i++)
			cout << myArray[i] << " ";
		cout << myArray[N - 1];
	}	
	else if (!isInsertFlag) {
		cout << "Merge Sort" << endl;
		Merge_Sort(myArray_1, N);
		for (int i = 0;i < N - 1;i++)
			cout << myArray_1[i] << " ";
		cout << myArray_1[N - 1];
	}

El código anterior se utiliza para determinar si se trata de una ordenación por inserción o una fusión.

En el tipo de fusión juzgamos de esta manera:

int isMerge = 0;
void Merge_Sort(ElementType A[], int N)
{
	int length;
	ElementType *TmpA;

	length = 1; // 初始化子序列长
	TmpA = (ElementType*)malloc(N * sizeof(ElementType));
	if (TmpA != NULL) {
		while (length < N) {
			Merge_pass(A, TmpA, N, length);
			if (isMerge == 1) {
				for (int ii = 0;ii < N;ii++)A[ii] = TmpA[ii];
				break;
			}
			if (isSame(TmpA, myArray2, N)) {
				isMerge = 1;
			}

			length *= 2;
			Merge_pass(TmpA, A, N, length);
			if (isMerge == 1) {
				break;
			}
			if (isSame(TmpA, myArray2, N)) {
				isMerge = 1;
			}
			length *= 2;
		}
		free(TmpA);
	}
	else printf("空间不足");
}

Como cada ciclo while se fusiona dos veces, uno se fusiona en A y el otro se fusiona en TmpA, por lo que debe procesarse por separado.

El código completo es el siguiente:

#include <iostream>
using namespace std;

#define MaxVertexNum 105   //最大100个数据,多留出5个空白
typedef int ElementType;
ElementType myArray[MaxVertexNum];//存原数据,插入排序用
ElementType myArray_1[MaxVertexNum];//存原数据,归并排序用
ElementType myArray2[MaxVertexNum];//存第二行数据

int isInsertFlag = 0;
bool isSame(ElementType A[], ElementType B[], int N) {
	for (int i = 0;i < N;i++) {
		if (A[i] != B[i])return false;
	}
	return true;
}


void InsertionSort(ElementType A[], int N)
{ 
	// 插入排序 
	int P, i;
	ElementType Tmp;
	int flag = 0;
	for (P = 1; P<N; P++) {
		Tmp = A[P]; // 取出未排序序列中的第一个元素
		for (i = P; i>0 && A[i - 1]>Tmp; i--)
			A[i] = A[i - 1]; //依次与已排序序列中元素比较并右移
		A[i] = Tmp; // 放进合适的位置 
		if (flag == 1)break;
		if (isSame(A, myArray2, N)) {
			flag = 1;
			isInsertFlag = 1;
			cout << "Insertion Sort"<<endl;
		}
	}
}

// 归并排序 - 递归实现 
// L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置
void Merge(ElementType A[], ElementType TmpA[], int L, int R, int RightEnd)
{ // 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列
	int LeftEnd, NumElements, Tmp;
	int i;

	LeftEnd = R - 1; // 左边终点位置 
	Tmp = L;         // 有序序列的起始位置 
	NumElements = RightEnd - L + 1;

	while (L <= LeftEnd && R <= RightEnd) {
		if (A[L] <= A[R])
			TmpA[Tmp++] = A[L++]; // 将左边元素复制到TmpA 
		else
			TmpA[Tmp++] = A[R++]; // 将右边元素复制到TmpA 
	}

	while (L <= LeftEnd)
		TmpA[Tmp++] = A[L++]; // 直接复制左边剩下的 
	while (R <= RightEnd)
		TmpA[Tmp++] = A[R++]; // 直接复制右边剩下的 

	for (i = 0; i < NumElements; i++, RightEnd--)
		A[RightEnd] = TmpA[RightEnd]; // 将有序的TmpA[]复制回A[] 
}
// 归并排序 - 循环实现 
// 这里Merge函数在递归版本中给出 
// length = 当前有序子列的长度

void Merge_pass(ElementType A[], ElementType TmpA[], int N, int length)
{ // 两两归并相邻有序子列 
	int i, j;

	for (i = 0; i <= N - 2 * length; i += 2 * length)
		Merge(A, TmpA, i, i + length, i + 2 * length - 1);
	if (i + length < N) // 归并最后2个子列
		Merge(A, TmpA, i, i + length, N - 1);
	else // 最后只剩1个子列
		for (j = i; j < N; j++) TmpA[j] = A[j];

}
int isMerge = 0;
void Merge_Sort(ElementType A[], int N)
{
	int length;
	ElementType *TmpA;

	length = 1; // 初始化子序列长
	TmpA = (ElementType*)malloc(N * sizeof(ElementType));
	if (TmpA != NULL) {
		while (length < N) {
			Merge_pass(A, TmpA, N, length);
			if (isMerge == 1) {
				for (int ii = 0;ii < N;ii++)A[ii] = TmpA[ii];
				break;
			}
			if (isSame(TmpA, myArray2, N)) {
				isMerge = 1;
			}

			length *= 2;
			Merge_pass(TmpA, A, N, length);
			if (isMerge == 1) {
				break;
			}
			if (isSame(TmpA, myArray2, N)) {
				isMerge = 1;
			}
			length *= 2;
		}
		free(TmpA);
	}
	else printf("空间不足");
}

int main(void) {
	int N;cin >> N;
	for (int i = 0;i < N;i++) {
		cin >> myArray[i];
		myArray_1[i] = myArray[i];
	}
		
	for (int i = 0;i < N;i++)
		cin >> myArray2[i];

	InsertionSort(myArray, N);//插入排序
	if (isInsertFlag) {	
		for (int i = 0;i < N - 1;i++)
			cout << myArray[i] << " ";
		cout << myArray[N - 1];
	}	
	else if (!isInsertFlag) {
		cout << "Merge Sort" << endl;
		Merge_Sort(myArray_1, N);
		for (int i = 0;i < N - 1;i++)
			cout << myArray_1[i] << " ";
		cout << myArray_1[N - 1];
	}

	system("pause");
	return 0;
}



Resultados de la prueba:

187 artículos originales publicados · elogiados 418 · 10,000+ vistas

Supongo que te gusta

Origin blog.csdn.net/tiao_god/article/details/105499321
Recomendado
Clasificación