Pouvez-vous penser à une raison spécifique pour laquelle la suppression est généralement beaucoup plus difficile à mettre en œuvre que l'insertion pour de nombreuses (la plupart?) Structures de données?
Exemple rapide: listes liées. L'insertion est triviale, mais la suppression comporte quelques cas spéciaux qui la rendent considérablement plus difficile. Les arbres de recherche binaires à équilibrage automatique tels que AVL et Rouge-noir sont des exemples classiques d'implémentation de suppression douloureuse.
Je voudrais dire que cela a à voir avec la façon dont la plupart des gens pensent: il est plus facile pour nous de définir les choses de manière constructive, ce qui conduit bien à des insertions faciles.
C'est plus qu'un simple état d'esprit; il existe des raisons physiques (c'est-à-dire numériques) pour lesquelles la suppression est plus difficile.
Lorsque vous supprimez, vous laissez un trou où quelque chose était. Le terme technique pour l'entropie résultante est "fragmentation" Dans une liste chaînée, cela vous oblige à "patcher" le nœud supprimé et à désallouer la mémoire qu'il utilise. Dans les arbres binaires, il provoque un déséquilibre de l'arbre. Dans les systèmes de mémoire, la mémoire reste inutilisée pendant un certain temps si les blocs nouvellement alloués sont plus grands que les blocs laissés par la suppression.
En bref, l'insertion est plus facile car vous pouvez choisir où vous allez insérer. La suppression est plus difficile car vous ne pouvez pas prévoir à l'avance quel élément va être supprimé.
Pourquoi est-il plus difficile de supprimer que d'insérer? Les structures de données sont conçues plus en fonction de l'insertion que de la suppression, et à juste titre.
Considérez ceci - afin de supprimer quelque chose d'une structure de données, il doit être là en premier lieu. Vous devez donc l'ajouter en premier, ce qui signifie qu'au plus vous avez autant de suppressions que d'insertions. Si vous optimisez une structure de données pour l'insertion, vous êtes assuré d'obtenir au moins autant d'avantages que si elle avait été optimisée pour la suppression.
De plus, à quoi sert la suppression séquentielle de chaque élément? Pourquoi ne pas simplement appeler une fonction qui l'efface tout d'un coup (peut-être simplement en en créant une nouvelle)? De plus, les structures de données sont plus utiles lorsqu'elles contiennent réellement quelque chose. Donc, le cas d'avoir autant de suppressions que d'insertions ne sera pas, dans la pratique, très courant.
Lorsque vous optimisez quelque chose, vous voulez optimiser les choses qu'il fait le plus et qui prennent le plus de temps. En utilisation normale, la suppression d'éléments d'une structure de données se produit moins fréquemment que l'insertion.
Ce n'est pas plus difficile.
Avec des listes doublement liées, lorsque vous insérez, vous allouez de la mémoire, puis vous établissez une liaison avec la tête ou le nœud précédent, et avec la queue ou le nœud suivant. Lorsque vous supprimez, vous serez dissocié de exactement le même, puis libérez de la mémoire. Toutes ces opérations sont symétriques.
Cela suppose que dans les deux cas, vous avez le nœud à insérer/supprimer. (Et dans le cas de l'insertion, que vous avez également le nœud à insérer avant, donc d'une certaine manière, l'insertion pourrait être considérée comme légèrement plus compliquée.) Si vous essayez de supprimer sans avoir le nœud à supprimer, mais le - payload du nœud, alors bien sûr, vous devrez d'abord rechercher la liste de la charge utile, mais ce n'est pas un défaut de suppression, n'est-ce pas?
Avec des arbres équilibrés, la même chose s'applique: un arbre a généralement besoin d'être équilibré immédiatement après une insertion et également immédiatement après une suppression. C'est une bonne idée d'essayer de n'avoir qu'une seule routine d'équilibrage et de l'appliquer après chaque opération, qu'il s'agisse d'une insertion ou d'une suppression. Si vous essayez d'implémenter une insertion qui laisse toujours l'arbre équilibré, ainsi qu'une suppression qui laisse toujours l'arbre équilibré, sans que les deux partagent la même routine d'équilibrage, vous compliquez inutilement votre vie.
En bref, il n'y a aucune raison pour que l'un soit plus dur que l'autre, et si vous trouvez que c'est le cas, il est en fait possible que vous soyez victime de la tendance (très humaine) à trouver plus naturel de penser de manière constructive que soustractive, ce qui signifie que vous pouvez implémenter la suppression d'une manière plus compliquée qu'elle ne devrait l'être. Mais c'est un problème humain. D'un point de vue mathématique, il n'y a pas de problème.
En termes d'exécution, en regardant le comparaison de la complexité temporelle des opérations de structure de données sur Wikipedia, notez que les opérations d'insertion et de suppression ont la même complexité. L'opération de suppression qui y est profilée est la suppression par index, où vous avez une référence à l'élément de structure à supprimer; l'insertion se fait par article. Le temps d'exécution plus long pour la suppression dans la pratique est dû au fait que vous avez généralement un élément à supprimer et non son index, vous avez donc également besoin d'une opération de recherche. La plupart des structures de données du tableau ne nécessitent pas de recherche supplémentaire pour une insertion, car la position de placement ne dépend pas de l'élément ou la position est déterminée implicitement lors de l'insertion.
Quant à la complexité cognitive, il y a une réponse à la question: les cas Edge. La suppression peut en avoir plus que l'insertion (cela n'a pas encore été établi dans le cas général). Cependant, au moins certains de ces cas Edge peuvent être évités dans certaines conceptions (par exemple, avoir un nœud sentinelle dans une liste chaînée).
En plus de tous les problèmes mentionnés, l'intégrité référentielle des données est impliquée. Pour construire la structure de données la plus appropriée, comme les bases de données en SQL, l'intégrité référentielle Oracle est très importante.
Pour vous assurer que vous ne le détruisez pas accidentellement, beaucoup de choses différentes ont été inventées.
Par exemple, une cascade lors de la suppression qui non seulement supprime ce que vous essayez de supprimer, mais déclenche également le nettoyage des données associées.
Cette base de données nettoie les données indésirables et conserve l'intégrité des données intactes.
Par exemple, vous avez des tableaux avec les parents et les types en tant qu'enregistrements associés dans le deuxième tableau.
Où le parent est la table principale. Si vous n'avez pas d'intégrité référentielle renforcée en place, vous pouvez supprimer tous les enregistrements dans n'importe quelle table et plus tard, vous ne saurez pas comment obtenir des informations complètes sur la famille car vous avez des données dans la table enfant et rien dans la table parent.
C'est pourquoi la vérification d'intégrité référentielle ne vous permettra pas de supprimer un enregistrement de la table parent tant que les enregistrements de la table enfant n'auront pas été nettoyés.
Et c'est pourquoi dans la plupart des sources de données, il est plus difficile de supprimer des données.