Desmontagem e análise do algoritmo de classificação de Hill

Prefácio : Depois de ler muitas explicações na Internet, parece não muito intuitivo. Portanto, pretendo usar um vernáculo para explicar o algoritmo de Hill claramente. Todos sabem que, na verdade, é uma versão aprimorada do tipo de inserção. Todos nós sabemos que se houver mais números ordenados localmente em um conjunto de dados, a classificação por inserção será mais eficiente. (Se você não entende, você pode ir para entender). Conhecendo esse recurso, o algoritmo de Hill nasceu disso.

Primeiro, vamos revisar o tipo de inserção

//比如有组数据:
int[] arr = {
    
    8, 6, 2, 3, 1, 5, 7, 4};

Resumo do texto: suponha que o primeiro elemento seja o menor número. Então, temos que voltar atrás do índice = 1, pegar os seguintes números por sua vez e compará-los com os números anteriores para encontrar o menor número. Ou seja, quando índice = 1, então arr [1] é comparado com arr [0]. Quando índice = 2, compare arr [2] com arr [1] para obter um valor mínimo e, em seguida, compare com arr [0]. Finalmente, conclua a classificação de pequeno a grande porte.

Portanto, o código é o seguinte

	//{8, 6, 2, 3, 1, 5, 7, 4}
    public void inseartSort(int[] arr) {
    
    
		//所以外层循环,我们跳过第一个元素 8,拿后面的数和前面的数比较
        for (int i = 1; i < arr.length; i++) {
    
    
			//1、这层的循环是拿后面的数和前面的【依次比较】得出最小数
            //2、下面内层循环不知道怎么写,我们可以先来拆分下逻辑
            //   (1)先看外层循环,index = 1,我们要拿arr[1]与arr[0]比较,较小的数字排在前面
            //   (2)继续看外层循环,index = 2,我们首先要拿arr[2]和arr[1]作比较,得出最小数后,继续和arr[0]做比较。
            // 	      相当于index--了。
			//	 (3)综上所述:外层循环的起始点,就是内层循环的起始点,其次index--才能依次和前面的数比较,做好排序。
            //        既然是index--,那么index要满足的条件是index > 0 。不然异常。所以代码如下
            for (int j = i; j > 0; j--) {
    
    
                if (arr[j] < arr[j - 1]) {
    
    
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }


Segundo, Hill sort

Conheça o algoritmo de ordenação por inserção. Um longo conjunto de dados. Quanto mais números ordenados localmente, mais eficiente será a classificação de inserção e melhor será o desempenho.
Algoritmo de Hill: ele é aprimorado usando as características desse tipo de inserção. Ele tem um conceito de lacuna incremental aqui. Não discutiremos a complexidade do tempo trazida pela sequência incremental por enquanto.

Se ainda for aquele conjunto de dados: {8, 6, 2, 3, 1, 5, 7, 4}. Suponha que o incremento aqui seja gap = arr.length / 2. Ou seja, 4, ele agrupará o array logicamente em várias partes (também pode ser considerado como o incremento de várias partes) e, em seguida, inserirá e classificará os grupos lógicos por sua vez, e o array ainda será o mesmo. Use gap / = 2 após a classificação. Isso é 2. Continue a agrupar logicamente, continue a inserir classificação. Dessa forma, a maioria dos dados no array original são dados ordenados. Finalmente, gap = 1, insira a classificação da matriz onde a maioria dos dados são dados ordenados. Então a velocidade é muito mais rápida, o desempenho é conveniente e muito eficiente.

Pode ser muito geral, consulte a análise


2.1, quando gap = 4

Quando gap = 4, então

  • conjunto arr [0] e arr [4]
  • arr [1] e arr [5] conjunto
  • arr [2] e arr [6] definido
  • arr [3] e arr [7] um conjunto
//数据就对应如下
8  6  2  3  1  5  7  4
|  |  |  |  |  |  |  |
8--|--|--|--1  |  |  |  
   6--|--|-----5  |	 |
	  2--|--------7  |
		 3-----------4

Este é um agrupamento lógico,

  • Depois que 8 e 1 são classificados: 1 8;
  • Depois que 5 e 6 são classificados: 5 6;
  • Depois que 2 e 7 são classificados: 2 7;
  • Depois que 3 e 4 são classificados: 3 4.
8  6  2  3  1  5  7  4
|  |  |  |  |  |  |  |
1--|--|--|--8  |  |  |  
   5--|--|-----6  |	 |
	  2--|--------7  |
		 3-----------4

Olhando verticalmente, os resultados da classificação são: 1 5 2 3 8 6 7 4


2.2, quando gap = 2

Quando o gap for 2, ele será separado por 2 para agrupar, é claro, será dividido em 2 grupos

1  5  2  3  8  6  7  4
|  |  |  |  |  |  |  |
1--|--2--|--8--|--7  |  
   |     |     |     |
   |     |     |     |
   5-----3-----6-----4

O agrupamento quando gap = 2 é

  • 1 2 8 7; após a classificação, 1 2 7 8
  • 5 3 6 4; após a classificação, 3 4 5 6

Então é

1  5  2  3  8  6  7  4
|  |  |  |  |  |  |  |
1--|--2--|--7--|--8  |  
   |     |     |     |
   |     |     |     |
   3-----4-----5-----6

Olhando verticalmente, os resultados da classificação são: 1 3 2 4 7 5 8 6

Finalmente, quando gap = 1, é uma classificação de inserção normal. Algumas pessoas podem dizer que, se você fizer isso em incrementos, o último conjunto de dados não estará em ordem para a maioria dos números. Porque, para fins de explicação, escolhi tamanho de dados relativamente pequeno = 8. Se o tamanho> = 100.000, será muito óbvio.


Três, a expressão java de classificação Hill

Através da explicação acima, nós sabemos. Na verdade, a classificação de Hill tem um conceito adicional de incremento, que é praticamente o mesmo

Em primeiro lugar, sabemos a mudança da lacuna incremental

//不难理解,gap最终变化是4,2,1
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    }

Em seguida, quando colocamos gap = 1, ou seja, o código para classificação de inserção normal é movido diretamente para


   for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
        for (int i = 1; i < arr.length; i++) {
    
    
            for (int j = i; j > 0; j--) {
    
    
                if (arr[j] < arr[j - 1]) {
    
    
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
    
    
    
   //上面式子看不大出来,我们把它变一下如下
   //看看哪里时候把gap加上
   for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
        for (int i = 1; i < arr.length; i++) {
    
    
            for (int j = i; j >= 1; j-=1) {
    
     //主要是修改了j>0 改成了 j>=1。 j-- 改成了 j-=1
                if (arr[j] < arr[j - 1]) {
    
    
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }




//改完之后,我们把gap=1的情况改成gap。也就是把1改成gap变化如下
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
    
    
            for (int i = gap; i < arr.length; i++) {
    
    
                for (int j = i; j >= gap; j -= gap) {
    
    
                    if (arr[j] < arr[j - gap]) {
    
    
                        int temp = arr[j - gap];
                        arr[j - gap] = arr[j];
                        arr[j] = temp;
                    }
                }
            }
        }


Bem, é isso para a classificação de Hill! A seguir, imprimimos para verificar a lógica inicial:

Acho que você gosta

Origin blog.csdn.net/leol_2/article/details/107982564
Recomendado
Clasificación