Algorithmes de tri

Tri par sélection

Complexité : \( C_n = \mathcal{O}(n^2) \) où \( n \) désigne la taille de l

let rec extrait_minimum l = match l with
  | [] -> failwith "Pas de minimum"
  | [a] -> (a, [])
  | p::q -> let (min_q, reste_q) = extrait_minimum q in
    if p < min_q then (p, min_q::reste_q) else (min_q, p::reste_q)

let rec tri_selection l = match l with
  | [] -> []
  | [a] -> [a]
  | _ -> let min, reste = extrait_minimum l in
    min::(tri_selection reste)

void tri_selection(int tab[], int taille_tab) {
  for (int i = 0; i < taille_tab; i += 1) {
    int imin = i;
    for (int j = i; j < taille_tab; j += 1) {
      if (tab[j] < tab[imin]) {
        imin = j;
      }
    }
    int tmp = tab[i];
    tab[i] = tab[imin];
    tab[imin] = tmp;
  }
}

Tri à bulles

Complexité : \( C_n = \mathcal{O}(n^2) \) où \( n \) désigne la taille de l

let rec un_tour l = match l with
  | [] -> []
  | [p] -> [p]
  | p1::p2::q -> if p1 < p2 then p1::(un_tour p2::q) else p2::(un_tour p1::q)

let rec tri_a_bulle l = let apres_un_tour = un_tour l in if l = apres_un_tour then l else tri_bulles apres_un_tour
void tri_a_bulles(int tab[], int taille_tab){
  for (int i = 0; i < taille_tab; i += 1){
    for (int j = 0; j < taille_tab - i - 1; j += 1){
      if (tab[j + 1] < tab[j]){
        int tmp = tab[j];
        tab[j] = tab[j + 1];
        tab[j + 1] = tmp;
      }
    }
  }
}

Tri par insertion

Complexité : \( C_n = \mathcal{O}(n^2) \) où \( n \) désigne la taille de l

let rec insere l e = match l with
  | [] -> [e]
  | p::q -> if e < p then e::p::q else p::(insere q e)

let tri_insertion l = match l with
  | [] -> []
  | p::q -> insere (tri_insertion q) p
void tri_insertion(int tab[], int taille_tab){
    for (int i = 0; i < taille_tab; i += 1){
        int j = i;
        while (j > 0 && tab[j] < tab[j - 1]){
            int temp = tab[j];
            tab[j] = tab[j - 1];
            tab[j - 1] = temp;
            j -= 1;
        }
    }
}

Tri fusion

Complexité : \( C_n = \mathcal{O}(n\log(n)) \) où \( n \) désigne la taille de l

Sur des listes

let diviser l =
  let rec aux l l1 l2 = match l with
    | [] -> (l1, l2)
    | h::[] -> (h::l1, l2)
    | h1::h2::q -> aux q (h1::l1) (h2::l2)
  in
  aux l [] []

let rec fusion l1 l2 = match l1, l2 with
  | [], [] -> failwith "PAS POSSIBLE"
  | [], a | a, [] -> a
  | h1::q1, h2::q2 ->
    if h1 < h2 then h1::(fusion q1 (h2::q2))
    else h2::(fusion (h1::q1) q2)

let rec tri_fusion l = match l with
  | [] | [_] -> l
  | _ ->
    let tri1, tri2 = diviser l in
    fusion (tri_fusion tri1) (tri_fusion tri2)
void divise(liste l, liste* pairs, liste* impairs){
    if (!est_vide(l)){
        ajoute(tete(l), pairs);
        if (!est_vide(queue(l))){
            ajoute(tete(queue(l)), impairs);
            divise(queue(queue(l)), pairs, impairs);
        }
    }
}

liste fusion(liste l1, liste l2){
    if (est_vide(l1)){
        return copie(l2);
    }
    else if (est_vide(l2)){
        return copie(l1);
    }
    else{
        liste res;
        if (tete(l1) < tete(l2)){
            res = fusion(queue(l1), l2);
            ajoute(tete(l1), &res);
        }
        else{
            res = fusion(l1, queue(l2));
            ajoute(tete(l2), &res);
        }
        return res;
    }
}

liste tri_fusion(liste l){
    if (est_vide(l) || est_vide(queue(l))){
        return copie(l);
    }
    else{
        liste temp1 = creer ();
        liste temp2 = creer ();
        divise(l, &temp1, &temp2);
        liste tri1 = tri_fusion(temp1);
        liste tri2 = tri_fusion(temp2);
        liste res = fusion(tri1, tri2);
        detruire(temp1);
        detruire(temp2);
        detruire(tri1);
        detruire(tri2);
        return res;
    }
}

Sur des tableaux

let sous_tableau a i j =
  let res = Array.make (j - i + 1) a.(0) in
  for k = i to j do
    res.(k - i) <- a.(k)
  done;
  res

let fusion_tableaux a1 a2 =
  let s1 = Array.length a1 in
  let s2 = Array.length a2 in
  let res = Array.make (s1 + s2) a1.(0) in
  let i = ref 0 in
  let j = ref 0 in
  for k = 0 to s1 + s2 - 1 do
    if !j >= s2 || (!i < s1 && a1.(!i) < a2.(!j)) then 
      begin 
      res.(k) <- a1.(!i);
      incr i;
      end
    else
      begin
      res.(k) <- a2.(!j);
      incr j
      end
  done;
  res

let rec tri_fusion_tableaux a =
  let s = Array.length a in
  if s = 0 || s = 1 then a
  else
    let tri1 = sous_tableau a 0 (s/2 - 1) in
    let tri2 = sous_tableau a (s/2) (s - 1) in
    fusion_tableaux (tri_fusion_tableaux tri1) (tri_fusion_tableaux tri2)
int* sous_tableau(int a[], int i, int j){
    int* res = malloc((j - i + 1) * sizeof(int));
    for (int k = i; k < j + 1; k += 1){
        res[k - i] = a[k];
    }
    return res;
} 

int* fusion_tableaux(int a1[], int a2[], int s1, int s2){
    int* res = malloc((s1 + s2) * sizeof(int));
    int i = 0;
    int j = 0;
    for (int k = 0; k < s1 + s2; k += 1){
        if (j >= s2 || (i < s1 && a1[i] < a2[j])){
            res[k] = a1[i];
            i += 1;
        }
        else{
            res[k] = a2[j];
            j += 1;
        }
    }
    return res;
}

int* tri_fusion_tableaux(int a[], int s){
    if (s == 0){
        return NULL;
    }
    else if (s == 1){
        int* res = malloc(sizeof(int));
        res[0] = a[0];
        return res;
    }
    else {
        int* temp1 = sous_tableau(a, 0, s/2 - 1);
        int* temp2 = sous_tableau(a, s/2, s - 1);
        int* tri1 = tri_fusion_tableaux(temp1, s/2);
        int* tri2 = tri_fusion_tableaux (temp2, s - s/2);
        int* res = fusion_tableaux(tri1, tri2, s/2, s - s/2);
        free(temp1);
        free(temp2);
        free(tri1);
        free(tri2);
        return res;
    }
}

Tri rapide

Complexité : \( C_n = \mathcal{O}(n^2) \) mais \( \Theta(n\log(n))\) où \( n \) désigne la taille de l

Sur des listes

let partition l p =
  let rec aux l l1 l2 = match l with
    | [] -> (l1, l2)
    | h::t ->
      if h < p then aux t (h::l1) l2
      else aux t l1 (h::l2)
  in
  aux l [] []

let rec tri_rapide l = match l with
  | [] -> []
  | h::t ->
    let tri1, tri2 = partition t h in
    (tri_rapide tri1)@(h::(tri_rapide tri2))
void partition(liste l, int pivot, liste* inf, liste* sup){
    if (!est_vide(l)){
        if (tete(l) < pivot){
            ajoute(tete(l), inf);
        }
        else{
            ajoute(tete(l), sup);
        }
        partition(queue(l), pivot, inf, sup);
    }
}

liste tri_rapide(liste l){
    if (est_vide(l)){
        return creer();
    }
    else{
        liste temp1 = creer ();
        liste temp2 = creer ();
        partition(queue(l), tete(l), &temp1, &temp2);
        liste tri1 = tri_rapide(temp1);
        liste tri2 = tri_rapide(temp2);
        ajoute(tete(l), &tri2);
        liste res = concat(tri1, tri2);
        detruire(temp1);
        detruire(temp2);
        detruire(tri1);
        detruire(tri2);
        return res;
        
    }
}

Sur des tableaux

let partition a deb fin =
  let k = ref deb in
  let pivot = a.(fin) in
  for i = deb to fin - 1 do
    if a.(i) < pivot then
      begin
      let temp = a.(i) in
      a.(i) <- a.(!k);
      a.(!k) <- temp;
      incr k
      end
  done;
  let temp = a.(fin) in
  a.(fin) <- a.(!k);
  a.(!k) <- temp;
  !k

let rec tri_rapide_aux a deb fin = 
  let k = partition a deb fin in
  if k > deb then tri_rapide_aux a deb (k-1);
  if k < fin then tri_rapide_aux a (k+1) fin

let tri_rapide a = tri_rapide_aux a 0 (Array.length a - 1)
int partition_lomuto(int t[], int debut, int fin){
    int k = debut;
    int pivot = t[fin];
    for (int i = debut; i < fin; i += 1){
        if (t[i] < pivot){
            int temp = t[i];
            t[i] = t[k];
            t[k] = temp;
            k += 1;
        }
    }
    int temp = t[fin];
    t[fin] = t[k];
    t[k] = temp;
    return k;
}

void tri_rapide_aux(int tab[], int debut, int fin){
    int k = partition_lomuto(tab, debut, fin);
    if (k > debut){
        tri_rapide_aux(tab, debut, k-1);
    }
    if (k < fin){
        tri_rapide_aux(tab, k+1, fin);
    }
}

void tri_rapide(int tab[], int taille_tab){
    tri_rapide_aux(tab, 0, taille_tab - 1);
}