85 votes

Question d'entretien : Fusionner deux listes chaînées triées sans créer de nouveaux noeuds

Il s'agit d'une question de programmation posée lors d'un test écrit pour un entretien. "Vous avez deux listes singulièrement liées qui sont déjà triées, vous devez les fusionner et renvoyer la tête de la nouvelle liste sans créer de nouveaux nœuds supplémentaires. La liste retournée doit également être triée.

La méthode signat Node MergeLists(Node list1, Node list2) ;

La classe de nœuds est indiquée ci-dessous :

class Node{
    int data;
    Node next;
}

J'ai essayé de nombreuses solutions, mais le fait de ne pas créer de nœud supplémentaire ne fait que compliquer les choses. Merci de m'aider.

Voici l'article de blog qui l'accompagne http://techieme.in/merging-two-sorted-singly-linked-list/

0 votes

Le dernier élément de la liste 1 est-il plus petit que le premier élément de la liste 2 ?

0 votes

Remarque : j'ai également trouvé une solution sur stackoverflow.com/questions/2348374/fusion de deux listes triées mais celui-ci, lorsqu'il est exécuté, s'inscrit dans une boucle infinie.

0 votes

@Pier : Il peut s'agir de n'importe quoi. Les deux listes sont triées individuellement et le code doit produire une troisième liste qui est triée.

191voto

Stefan Haustein Points 4458
Node MergeLists(Node list1, Node list2) {
  if (list1 == null) return list2;
  if (list2 == null) return list1;

  if (list1.data < list2.data) {
    list1.next = MergeLists(list1.next, list2);
    return list1;
  } else {
    list2.next = MergeLists(list2.next, list1);
    return list2;
  }
}

117 votes

La récursivité sur des listes arbitrairement longues est une recette pour un débordement de pile. Mais je suppose qu'il s'agit de Stack Overflow. Oh, l'ironie ! ;-)

0 votes

Des solutions fraîches et croustillantes ! J'ai adapté ce code à Java en utilisant les génériques. Code hébergé ici avec explication git.io/-DkBuA Cas de test inclus dans le même référentiel.

0 votes

@StefanHaustein Quel est le type de retour de cette fonction qui est void ? Comment dois-je la modifier ?

115voto

Stefan Haustein Points 4458

La récursivité ne devrait pas être nécessaire pour éviter l'allocation d'un nouveau nœud :

Node MergeLists(Node list1, Node list2) {
  if (list1 == null) return list2;
  if (list2 == null) return list1;

  Node head;
  if (list1.data < list2.data) {
    head = list1;
  } else {
    head = list2;
    list2 = list1;
    list1 = head;
  }
  while(list1.next != null) {
    if (list1.next.data > list2.data) {
      Node tmp = list1.next;
      list1.next = list2;
      list2 = tmp;
    }
    list1 = list1.next;
  } 
  list1.next = list2;
  return head;
}

5 votes

Lors d'un entretien, il est généralement préférable de commencer par la solution la plus propre, la plus courte et la plus élégante qui réponde aux critères, puis de l'améliorer, en particulier s'il y a un risque de manquer de temps.

1 votes

@SonDo C'est la prérogative de l'OP de choisir la réponse acceptée. Et il n'y a rien de mal à la réponse qui a été choisie. Si vous estimez que cette réponse devrait être acceptée, vous pouvez voter pour elle.

0 votes

Quel est l'intérêt de faire head = list2 ; list2 = list1 ; list1 = head ; ne peut-on pas simplement assigner head = list2 ;

12voto

Ben Points 31
Node MergeLists(Node node1, Node node2)
{
   if(node1 == null)
      return node2;
   else (node2 == null)
      return node1;

   Node head;
   if(node1.data < node2.data)
   {
      head = node1;
      node1 = node1.next;
   else
   {
      head = node2;
      node2 = node2.next;
   }

   Node current = head;
   while((node1 != null) ||( node2 != null))
   {
      if (node1 == null) {
         current.next = node2;
         return head;
      }
      else if (node2 == null) {
         current.next = node1;
         return head;
      }

      if (node1.data < node2.data)
      {
          current.next = node1;
          current = current.next;

          node1 = node1.next;
      }
      else
      {
          current.next = node2;
          current = current.next;

          node2 = node2.next;
      }
   }
   current.next = NULL // needed to complete the tail of the merged list
   return head;

}

1 votes

La boucle while doit être exécutée à la condition "ou".

5voto

wildplasser Points 17900

Regardez maman, pas de récursivité !

struct llist * llist_merge(struct llist *one, struct llist *two, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *result, **tail;

for (result=NULL, tail = &result; one && two; tail = &(*tail)->next ) {
        if (cmp(one,two) <=0) { *tail = one; one=one->next; }
        else { *tail = two; two=two->next; }
        }
*tail = one ? one: two;
return result;
}

4voto

Jaguar Points 8451

Voici l'algorithme permettant de fusionner deux listes chaînées triées A et B :

while A not empty or B not empty:
   if first element of A < first element of B:
      remove first element from A
      insert element into C
   end if
   else:
      remove first element from B
      insert element into C
end while

Ici, C sera la liste de sortie.

6 votes

Ceci n'est possible que si vous créez un nouveau nœud. La question limite la création de nouveaux nœuds.

1 votes

Vous devez vérifier null car il se peut que A ou B soit vide. Une autre façon de procéder est de boucler jusqu'à ce que A ne soit pas vide et que B ne soit pas vide.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X