Un bon truc qui "prend la poussière" dans les favoris - "Les favoris ne s'arrêtent jamais, l'action ne commence jamais"

Direction 1 : Partagez une bonne question que vous avez collectée

Lorsque Xiao Yalan a appris la structure des données et l'algorithme pour la première fois, c'était vraiment difficile à apprendre. J'ai senti que la liste chaînée était vraiment difficile. Après avoir appris les connaissances suivantes, j'ai trouvé que la liste chaînée devenait progressivement plus simple. Si c'est maintenant, Xiao Yalan pense toujours que les points de connaissance de la liste chaînée et les questions du JO sont très significatifs.

Il s'agit d'un blog écrit par Xiao Yalan lié aux points de connaissance de la liste liée : Liste liée individuellement - "Structure de données et algorithme"

Double liste chaînée - "Structure de données et algorithme"

Table de séquence (version mise à jour) - "Structure de données et algorithme"

 


struct ListNode* reverseList(struct ListNode* head){
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode*n1=NULL;
    struct ListNode*n2=head;
    struct ListNode*n3=n2->next;
    while(n2!=NULL)
    {
        n2->next=n1;
        //迭代
        n1=n2;
        n2=n3;
        if(n3!=NULL)
        {
             n3=n3->next;
        }
    }
    return n1;
  
}

 

 

 

 

 

 

 

 

 

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if (headA == NULL || headB == NULL) {
        return NULL;
    }
    struct ListNode *pA = headA, *pB = headB;
    while (pA != pB) {
        pA = pA == NULL ? headB : pA->next;
        pB = pB == NULL ? headA : pB->next;
    }
    return pA;
}

 

 

 

 

L'idée principale utilisée dans ce sujet est l'idée de pointeurs rapides et lents ! ! !

 

bool hasCycle(struct ListNode* head) {
    if (head == NULL || head->next == NULL) {
        return false;
    }
    struct ListNode* slow = head;
    struct ListNode* fast = head->next;
    while (slow != fast) {
        if (fast == NULL || fast->next == NULL) {
            return false;
        }
        slow = slow->next;
        fast = fast->next->next;
    }
    return true;
}

Direction 2 : Partagez une technique pratique que vous avez collectée

Une liste chaînée est une structure de stockage non séquentielle et non séquentielle sur une unité de stockage physique, et l'ordre logique des éléments de données est réalisé par l'ordre des liens des pointeurs dans la liste chaînée. La liste chaînée est composée d'une série de nœuds (chaque élément de la liste chaînée est appelé un nœud), et les nœuds peuvent être générés dynamiquement au moment de l'exécution. Chaque nœud se compose de deux parties : l'une est un champ de données qui stocke les éléments de données, et l'autre est un champ de pointeur qui stocke l'adresse du nœud suivant. Par rapport à la structure séquentielle de liste linéaire, l'opération est plus compliquée. Puisqu'elle n'a pas besoin d'être stockée dans l'ordre, la liste chaînée peut atteindre la complexité de O(1) lors de l'insertion, ce qui est beaucoup plus rapide qu'une autre table de séquence de liste linéaire, mais il faut O(n) pour trouver un nœud ou accéder un temps de nœud numéroté spécifique, et les complexités temporelles correspondantes du tableau linéaire et du tableau séquentiel sont O(logn) et O(1) respectivement.
L'utilisation de la structure de liste chaînée peut surmonter l'inconvénient selon lequel la liste chaînée de tableau a besoin de connaître la taille des données à l'avance, et la structure de liste chaînée peut utiliser pleinement l'espace mémoire de l'ordinateur et réaliser une gestion dynamique de la mémoire flexible. Cependant, la liste chaînée perd les avantages de la lecture aléatoire du tableau, et en même temps, la liste chaînée a une surcharge d'espace relativement importante en raison de l'augmentation du champ de pointeur du nœud. L'avantage le plus évident de la liste chaînée est que la façon dont le tableau conventionnel organise les éléments associés peut être différente de l'ordre de ces éléments de données en mémoire ou sur le disque, et l'accès aux données doit souvent être converti en différents ordres d'arrangement. . Les listes chaînées permettent l'insertion et la suppression de nœuds à des positions arbitraires sur la liste, mais n'autorisent pas l'accès aléatoire. Il existe de nombreux types de listes chaînées : listes chaînées simples, listes chaînées doubles et listes chaînées circulaires. Les listes chaînées peuvent être implémentées dans de nombreux langages de programmation. Les types de données intégrés des langages tels que Lisp et Scheme incluent l'accès et le fonctionnement des listes liées. Les langages procéduraux ou orientés objet tels que C, C++ et Java s'appuient sur des outils modifiables pour générer des listes chaînées.

La caractéristique de la représentation de stockage lié de la table linéaire est d'utiliser un groupe d'unités de stockage arbitraires pour stocker les éléments de données de la table linéaire (ce groupe d'unités de stockage peut être continu ou discontinu). Par conséquent, afin de représenter la relation logique entre chaque élément de données et son élément de données successeur direct, pour un élément de données, en plus de stocker ses propres informations, il est également nécessaire de stocker une information indiquant son successeur direct (c'est-à-dire le stockage de l'Emplacement successeur direct). Un "nœud" est composé de ces deux parties d'informations, représentant un élément de données dans le tableau linéaire. Un inconvénient de la représentation en stockage chaîné de la table linéaire est que pour trouver un nombre, il faut recommencer depuis le début, ce qui est très gênant.
Selon la situation, vous pouvez également concevoir vous-même d'autres extensions de la liste chaînée. Mais généralement, aucune donnée ne sera attachée au bord, car les points et les bords de la liste chaînée sont fondamentalement en correspondance un à un (sauf pour le premier ou le dernier nœud, mais il n'y aura pas de cas particuliers). Cependant, il existe un cas particulier où si la liste liée prend en charge l'inversion des pointeurs avant et arrière dans une section de la liste liée, il peut être plus pratique d'ajouter la marque d'inversion sur le côté.
Pour les listes chaînées non linéaires, vous pouvez faire référence à d'autres structures de données connexes, telles que des arbres et des graphiques. De plus, il existe une structure de données basée sur plusieurs listes liées linéaires : liste de sauts, la vitesse des opérations de base telles que l'insertion, la suppression et la recherche peut atteindre O(nlogn), la même chose qu'un arbre binaire équilibré.
Le domaine stockant les informations d'élément de données est appelé un domaine de données (définir le nom de domaine comme données), et le domaine stockant l'emplacement de stockage suivant immédiat est appelé un domaine de pointeur (définir le nom de domaine comme suivant). Les informations stockées dans le champ de pointeur sont également appelées pointeur ou lien.
Une liste chaînée composée de N nœuds représentant respectivement ,,…, est appelée une représentation de stockage chaîné d'une liste linéaire. Puisque chaque nœud de ce type de liste chaînée ne contient qu'un seul champ de pointeur, on l'appelle aussi une liste chaînée unique. ou une liste chaînée linéaire. 

Structurellement, les listes chaînées peuvent être divisées en : liste chaînée simple, liste chaînée double et liste circulaire. Liste), dans la plupart des cas logarithmiques, nous n'utiliserons que les trois listes chaînées suivantes.

Lié individuellement

La structure de stockage de la liste simplement chaînée est relativement simple : en termes de stockage, elle peut utiliser un ensemble d'unités de stockage arbitraires pour stocker les éléments de données de la liste linéaire (cet ensemble d'unités de stockage peut être continu ou discontinu). Chaque élément contient deux champs, où le champ qui stocke les informations d'élément de données est appelé le champ de données ; le champ qui stocke l'emplacement de stockage suivant immédiat est appelé le champ de pointeur. Les informations stockées dans le champ du pointeur sont appelées un pointeur ou un lien. Comme le montre la figure ci-dessous, le lien pointe vers le nœud suivant de la liste, tandis que le dernier nœud pointe vers une valeur nulle.

 

Liste doublement chaînée

La structure de stockage de la liste doublement liée est plus compliquée que celle de la liste simplement liée. Dans la liste doublement liée, il y a deux champs de pointeur dans chaque nœud, l'un pointe vers le successeur direct et l'autre pointe vers le prédécesseur direct. Lorsque la connexion est la dernière connexion, elle pointe vers une valeur nulle ou une liste vide. Comme indiqué ci-dessous:

Liste circulaire liée (liste circulaire)

Une liste chaînée circulaire est une autre forme de structure de stockage chaînée. Sa caractéristique est que le champ de pointeur du dernier nœud de la liste pointe vers le nœud principal et que toute la liste chaînée forme un anneau. Par conséquent, à partir de n'importe quel nœud de la table, d'autres nœuds de la table peuvent être trouvés, comme illustré dans la figure suivante :

 

De même, une liste doublement liée peut également créer une liste circulaire liée. La liste chaînée circulaire a deux caractéristiques : premièrement, il n'y a pas de pointeur NULL dans la liste chaînée, deuxièmement, la liste chaînée n'a pas besoin d'augmenter la capacité de stockage. 

  • Les cellules de mémoire peuvent être contiguës ou non contiguës
  • Chaque nœud contient deux parties, à savoir le champ d'élément de données et le champ de pointeur
  • Les nœuds sont connectés via des champs de pointeur 

Direction 3 : La poussière s'est accumulée depuis si longtemps, cette chose que vous avez collectée vous est-elle encore utile maintenant ?

Le but de la liste chaînée

  • Réaliser le système de fichiers : la liste chaînée peut être utilisée pour réaliser la structure du répertoire de fichiers dans le système de fichiers, chaque nœud peut représenter un fichier ou un répertoire, et l'ensemble du système de fichiers peut être considéré comme une structure de liste chaînée contenant plusieurs nœuds.
  • Tri : les listes chaînées peuvent être utilisées pour implémenter des algorithmes de tri tels que le tri par fusion et le tri rapide. Ces algorithmes nécessitent généralement la création et la suppression dynamiques de nœuds au moment de l'exécution, ce qui est la force des listes chaînées.
  • Gérer les données dynamiques : une liste chaînée est une structure de données dynamique qui peut librement ajouter et supprimer des nœuds. Elle est donc souvent utilisée pour gérer des collections de données de taille dynamique, telles que les systèmes de fichiers, la gestion de la mémoire du système d'exploitation et les protocoles réseau.
  • Stockage de données éparses : les listes chaînées peuvent également être utilisées pour stocker des structures de données éparses telles que des matrices éparses. Étant donné que les listes liées peuvent gérer et stocker efficacement des collections de données non ordonnées, il s'agit d'un moyen efficace de stocker des données éparses.
  • Implémenter diverses structures de données : les tables sont souvent utilisées pour implémenter d'autres structures de données efficaces telles que des files d'attente, des piles et des tables de hachage. Les listes chaînées fournissent des opérations d'insertion et de suppression efficaces qui peuvent être effectuées en temps O (1), tandis que d'autres structures de données telles que les tableaux nécessitent une grande quantité de relocalisation des données.

Structures de données pouvant être implémentées avec des listes chaînées :

  1. Structure de données linéaire : les listes liées peuvent être utilisées pour implémenter des structures de données linéaires telles que des piles, des files d'attente et des files d'attente chaînées, et les piles et les files d'attente basées sur des listes liées peuvent croître de manière dynamique, ce qui est plus flexible que les implémentations basées sur des tableaux.
  2. Table de hachage : la table de hachage peut résoudre le problème de collision de hachage (Hash Collision) en utilisant une liste liée. La liste liée peut être utilisée pour former un seau de hachage. Lorsqu'une collision de hachage se produit, les données en conflit seront ajoutées à la fin. de la liste chaînée.
  3. Graphiques et arbres : les listes chaînées peuvent être utilisées pour décrire et implémenter des structures de données complexes de graphes et d'arbres, et chaque nœud peut utiliser une liste chaînée pour stocker des nœuds enfants ou des nœuds adjacents.
  • Réaliser un répartiteur de mémoire efficace : la liste chaînée peut être utilisée pour réaliser la structure du répertoire de fichiers dans le système de fichiers, chaque nœud peut représenter un fichier ou un répertoire, et l'ensemble du système de fichiers peut être considéré comme une structure de liste chaînée contenant plusieurs nœuds.

La liste chaînée est principalement destinée à faciliter la gestion des données de longueur ou de quantité incertaines. Par rapport au tableau, la liste chaînée économise de la mémoire lors du traitement de ce type de données. Les listes chaînées ne sont généralement pas nécessaires dans les langages dynamiques, car l'interpréteur de langages dynamiques gère la mémoire pour vous, mais vous pouvez également utiliser des listes chaînées dans les langages dynamiques lorsque vous avez des exigences particulières en matière d'efficacité de l'espace ou d'efficacité des actions d'insertion.

Les listes chaînées sont souvent utilisées pour stocker temporairement un ensemble de données linéaires de longueur variable dans des programmes.

Les données avec de telles caractéristiques peuvent être stockées dans une liste chaînée :

1. Les données augmentent progressivement

2. La longueur des données est indéfinie.Avant de stocker les premières données, il est difficile de déterminer une limite supérieure de la quantité de données devant être stockées à l'avenir, ou bien que la limite supérieure puisse être déterminée, la limite supérieure est plus grande que la longueur possible des données dans la plupart des cas. Par conséquent, il n'est pas rentable d'allouer l'espace en fonction de la limite supérieure en une seule fois. La liste liée peut demander de la mémoire chaque fois que de nouvelles données doivent être ajoutées, ce qui ne causera pas de gaspillage et ne limitera pas la quantité de données en raison d'une application insuffisante.

3. Il n'est pas nécessaire d'effectuer un accès aléatoire aux données en fonction du numéro de série.

Le conteneur de liste est fourni en C++ STL, qui est une liste chaînée. Dans le même temps, STL fournit également un conteneur vectoriel, qui peut également être utilisé pour traiter des données avec les caractéristiques ci-dessus, et le vecteur prend également en charge l'accès aléatoire (c'est-à-dire que la 3e exigence ci-dessus peut être ignorée). Cependant, lorsque le vecteur ajoute des données, si la mémoire continue allouée à l'origine a été épuisée, il doit réallouer la mémoire et copier les données d'origine.A ce moment, la complexité temporelle de ses données d'insertion n'est pas O (1) (non constante Le temps s'est écoulé). Par conséquent, en plus des caractéristiques ci-dessus, les données que la liste chaînée peut traiter ont les caractéristiques suivantes du quatrième point, alors la liste chaînée est le meilleur choix :

4. On espère que la complexité temporelle de chaque action d'ajout de données et de suppression de données est O(1) (temps constant).


Bon, c'est la fin du partage de Xiao Yalan aujourd'hui, continuons à travailler dur ! ! !

 

 

Je suppose que tu aimes

Origine blog.csdn.net/weixin_74957752/article/details/132263682
conseillé
Classement