1. Método de pesquisa binária
- Pré-requisito: uma matriz classificada é necessária
- Defina o limite esquerdo L e o limite direito R, confirme o intervalo de pesquisa e execute a pesquisa binária em um loop (3, 4)
- Obtenha o índice do meio M = Floor((L+R)/2)
- O valor A[M] do valor do índice intermediário é comparado com o valor T a ser pesquisado,
- A[M] == T significa encontrado, retorne o índice intermediário
- A[M]>T, outros elementos no lado direito do valor do meio são maiores que T (o valor pesquisado), não há necessidade de comparar, defina o índice do meio M-1 como o limite direito e pesquise novamente;
- A[M]>T, outros elementos à esquerda do valor do meio são menores que T (o valor pesquisado), não há necessidade de comparar, defina o índice do meio M-1 para o limite direito e pesquise novamente;
Ao usar a pesquisa binária, o número binário ímpar é o valor do meio,
Divida um número par em dois e pegue o valor do meio à esquerda
/**
*二分查找
*@parama查找数组
*@paramt查找的值
*@return
*/
private static int binarySearch1(int[] a,int t) {
// l:左边索引,r右边索引,中间索引
int l = 0 ,r=a.length -1,m;
int i=1;
while (l<=r){
m=(l+r)>>>1;
System.out.println("第"+i+"轮:左边下标--"+l+",右边下标--"+r+",中间下标--"+m+"中间下标的值--"+a[m]);
if (a[m] == t){
return m; //表示查找到了
}else if (a[m] >t){
r=m-1; //把右边界设置为中间索引-1
}else {
l=m+1; //把左边界设置为中间索引+1
}
i++;
}
return -1;
}
2. Classificação por bolha
-
conceito:
- Cada vez que dois números adjacentes são comparados, se a[j]>a[j+1] for um elemento, os dois elementos são trocados e ambos são comparados novamente, o que é chamado de rodada de borbulhamento. O resultado é deixar o maior linha do elemento à direita
- Repita as etapas acima até que todo o array esteja classificado
-
Método de otimização:
- Durante cada rodada de borbulhamento, o último índice de troca pode ser usado como o número de comparações para a próxima rodada de borbulhamento.Se este valor for 0, significa que toda a matriz está em ordem e o loop externo é encerrado diretamente.
-
Opção um:
/** *冒泡排序 *@parama */ public static void bubble(int[] a){ // 循环次数 for (int j = 0; j < a.length-1; j++) { boolean swapped = false; // 比较次数 // 因为每次都会有一位排好序的数,所有比较次数可以设置为每次都比上一次少1,以此减少比较次数 for (int i = 0; i < a.length-1-j; i++) { System.out.println("比较次数:"+i); // 每一次交换,把swapped改为true if (a[i] > a[i+1]){ swap(a,i,i+1); swapped = true; } } System.out.println("第"+j+"轮,循环"+Arrays.toString(a)); // 没产生交换时退出循环 if (!swapped){ break; } } }
-
Opção II:
/** *冒泡排序 *@parama */ public static void bubble(int[] a){ // 每一轮交换次数 int n = a.length-1; // 循环次数 while (true){ boolean swapped = false; int last = 0; //表示最后异常交换的下标 // 比较次数 // 因为每次都会有一位排好序的数,所有比较次数可以设置为每次都比上一次少1,以此减少比较次数 for (int i = 0; i < n; i++) { System.out.println("比较次数:"+i); if (a[i] > a[i+1]){ swap(a,i,i+1); last = i; //每一轮比较的交换次数 } } n = last; //把最后一轮比较的下标赋给n System.out.println("第n轮,循环"+Arrays.toString(a)); // 当最后一轮比较的下标是0时,代表比较完毕,没有产生交换,退出循环 if (n == 0){ break; } } }
3. Classificação de seleção
-
Visão geral:
- Divida a matriz em dois subconjuntos, classificados e não classificados. Em cada rodada, selecione o menor elemento do subconjunto não classificado e coloque-o no subconjunto classificado.
- Repita as etapas acima até que todo o array esteja classificado
-
Comparar com classificação por bolha
- A complexidade média de ambos é O (n 2) O(n^2)Ó ( n2 )
- A classificação por seleção é geralmente mais rápida do que a classificação por bolha porque requer menos trocas.
- Mas se o conjunto for altamente ordenado, o borbulhamento é melhor que a seleção, porque durante a comparação de bolhas, você pode registrar se há uma troca para determinar se o conjunto está ordenado, mas a classificação por seleção não pode
- A bolha é uma classificação estável e não haverá troca quando os valores forem iguais, enquanto a seleção é uma classificação instável.
4. Classificação rápida
-
Visão geral
- Cada rodada de classificação seleciona um ponto de referência para particionamento
- Deixe que os elementos menores que o ponto de referência entrem em uma partição e os elementos maiores que o ponto de referência entrem em outra partição.
- Quando o particionamento estiver concluído, a posição do elemento do ponto base será sua posição final
- Repita o processo acima na subpartição até que o número de elementos na subpartição seja menor ou igual a 1, o que significa que a classificação está concluída. Isso reflete principalmente a ideia de dividir para governar
- Cada rodada de classificação seleciona um ponto de referência para particionamento
-
Classificação:
- Classificação rápida cíclica unilateral
- Selecione o elemento mais à direita como o elemento do ponto base
- O ponteiro j é responsável por encontrar o elemento menor que o ponto de referência. Uma vez encontrado, ele é trocado por i
- O ponteiro i mantém o limite dos elementos menores que o ponto de referência e também é o índice alvo de cada troca
- Finalmente, o ponto de referência é trocado por i, que é a posição da partição.
- Classificação rápida de circulação bilateral
- Selecione o elemento mais à esquerda como o elemento do ponto base
- O ponteiro j é responsável por encontrar elementos menores que o ponto de referência da direita para a esquerda, e o ponteiro i é responsável por encontrar elementos maiores que o ponto de referência da esquerda para a direita. Uma vez encontrados os dois, eles são trocados até i e j cruzar.
- Finalmente, o ponto de referência é trocado por i (i e j são iguais neste momento), e i é a posição da partição.
- Pontos principais
- O ponto de referência está à esquerda e deve ser j primeiro e depois i
- while( i < j && a[j] > pv ) j-- // i < j deve ser adicionado
- while ( i < j && a[i] <= pv ) i++ //必须加≤
- Classificação rápida cíclica unilateral
1. Implementação de código de classificação rápida unilateral
public static void quick(int[] a,int l,int h){
if (l>=h){
return;
}
// p:索引值 ,用于做子分区的左右边界
int p =partition(a, l, h);
quick(a, l,p-1); // 左边分区的范围确认
quick(a, p+1,h); // 右边分区的范围确认
}
/**
*@Description//TODO单边快排
*@param:a数组
*@param:l左边界
*@param:h右边界
*@return:int表示基准点元素所在的正确索引,用它确认下一轮分区的边界
**/
private static int partition(int[] a,int l,int h){
int pv = a[h]; // 基准点的值
int i = l;
for (int j = l;j < h; j++){
if(a[j] < pv){
if (i != j){
//当i和j指向的是同一个元素时,代表没必要交换,
swap(a,i,j);
}
i++;
}
}
if (i != h){
swap(a,h,i);
}
System.out.println("比较后的值:"+Arrays.toString(a)+" 基准点下标="+i);
return i;
}
2. Implementação de código de triagem rápida bilateral
public static void quick(int[] a,int l,int h){
if (l>=h){
return;
}
// p:索引值 ,用于做子分区的左右边界
int p =partition(a, l, h);
quick(a, l,p-1); // 左边分区的范围确认
quick(a, p+1,h); // 右边分区的范围确认
}
/**
*@Description//TODO双边快排
*@param:a数组
*@param:l左边界
*@param:h右边界
*@return:int表示基准点元素所在的正确索引,用它确认下一轮分区的边界
**/
private static int partition(int[] a,int l,int h){
int pv = a[l];
int i = l;
int j = h;
while (i < j){
// 寻找的顺序也不能更改,必须先执行j从右向左,再执行i从左向右寻找
// j从右向左找小的 ,必须加i < j 条件,因为不加会出现i走过头,跑到比j大的位置取拿取元素
while (i < j && a[j] > pv){
j--;
}
// i从左向右找大的 ,a[i] <= pv必须加等于,因为a[i]最开始是从左边界开始,就是等于pv
while (i < j && a[i] <= pv){
i++;
}
swap(a,i,j);
}
// 基准点和j交换位置,j代表分区位置
swap(a,l,j);
System.out.println(Arrays.toString(a)+" j="+j);
return j;
}
```