Ocho algoritmos de clasificación (lenguaje C)

contenido

1. Clasificación por inserción

1.1 Clasificación por inserción directa

1.2 Clasificación de colinas

2. Clasificación de selección

2.1 Clasificación por selección

2.2 Clasificación de montón

3. Tipo de cambio

3.1 Clasificación de burbujas

3.2 Clasificación rápida

4. Clasificación por fusión

4.1 Clasificación por fusión

5. Clasificación no comparativa

5.1 Clasificación de conteo


1. Clasificación por inserción

Idea básica: (orden ascendente predeterminado) a partir del segundo elemento de la matriz, primero use una variable para guardar el subíndice de este elemento y luego comience a comparar con el anterior, si es más pequeño que él, cambie la posición y continúe comparando con el anterior, hasta que encuentre uno Si la posición es mayor que su elemento anterior, deténgase (o deténgase al comienzo de la matriz) y luego mueva el subíndice almacenado hacia atrás para continuar la operación anterior hasta el final de la matriz

1.1 Clasificación por inserción directa

Idea básica: la clasificación por inserción directa es una implementación directa de la idea de clasificación por inserción.

Complejidad del tiempo: O(N^2)

Complejidad espacial: O(1)

Estabilidad: estable

Situación aplicable: cuanto más cerca esté la matriz de la orden, más eficiente será utilizar la ordenación por inserción directa.

Diagrama de operación:

Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>

void InsertSort(int* a,int n){//算法实现
  int i,insert,temp;
  for(i=1;i<n;i++){//从第二个元素开始向前比较
    insert=i-1;//元素要插入的位置
    temp=a[i];//记录当前元素的数值
//开始向前比较,插入位置没到数组头部或insert位置的元素大于要插入元素,一直循环.
    while(insert>=0 && temp<a[insert]){
      a[insert+1]=a[insert];//比插入元素大的直接后移
      insert--;//insert向前
    }
    a[insert+1]=temp;//找到比要插入元素小的元素的位置,直接放到其后面.
  }
}

void PrintList(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d",a[i]);
  }
  printf("\n");
}

int main(){//测试
  int a[]={3,1,6,2,7,9,8,5,4};
  InsertSort(a,sizeof(a)/sizeof(a[0]));
  PrintList(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

1.2 Clasificación de colinas

Idea básica: optimización de la clasificación por inserción directa, porque sabemos anteriormente que la clasificación por inserción directa es más eficiente en la clasificación cuando la matriz está cerca de la clasificación, por lo que tratamos de hacer que la matriz esté cerca de la clasificación, para que podamos dar un intervalo, Let all los datos con el intervalo como grupo realizan la ordenación por inserción directa y continúan la operación anterior cuando el intervalo se reduce.Cuando el intervalo es 1, la matriz ya es una matriz casi ordenada, y la eficiencia de usar la ordenación por inserción directa nuevamente será obvio mejorar

Complejidad de tiempo: entre O(N^1.25)~O(1.6*N^1.25)

Complejidad espacial: O(1)

Estabilidad: Inestable

Brecha (intervalo): Hay muchas formas de tomar el intervalo aquí. Yo uso gap=n/2 en el código, n es la longitud de la matriz, por lo que la brecha se reduce a la mitad hasta que sea 1.

Situación aplicable: cuanto más cerca esté la matriz del pedido, mayor será la eficiencia.

Diagrama de operación:

 Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>

void ShellSort(int* a,int n){//算法实现
  int i,gap=n/2;
  while(gap>0){//使用gap让数组逐渐接近有序
    i=0;
    //类似直接插入排序(将直接插入排序中的1换为gap)
    while(i+gap<n){
      int insert=i;//元素插入位置
      int temp=a[i+gap];//记录要插入元素的值
//开始向前比较,插入位置没到数组头部或insert位置的元素大于要插入元素,一直循环.
      while(insert>=0 && temp<a[insert]){
        a[insert+gap]=a[insert];//插入位置元素大于要插入的元素,插入位置的元素后移
        insert=insert-gap;//插入位置前移
      }
     a[insert+gap]=temp;//插入
     i++;
    }
    gap=gap/2;//间隔每次缩小一半
  }
}

void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d",a[i]);
  }
  printf("\n");
}

int main(){//测试
  int a[]={3,4,2,6,5,9,8,7,1};
  ShellSort(a,sizeof(a)/sizeof(a[0]));
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

2. Clasificación de selección

Idea básica: (orden ascendente predeterminado), encuentre el elemento más grande de todos los elementos de la matriz y colóquelo al final de la matriz, luego busque el segundo elemento más grande y colóquelo en la penúltima posición de la matriz, y así sucesivamente cuando se alcanza el último elemento Las matrices son simplemente matrices ordenadas en orden ascendente.

2.1 Clasificación por selección (optimización)

Idea básica: dado que cada vez que recorremos la matriz, encontramos el elemento más grande y lo colocamos al final de la matriz, entonces podemos optimizar el algoritmo. Cada vez que recorremos la matriz, no solo encontramos el valor más grande sino también el valor más pequeño, y poner el valor más grande en la matriz.Al final de la matriz, el valor más pequeño se coloca al principio de la matriz, de modo que cada vez que recorremos la matriz, se organizan dos valores, que casi se duplica la eficiencia en comparación con el algoritmo anterior.

Complejidad del tiempo: O(N^2)

Complejidad espacial: O(1)

Estabilidad: Inestable

Diagrama de operación:

 Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>

void Swap(int* a,int* b){//交换数据
  int temp=*b;
  *b=*a;
  *a=temp;
}

/*
void SelectSort(int* a,int n){//选择排序
  int i,j,max;
  for(i=0;i<n-1;i++){//查找n-1次(最后剩一个元素时不用比较)
    max=0;
    for(j=1;j<n-i;j++){//从第二个元素位置开始向n-i开始遍历寻找最大的值的下标
      if(a[max]<a[j]){
        max=j;
      }
    }
    Swap(&a[max],&a[n-1-i]);//把最大的值与最后一个元素交换
  }
}
*/

void SelectSort1(int* a,int n){//选择排序优化(降序)
  int i,j,max,min,sum=0;
  for(i=0;i<n-1;i=i+2){//每次排好两个元素进行循环
    max=sum;
    min=sum;
    for(j=sum+1;j<n-sum;j++){//从sum+1到n-sum的遍历,查找最大元素下标和最小元素下标
      if(a[max]<a[j]){
        max=j;
      }
      if(a[min]>a[j]){
        min=j;
      }
    }
    Swap(&a[max],&a[sum]);//把最大的元素放到第一位
    if(sum==min){//防止最小的元素本身就在第一位.
      Swap(&a[max],&a[n-1-sum]);
    }else{
      Swap(&a[min],&a[n-1-sum]);
    }
    sum++;
  }
}

void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d ",a[i]);
  }
  printf("\n");
}

int main(){//测试
  int a[]={3,6,5,2,9,6,8,7,1};
  SelectSort1(a,sizeof(a)/sizeof(a[0]));
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

2.2 Clasificación de montón

Idea básica: en primer lugar, debemos comprender qué es un montón. El montón se divide en un montón raíz grande y un montón raíz pequeño. El nodo principal del montón raíz pequeño siempre es más pequeño que sus nodos secundarios, por lo que podemos ajustar los datos en un montón. El nodo es el elemento más pequeño, eliminamos este nodo del montón (la forma de eliminar el montón es intercambiar el nodo raíz con el último nodo, reducir la longitud del montón en uno, y luego reajustar el montón), por lo que siempre eliminamos el montón. La operación se detiene cuando solo hay un elemento en el montón, y la matriz está en orden descendente. Usar un montón raíz grande es todo lo contrario.

Complejidad de tiempo: O(N*logN)

Complejidad espacial: O(1)

Estabilidad: Inestable

Diagrama de operación:

Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>

void Swap(int* a,int* b){//交换数据
  int temp=*b;
  *b=*a;
  *a=temp;
}

void AdjustDwon(int* a,int n,int root){//向下调整(堆调整)建立大根堆
  int parents=root;//双亲结点位置
  int child=root*2+1;//孩子结点位置
  while(child<n){//孩子结点位置不能大于数组长度
    if(child+1<n && a[child]<a[child+1]){//在右孩子存在的情况下,让child处在更大的位置
      child++;
    }
    if(a[parents]<a[child]){//如果双亲结点小于孩子结点就进行交换
      Swap(&a[parents],&a[child]);
      parents=child;//交换之后重新设置双亲结点的位置和孩子结点的位置继续进行判断
      child=parents*2+1;
    }else{
//如果双亲结点大于孩子结点就直接退出函数(要进行向下调整的条件就是该节点的左右子树已经是堆了)
      return;
    }
  }
}

void HeapSort(int* a,int n){//堆排序
  int i,j;
  for(i=(n-2)/2;i>=0;i--){//从最后一个双亲结点开始调用向下调整建立堆
    AdjustDwon(a,n,i);
  }
  for(j=n-1;j>0;j--){//使用堆删除进行堆排序
    Swap(&a[0],&a[j]);//将首尾结点数据交换
    AdjustDwon(a,j,0);//将堆的长度减一,从根开始进行向下调整,重新建立堆
  }
}

void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d ",a[i]);
  }
  printf("\n");
}

int main(){//测试
  int a[]={4,5,2,3,8,9,6,7,1};
  HeapSort(a,sizeof(a)/sizeof(a[0]));
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

3. Tipo de cambio

Idea básica: el llamado intercambio es intercambiar las posiciones de los dos registros en la secuencia de acuerdo con los resultados de la comparación de los valores clave de los dos registros en la secuencia. Los registros con valores clave más pequeños se mueven hacia el frente de la secuencia

3.1 Clasificación de burbujas

Idea básica: (orden ascendente predeterminado) establezca i=0, comience desde el i-ésimo elemento y compare el valor de su elemento adyacente i+1, si el valor de i es grande, cámbielo, de lo contrario no lo intercambie, entonces i + 1, repita la operación anterior hasta que i vaya a la posición de n - 1. Esto coloca el elemento más grande en la última posición, y luego repite la operación anterior, y el ya ordenado no necesita compararse, hasta que solo haya queda un elemento en la matriz Detener cuando la matriz es una matriz ordenada ascendente.

Complejidad del tiempo: O(N^2)

Complejidad espacial: O(1)

Estabilidad: estable

Diagrama de operación:

Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>

void Swap(int* a,int* b){//交换数据
  int temp=*b;
  *b=*a;
  *a=temp;
}

void BubbleSort(int* a,int n){//冒泡排序
  int i,j,length=n-1;
  for (i=0;i<length;i++){//n个元素总共排序n-1个元素
    int flag=0;
//标志位用来标识一趟循环中是否有数据的交换,如果没有数据的交换说明数组已经为有序数组直接退出函 
//数即可
    for(j=0;j<length-i;j++){//进行一趟循环,每排序好一个元素此循环少进行一次
      if(a[j] < a[j+1]){//(降序)第j个元素与第j+1个元素比较如果比其小就进行交换,并将flag变1
        Swap(&a[j],&a[j+1]);
        flag=1;
      }
    }
    if(0==flag){//没有进行数据交换则说明数组有序,直接退出函数
      break;
    }
  }
}

void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d ",a[i]);
  }
  printf("\n");
}

int main(){//测试
  int a[]={4,3,2,7,9,8,6,5,1};
  BubbleSort(a,sizeof(a)/sizeof(a[0]));
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

3.2 Clasificación rápida

Idea básica: (orden ascendente predeterminado) tome un número de la matriz como el número estándar, luego recorra la matriz, coloque el número más grande que el número estándar detrás de él y coloque el número más pequeño que él delante. En este momento , el número estándar está ubicado La posición de es su posición en la matriz ordenada, y luego use la recursividad para realizar esta operación en los datos de la izquierda y la derecha. Deténgase cuando el subíndice del elemento de la izquierda sea mayor o igual que el subíndice del elemento derecho, y la matriz es una matriz ordenada ascendente.

Extensiones y optimizaciones para quicksort:

a.para optimizar

El medio de tres números: cuando tomamos el número estándar, cuanto más central es el número, menor es la complejidad temporal del algoritmo y cuanto más cerca de O(N*logN) mayor es la eficiencia. Cuanto más extremo es el número que tomamos , cuanto más cerca esté del valor máximo o mínimo. Cuanto mayor sea la complejidad del tiempo, más cerca de O(N^2), menor será la eficiencia. Por lo tanto, el número estándar obtenido mediante el método de los tres números está más centrado. El valor específico La operación es tomar tres números de tres posiciones al principio y al final de la matriz, y luego usar El número del medio entre estos tres números es el número estándar.

B. Expansión (tres métodos de clasificación rápida)

Método Hoare: primero seleccione el número estándar, luego defina dos punteros (anterior (frente), posterior (trasero)), uno de adelante hacia atrás, uno de atrás hacia adelante, use prev para encontrar un número mayor que el número estándar, use trasero Encuentre un número más pequeño que el número estándar, y luego intercambie los dos números hasta que el anterior y el posterior vayan a la misma posición para salir del ciclo, y luego intercambie el número estándar con aquí.

Método de excavación: primero seleccione el número estándar, coloque el número escalar al final de la matriz y luego regístrelo en temperatura, luego defina anterior (frontal), posterior (posterior), anterior vaya primero para encontrar el número más grande que el número estándar y colóquelo directamente al final de la matriz, luego Rear continúa caminando para encontrar una posición más pequeña que el número estándar y colóquelo directamente en anterior, y continúe repitiendo la operación anterior hasta que anterior y posterior se unan para salir del bucle, y pon el número en temp aquí.

Método de puntero delantero y trasero: primero seleccione el número estándar, coloque el número estándar en la cabeza de la matriz y luego defina el puntero delantero y trasero anterior en la cabeza, cur = anterior + 1, los dos punteros retroceden juntos, cur encuentra un número más pequeño que el número estándar, y prev encuentra la proporción Si el número estándar es grande, se encuentra e intercambia. Cuando cur llega al final, se sale del ciclo. Porque la posición de prev es siempre el último dígito del número más pequeño que el número estándar, el número estándar y la posición anterior se intercambian, y el número estándar se puede colocar en el medio.

característica:

Complejidad de tiempo: O(N*logN)

Complejidad espacial: O(logN)

Estabilidad: Inestable

Situación aplicable: cuanto más desordenados y caóticos sean los elementos de la matriz, mayor será la eficiencia de clasificación.

Diagrama de operación:

hoare:

Ver imagen de origen

Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>

void Swap(int* a,int* b){
  int temp=*b;
  *b=*a;
  *a=temp;
}

//取中间数
int MidNum(int* a,int b,int c,int d){
  int n_1=a[b],n_2=a[c],n_3=a[d];
  int temp[3]={n_1,n_2,n_3};
  if(temp[0]>temp[1]){
    Swap(&temp[0],&temp[1]);
  }
  if(temp[1]>temp[2]){
    Swap(&temp[1],&temp[2]);
  }
  if(temp[0]>temp[1]){
    Swap(&temp[0],&temp[1]);
  }
  if(temp[1]==a[b]){
    return b;
  }
  if(temp[1]==a[c]){
    return c;
  }
  return d;
}

//hoare
int PartSort1(int* a,int left,int right){//降序
  int i=left,j=right,mid=MidNum(a,left,(left+right)/2,right);//三数取中
  Swap(&a[right],&a[mid]);//将标准数放到末尾
  int temp=a[right];//记录标准数
  while(i<j){
    while(i<j && a[i]>=temp){//找比标准数小的
      i++;
    }
    while(i<j && a[j]<=temp){//找比标准数大的
      j--;
    }
    Swap(&a[i],&a[j]);//交换
  }
  Swap(&a[i],&a[right]);//将标准数放到中间
  return i;
}

//挖坑法
int PartSort2(int* a,int left,int right){
  int i=left,j=right,mid=MidNum(a,left,(left+right)/2,right);//三数取中
  Swap(&a[mid],&a[right]);//将标准数放到末尾
  int temp=a[right];//记录标准数
  while(i<j){
    while(i<j && a[i]<=temp){//找比标准数大的数
      i++;
    }
    if(i<j){//将其放到j的位置
      a[j]=a[i];
      j--;
    }
    while(i<j && a[j]>=temp){//找比标准数小的数
      j--;
    }
    if(i<j){//将其放到i的位置
      a[i]=a[j];
      i++;
    }
  }
  a[i]=temp;//将标准数的值放到中间
  return i;
}

//前后指针法
int PartSort3(int* a,int left,int right){
  int cur,prev,mid=MidNum(a,left,(left+right)/2,right);//三数取中
  Swap(&a[left],&a[mid]);//将标准数放到首部
  prev=left;//定义前后指针
  cur=prev+1;
  while(cur<=right){
    if(a[cur]<a[left] && ++prev!=cur){//cur找比标准数小的,prev找比标准数大的然后交换
      Swap(&a[cur],&a[prev]);
    }
    cur++;
  }
  Swap(&a[left],&a[prev]);//prev所在的位置永远在小于标准数的最后一位,将标准数与其交换放在中间
  return prev;
}

void QuickSort(int* a,int left,int right){//递归调用
  if(left<right){//当left小于right时一直进行调用
    int mid=PartSort3(a,left,right);//找到标准数所在的位置
    QuickSort(a,left,mid-1);//对标准数的左侧进行调用
    QuickSort(a,mid+1,right);//对标准数的右侧进行调用
  }
}

void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d ",a[i]);
  }
  printf("\n");
}

int main(){测试
  int a[]={3,4,2,7,5,6,9,8,1};
  QuickSort(a,0,sizeof(a)/sizeof(a[0])-1);
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

4. Clasificación por fusión

4.1 Clasificación por fusión

Idea básica: (orden ascendente predeterminado) Primero, use la recursividad para descomponer los elementos en la matriz. Cuando los elementos se descomponen en un solo dato, se fusionan fusionando matrices ordenadas. (El núcleo del algoritmo es fusionar dos matrices ordenadas ), defina tres punteros para apuntar respectivamente a la cabeza de dos matrices ordenadas y la cabeza de una nueva matriz (defina una nueva matriz para almacenar datos ordenados), compare los valores de los punteros de las dos matrices ordenadas y coloque el más pequeño uno en el El puntero pequeño en la nueva matriz se mueve hacia atrás, y el puntero de la nueva matriz también se mueve hacia atrás, hasta que una de las dos matrices ordenadas llega al final para finalizar el ciclo, y todos los datos restantes en la matriz ordenada que no ha llegado al final se coloca en Después de la nueva matriz, la nueva matriz es una matriz ordenada ascendente.

Complejidad de tiempo: O(N*logN)

Complejidad espacial: O(N)

Estabilidad: estable

Ámbito de aplicación: el pensamiento de la ordenación por combinación es más para resolver el problema de la clasificación externa en el disco.

Diagrama de operación:

Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//合并两个有序数组(降序)
void MergeOrderArray(int* new_a,int* a,int begin_1,int end_1,int begin_2,int end_2){
  int i=begin_1,j=begin_2,k=begin_1;//定义三个指针
  while(i<=end_1 && j<=end_2){//对两个有序数组进行合并,当其中一个走到末尾时结束循环
    if(a[i] >= a[j]){//比较两个有序数组中的元素,大的那个数放到新的数组中,同时两个指针后移
      new_a[k++]=a[i++];
    }else{
      new_a[k++]=a[j++];
    }
  }
  while(i<=end_1){//如果是以i遍历的数组没有走到末尾,则将其后面的元素全加到新数组的后面
    new_a[k++]=a[i++];
  }
  while(j<=end_2){//如果是以j遍历的数组没有走到末尾,则将其后面的元素全加到新数组的后面
    new_a[k++]=a[j++];
  }
}

void _MergeSort(int* new_a,int* a,int i,int j){//递归调用(类似于二叉树的后序遍历)
  if(i<j){//对数组进行递归分解当i等于j时停止
    int mid=i+((j-i)>>1);//找中间数值
    _MergeSort(new_a,a,i,mid);//分解左边
    _MergeSort(new_a,a,mid+1,j);//分解右边
    MergeOrderArray(new_a,a,i,mid,mid+1,j);//调用合并算法对有序的数组进行合并
    memcpy(a+i,new_a+i,sizeof(int)*(j-i+1));//将合并好的有序数组复制回原数组中
  }
}

void MergeSort(int* a,int n){//归并排序的外部调整
  int* new_a=(int*)malloc(sizeof(int)*n);//创建新数组用来存储有序元素
  if(NULL==new_a){
    return;
  }
  _MergeSort(new_a,a,0,n-1);//递归调用
  free(new_a);
}

void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d ",a[i]);
  }
  printf("\n");
}

int main(){//测试
  int a[]={3,4,5,2,1,9,8,7,6};
  MergeSort(a,sizeof(a)/sizeof(a[0]));
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

5. Clasificación no comparativa

5.1 Clasificación de conteo

Idea básica: (orden ascendente predeterminado) Encuentre los elementos más pequeños y más grandes de un conjunto de datos, cree una nueva matriz (inicializada en 0) con la diferencia como límite y luego use el valor de los elementos en la matriz para ordenar El subíndice de la nueva matriz, recorrer la matriz que se va a ordenar, agregar uno al contenido de la matriz con los datos como subíndice en la nueva matriz cada vez que se recorren los datos y contar la cantidad de veces que cada elemento de la matriz para ser ordenado aparece, y finalmente complete estos tiempos para ser ordenados En la matriz, en este momento la matriz es una matriz ordenada en orden ascendente.

Complejidad del tiempo: O(max(N,max-min+1))

Complejidad espacial: O(max-min+1)

Estabilidad: estable

Uso: Aplicable cuando los elementos están particularmente concentrados.

Diagrama de operación:

Código: (puedes copiar la prueba directamente)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void CountSort(int* a,int n){//计数排序(降序)
  int max=a[0],min=a[0];
  int i;
  for(i=0;i<n;i++){//获取最大值和最小值
    if(a[i]>max){
      max=a[i];
    }
    if(a[i]<min){
      min=a[i];
    }
  }
  int length=max-min+1;
  int* temp=(int*)calloc(length,sizeof(int));//以max-min+1为界限创建新数组
  for(i=0;i<n;i++){//统计要排序数组中各个元素出现的次数
    temp[a[i]-min]++;
  }
  int k=0;
  for(i=length-1;i>=0;i--){//将统计好的数据依次按顺序填入要排序的数组
    while(temp[i]!=0){
      a[k++]=i+min;
      temp[i]--;
    }
  }
  free(temp);
}

void PrintArray(int* a,int n){//打印数组
  int i;
  for(i=0;i<n;i++){
    printf("%d ",a[i]);
  }
  printf("\n");
}

int main(){//测试
  int a[]={2,3,4,5,6,7,8,2,3,3,2,5,4,7,6,9,8,1};
  CountSort(a,sizeof(a)/sizeof(a[0]));
  PrintArray(a,sizeof(a)/sizeof(a[0]));
  return 0;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_49312527/article/details/123031374
Recomendado
Clasificación