1. Otimização recursiva de classificação rápida
- A primeira ideia de otimização :
1. Em primeiro lugar, a classificação rápida é para uma grande quantidade de dados, como dez mil como unidade de medida, então a complexidade do tempo e a complexidade do espaço da classificação rápida são as melhores em comparação com outros tipos, então para uma pequena quantidade de dados como 10, 100, a classificação rápida obviamente não é a melhor;
2. Em seguida, a classificação rápida sempre após procurar um benchmark, de modo que os dados tendam lentamente à ordem, desta vez quando os dados entre baixo e alto são menores que um dado valor Quando, por exemplo, 100, podemos chamar entre inserir classificação para classificação;
public static void quick(int[] arr,int low,int high){
if(low > high){
return;
}
//第一个优化:当low,high之间的数据个数少于某一个范围,可以调用直接插入排序
if(high-low+1 < 100){
insertsort2(arr,low,high);
return;
}
}
//用来优化的的直接插入排序
public static void insertsort2(int[] arr,int low,int high){
for(int i = low+1;i <= high;i++) {
int tmp = arr[i];
int j = i-1;
for (;j >= low;j--){
if (arr[j] > tmp) {
arr[j+1] = arr[j];
}else{
break;
}
}
arr[j+1] = tmp;
}
}
- A segunda otimização :
1. Por exemplo, para o grupo de dados {1, 2, 3, 4, 5}, cada vez que os dados com o subscrito 0 à esquerda são tomados como referência, cada vez que a posição de referência é determinada, haverá situações extremas, e os dados estão todos na referência. Para determinar a posição do benchmark, todos pensam que é bom ter dados à esquerda e à direita do benchmark toda vez que ele é determinado, ou os casos extremos são classificados, então é óbvio que é bom quando ambos os lados estão;
2. Então, o que? A fim de garantir que haja dados em ambos os lados de cada benchmark, pegamos o mais baixo à esquerda e o mais alto à direita sempre, e o subscrito do meio meio = (alto + baixo) / 2. Esses três subscritos correspondem à mediana dos dados., que é (arr [mid] <arr [baixo] <arr [alto]), o último subscrito baixo é a mediana. Não importa qual a posição é encontrada nessas três posições, você só precisa comparar com a posição baixa do câmbio, então a baixa sempre colocará essa mediana;
public static void quick(int[] arr,int low,int high){
if(low > high){
return;
}
}
//第二次优化,取三个数中位数,这样的基准就不会出现极端情况
mid(arr,low,high);
//par是基准
int par = parttion(arr,low,high);
quick(arr,low,par-1);
quick(arr,par+1,high);
}
//优化的取三个数字的中位数
public static void mid(int[] arr,int low,int high){
/*int mid = (high+low)/2;
if (arr[low] < arr[mid] && arr[mid] < arr[high]){
int tmp = arr[low];
arr[low] = arr[mid];
arr[mid] =tmp;
System.out.println(low);
}else if(arr[high] > arr[low] && arr[high] < arr[mid]) {
int tmp = arr[high];
arr[high] = arr[low];
arr[low] =tmp;
System.out.println(low);
}else{
System.out.println(low);
return;
}*/
int mid = (low+high)/2;
//array[mid] < array[low] < array[high]
if(arr[low] >= arr[high]) {
swap(arr,low,high);
}
if(arr[low] <= arr[mid]) {
swap(arr,low,mid);
}
if(arr[mid] >= arr[high]) {
swap(arr,low,mid);
}
}
- Todo o código para ambas as otimizações
public static void quicksort(int[] arr){
quick(arr,0,arr.length-1);
}
//
public static void quick(int[] arr,int low,int high){
if(low > high){
return;
}
//第一个优化:当low,high之间的数据个数少于某一个范围,可以调用直接插入排序
if(high-low+1 < 100){
insertsort2(arr,low,high);
return;
}
//第二次优化,取三个数中位数,这样的基准就不会出现极端情况
mid(arr,low,high);
//par是基准
int par = parttion(arr,low,high);
quick(arr,low,par-1);
quick(arr,par+1,high);
}
//用来优化的的直接插入排序
public static void insertsort2(int[] arr,int low,int high){
for(int i = low+1;i <= high;i++) {
int tmp = arr[i];
int j = i-1;
for (;j >= low;j--){
if (arr[j] > tmp) {
arr[j+1] = arr[j];
}else{
break;
}
}
arr[j+1] = tmp;
}
}
//优化的取三个数字的中位数
public static void mid(int[] arr,int low,int high){
/*int mid = (high+low)/2;
if (arr[low] < arr[mid] && arr[mid] < arr[high]){
int tmp = arr[low];
arr[low] = arr[mid];
arr[mid] =tmp;
System.out.println(low);
}else if(arr[high] > arr[low] && arr[high] < arr[mid]) {
int tmp = arr[high];
arr[high] = arr[low];
arr[low] =tmp;
System.out.println(low);
}else{
System.out.println(low);
return;
}*/
int mid = (low+high)/2;
//array[mid] < array[low] < array[high]
if(arr[low] >= arr[high]) {
swap(arr,low,high);
}
if(arr[low] <= arr[mid]) {
swap(arr,low,mid);
}
if(arr[mid] >= arr[high]) {
swap(arr,low,mid);
}
}
public static void swap(int[] arr,int low,int high){
int tmp = arr[low];
arr[low] = arr[high];
arr[high] = tmp;
}
//划分函数
public static int parttion(int[] arr,int start,int end){
//申请一个tmp空间用来放基准的值(基准一般选择的是边上的值)
int tmp = arr[start];//这里取的是最左边的值,那么一会就先从最右边开始找[end]位置
while(start < end){
while(start < end && arr[end] >= tmp){
end--;
}
//到了这里,从while出来有俩种情况,不满足start < end或者不满足arr[end] >= tmp
if (start >= end){
//arr[start] = tmp;
break;//直接退出,因为已经遍历完毕
}else{
//else就是arr[end] < tmp
arr[start] = arr[end];
}
while(start < end && arr[start] <= tmp){
start++;
}
//到了这里,同样从while出来有俩种情况,不满足start < end或者不满足arr[start] <= tmp
if (start > end){
//arr[end] = tmp;
break;
}else{
arr[end] = arr[start];
}
}
arr[start] = tmp;
return start;//返回基准移动到位置,这样基准的左边全小于它,右边全都大于它
}
2. Classificação rápida não recursiva
- Idéias :
1. Use uma pilha para ajudar a obter uma classificação rápida não recursiva;
2. Para o seguinte conjunto de dados, após a posição de referência ser encontrada pela primeira vez, há um quadrado vermelho (subscrito nº 5),
3. Para recursão , a esquerda deve ser deixada? Execute a mesma determinação da posição de referência com a da direita. Em seguida, para a não recursão, colocamos o subscrito baixo (nº 0) dos dados à esquerda na pilha primeiro, alto (nº 4) na pilha e coloque o novo baixo (6) Empurre a pilha e empurre o novo alto (9) na pilha;
4. Em seguida, primeiro avalie se a pilha está vazia. Se não estiver vazio, atribua o topo da pilha como alto e o segundo como baixo, e também encontre a posição, E então empurre para a pilha, pule para fora da pilha, até que a pilha esteja vazia, então ela será organizada;
//非递归实现快速排序(需要一个栈)
public static void quicksort1(int[] arr){
Norquick(arr,0,arr.length-1);
}
//非递归实现快速排序
public static void Norquick(int[] arr,int low,int high){
Stack<Integer> stack = new Stack<>();
int par = parttion(arr,low,high);
if (par > low+1){
stack.push(low);
stack.push(par-1);
}
if (par < high-1){
stack.push(par+1);
stack.push(high);
}
while(!stack.empty()){
int end = stack.pop();
int start = stack.pop();
par = parttion(arr,start,end);
if (par > start+1){
stack.push(start);
stack.push(par-1);
}
if (par < end-1){
stack.push(par+1);
stack.push(end);
}
}
}
3. Mesclar classificação
- Conforme mostrado na figura abaixo: divida primeiro e depois mescle;
//归并排序
public static void mergesort(int[] arr){
mergeSortInternal(arr,0,arr.length-1);
}
//分割
public static void mergeSortInternal(int[] arr,int low,int high){
if(low >= high){
return;
}
int mid = (low + high)/2;
mergeSortInternal(arr,low,mid);
mergeSortInternal(arr,mid+1,high);
//分割完成,就开始合并
merge(arr,low,high,mid);
}
//合并方法
public static void merge(int[] arr,int low,int high,int mid){
int s1 = low;
int s2 = mid+1;
int[] tmp = new int[high-low+1];//临时存放合并后的数据
//开始合并
int k = 0;//tmp开始下标
while(s1 <= mid && s2 <= high){
//俩个段都有数据
if (arr[s1] <= arr[s2]){
tmp[k++] = arr[s1++];
}else{
tmp[k++] = arr[s2++];
}
}
//第一个归并段还有很多数据
while(s1 <= mid){
//第一个还有若干个数据
tmp[k++] = arr[s1++];
}
while(s2 <= high){
//第二个还有若干个数据
tmp[k++] = arr[s2++];
}
//此时就有序了
for (int i = 0;i < tmp.length;i++){
arr[low+i] = tmp[i];//将临时存放好的数据给人家放回去;
}
}