7
votes

Quelle structure de données en C permettez-moi de stocker des lignes et appendez-vous facilement des lignes?

J'ai reçu une liste de données de chaîne. 10,20,30 sont les numéros de ligne xxx pré>

et si les types d'utilisateurs sont dans "23 données de chaîne". 23 L'utilisateur numéro de ligne souhaite insérer dans. Les données doivent devenir telles que P>

10. string 1
20. string 2
23. string data
30. string 3
40. string data


9 commentaires

L'informatique concerne les compromis. Dans votre cas, vous devez décider de ce que vous voulez échanger - mémoire vs vitesse. Seulement vous pouvez répondre à cela en fonction de vos besoins. En plus des matrices droites et des listes liées, vous pouvez également consulter les tables de hachage.


Vous pouvez utiliser presque toute structure que vous choisissez. Vous ne pouvez pas indexer dans les tableaux en utilisant le «numéro de ligne» car ils ne sont pas uniformément espacés. Cela signifie que vous ferez une recherche linéaire - et des listes liées sont sans doute meilleures (au moins, l'insertion d'une nouvelle ligne au milieu implique moins de mouvement de données). Vous avez toutes les informations dont vous avez besoin dans le nœud actuel et le nœud suivant d'une liste pour indiquer si la nouvelle ligne entre entre ces deux, et vous pouvez ensuite faire l'insertion facilement.


@Kaylum: Un hachage vous permet de trouver si un numéro de ligne particulier est présent ou non, mais trouver le numéro suivant après, disons, 20 est plutôt difficile avec le hachage moyen, n'est-ce pas?


La table de hachage est la façon standard de le faire. Un moyen plus facile: vous pouvez utiliser une liste liée avec un tableau auxiliaire contenant des pointeurs de référence sur chaque k-ème emplacement dans la matrice de chaîne, vous devez donc itérer au plus (K-1) index pour trouver celui que vous voulez. @JonathanLeffler trouve la suivante requise? Si tel est le cas, ma deuxième suggestion le rend facile.


@sudo: Je suis en désaccord avec votre évaluation. Pour une structure qui doit être recherchée linéairement, les tables de hachage sont la mauvaise structure de données. Étant donné que l'un des problèmes liés à une liste liée est l'incapacité d'être «index de saut» et la mention des lignes provenant des autres, je pense que le séquençage est important.


@Jonathanleffler Vous avez raison. Mais il n'est pas clair que l'OP a vraiment besoin de commander ou de l'importance de cette partie. Je sais que l'OP a montré les données de cette façon, mais cela peut être à la suite des structures que l'OP a en tête. Mais il se peut que l'OP est vraiment intéressé par le stockage et la récupération rapide des données sans nécessairement nécessairement une traversée linéaire. Quoi qu'il en soit, une plus grande idée de l'OP de considérer. Cette question n'est vraiment pas responsable dans le format SO.


@Jonathanleffler tu as raison. J'ai raté la partie dans le point de trouver la suivante. Dans ce cas, vous pouvez toujours utiliser la table de hachage tant que vous gardez dans chaque entrée un pointeur à la valeur suivante.


@Sudo: une "liste de sauts" serait une belle raffinement si la liste était suffisamment grande pour le garantir (probablement pas requise pour 20 lignes; probablement utile pour 1000 lignes; et il y aurait un point mortel quelque part entre les deux) . La description rappelle les numéros de ligne en (gasp) de base.


Haha, alors maintenant nous savons ce que c'est pour;)


6 Réponses :


3
votes

Je vais donner les deux solutions que je pourrais proposer, mais cette question est éventuellement ouverte.

  1. Utilisez une table de hachage. Les clés sont des numéros de ligne. Les valeurs sont (chaîne, pointeur à la valeur de la ligne suivante) . Cela rend l'accès aléatoire et linéaire rapidement. edit: L'insertion est toujours o (n) avec ceci. Cela aidera seulement avec l'heure d'accès, qui sera O (1) . La deuxième solution a O (1) insertion.

  2. En supposant que vous n'avez pas de notes de ligne extrêmement espacées: utilisez une liste lié l pour stocker des chaînes. Créez également un tableau distinct p contenant un pointeur sur chaque noeud k -th de la liste. Pour accéder à la ligne i , vérifier p [plancher (i / k)] , saute au nœud qu'il pointe dans l et sauvegarder i mod k fois pour atteindre votre chaîne. L'heure d'accès est donc O (k) . Le temps d'insertion est o (1) . L'utilisation de l'espace pour n cordes est o (n + max {i} / k) .

    La seule chose qui le rend pertinent à c ... est qu'il n'y a pas de table de hachage intégrée, bien sûr! Donc # 2 peut être plus facile à mettre en œuvre.


4 commentaires

Il est mentionné dans les commentaires à la question, mais pas dans votre réponse: à un moment donné, vous voudrez extraire les lignes dans l'ordre (sinon, quel est le point des numéros de ligne?), Qui n'est pas 't directement à faire avec une table de hachage.


La table de hachage décrite dans ma réponse contient le pointeur à la valeur de la ligne suivante dans la valeur, alors traverser dans l'ordre est facile. Je vois maintenant comment cela pourrait être incertain. Lorsque je dis "Pointeur à la valeur de la ligne suivante", je veux dire le tuple pour la ligne suivante, qui pointe à son tour sur le tuple pour la ligne après cela ... non seulement la chaîne de la ligne suivante. J'ai édité ma réponse pour clarifier.


Comment maintenez-vous ces pointeurs à la ligne suivante? Je suppose que vous gardez toujours un pointeur à la dernière ligne, mais cela n'aide pas beaucoup à insérer au milieu. Soit vous ithérez sur la liste liée pour rechercher le point d'insertion (auquel cas, quel est le point d'utiliser une table de hachage du tout?) Vous espérez que les numéros de ligne ne sont pas espacés par des quantités énormes et devinez successivement quoi Le numéro de ligne précédent est.


Oui vous avez raison. J'ai mal interprété l'Op un tas de fois et je n'ai pas vu qu'il voulait insérer dans le milieu rapidement, alors je pensais seulement à l'accès. L'édition ... # 1 est toujours plus rapide pour accéder, il convient donc de mentionner.



0
votes

Je vous conseille d'utiliser une liste liée.

// Define your list like this
typedef struct node {
    int line; // To hold the line number
    char * data;
    struct node * next;
} node_t;

// To insert
node_t* insert(node_t *head, const char * data, int line) // n is line from beginning
{
    // Node to be inserted in given line
    node_t *newNode;

    // Allocating Memory
    newNode = malloc(sizeof(node_t));

    // Filling the Data to New Node
    newNode->data = malloc(strlen(data)+1); // Allocate memory to store data
    strcpy(newNode->data, data);
    newNode->line = line;
    newNode->next = NULL;

    // It might be our First Node in Linked List
    if(head == NULL) {

        //Address of New Node Becomes our head
        return (head = newNode);
    } 

    // Node Might be inserted At Head
    else if(line == 0) {
        // Joining previous Linked List After new Node
        newNode->next = head;

       // Address of New Node Becomes our head
        return (head = newNode);
    } 

    // Inserting At the line next to line
    else {

        // Pointer to store intermediate address of node
        // To be used in Traversing
        node_t * current = head;

        // Go through to insert at Nth line
        while(current != NULL) {

            node_t * next = current->next; //The next Node

            if((line >= current->line && line < next->line) || (line >= current->line && NULL == next->line)) { // Test if we are at some point between current line and next line or if there is no next

                // If we are, point newNode to the next node of current
                newNode->next = current->next;

                // Now point current towards our New Node
                current->next = newNode;

                // Return Head as soon as we have inserted our new node
                return head;
            }
            current = next; // Point current to the next node to continue
        }
    }
}


0 commentaires

4
votes

Suivissons les suivantes sur vos besoins:

  1. pas fort temps réel. (c'est-à-dire que ce n'est pas pour la négociation à haute fréquence ou le contrôle des machines.)

  2. Il fonctionne sur un PC relativement contemporain (RAM mesuré en GB, fréquence de la CPU dans GHz). En particulier, il ne fonctionne pas sur un système embarqué.

  3. Les données sont pas plus de quelques mille lignes.

    Ensuite, vous pouvez utiliser presque toutes les structures de données que vous aimez; Cela ne comportera pas en ce qui concerne la mémoire ou le comportement du temps d'exécution.

    Par exemple, afin de trouver le point d'insertion dans une liste liée, juste itérer cette liste. Les PC sont assez rapides pour itérer des dizaines de milliers de fois avant de finir de clignoter.

    ou simplement allouer un tableau de 100 000 lignes de 80 caractères chacun. Pas de problème que ce soit. Ou d'un million de lignes. Toujours pas de problème. Ou de 10 millions de lignes, toujours pas de problème. Vous voyez mon point? (Dans une matrice, vous aurez besoin d'un marqueur pour marquer des lignes inutilisées. J'utiliserais une ligne de structure {bool utilisé; chargez le texte [80];} ou similaire. Vous pouvez également répondre à une longue durée. Lignes - et sauvegarder la mémoire - en ayant juste un membre char * texte et alloué de manière dynamique, ou définissant le texte sous forme de liste liée des morceaux liés.)

    Le choix se résume donc à ce qui est le plus facile à utiliser. pourrait être le tableau.


0 commentaires

1
votes

La meilleure solution pour cette tâche consiste à utiliser le type de données de dictionnaire. Bien sûr, en fonction de la nature des clés (nombre de lignes), vous pouvez effectuer une optimisation via une table de hachage appropriée.

Bien sûr, la bibliothèque C n'a pas de mise en œuvre du dictionnaire. Mais vous pouvez créer la vôtre, basé sur l'arbre noir rouge. CORLEN a expliqué une telle structure de données facilement https://www.amazon. com / introduction-algorithmes-3rd-mit-presse / dp / 0262033844

Remarque: Si votre collection a de petite taille ou que vous modifiez rarement la structure, vous pouvez simplement utiliser la liste liée.


3 commentaires

... que c n'a pas; Avez-vous une suggestion pour une bibliothèque? Parce que la mise en œuvre ad-hoc serait surchargée. (J'ai googlé et la glib est arrivée.)


Cormen a une excellente implémentation simple. Voir Amazon.com/introduction-algorithms-3rd-mit-press / dp / 02620338 44


Je pense qu'un arbre rouge-noir (ou un autre arbre de recherche binaire équilibré) irait bien, mais "une table de hachage appropriée" aurait le problème que l'extraction des données dans l'ordre est ennuyeuse.



2
votes

Je sais que vous recherchez une structure de données spécialisée, mais que diriez-vous de la structure de données simple , mais de le trier paresseusement ? Vous pouvez ajouter de nouvelles lignes à un tableau dynamique puis trier le tableau (avec qsort ) lorsque vous devez les imprimer.

Je pense que cela serait mieux parce que toutes les lignes sont probablement faites < em> beaucoup moins fréquemment que d'ajouter / inserrer des lignes. Par conséquent, vous devriez faire ajouter des lignes bon marché (dans ce cas, O (1) amortized) et l'impression peut être plus chère (dans ce cas, O ( n journal n ) ). Cela conserve également vos structures de données simples et permet à la bibliothèque standard C de manière compliquée des pièces compliquées.

Vous pouvez en faire un peu mieux en conservant un drapeau qui suit si toutes les données sont déjà connues pour être triées. ; De cette manière imprimant à plusieurs reprises (ou, en présumant que vous essayez d'écrire un interprète de base, il sera également bon marché. Un tel drapeau peut également être utile si vous vous attendez à ce que les lignes soient habituellement saisies dans l'ordre; Ensuite, comme chaque ligne est ajoutée: xxx

Je vais noter que vous n'avez pas spécifié ce qui se passe si une ligne est ajoutée qui réutilise un numéro de ligne existant. Si vous souhaitez remplacer l'ancienne ligne, vous pouvez modifier cette approche à l'aide d'un type stable et d'itération par la suite sur les lignes pour éliminer les lignes avec des numéros en double, en gardant uniquement le dernier.

(Si vous voulez faire qsort Stable pour ce cas, au lieu de stocker une chaîne pour chaque ligne, vous pouvez stocker des métadonnées supplémentaires avec elle (tout compteur croissant monotone le ferait, telle que L'heure actuelle, ou juste le nombre total de lignes au moment où la ligne a été ajoutée). Ensuite, la fonction de comparaison que vous donnez à qsort aurait juste besoin d'utiliser ces données supplémentaires pour résoudre les liens des numéros de ligne en double .)

Un inconvénient de cette approche est que la suppression des lignes ne sera pas rapide ou ne sera pas récupéré la mémoire immédiatement. Cependant, vous n'avez pas précisé si l'élimination de la ligne est une exigence; Même si c'est le cas, il sera probablement une opération rare (donc être un peu plus inefficace inefficace ou un peu plus d'espace inefficace peut être acceptable).


0 commentaires

1
votes

Ma suggestion consiste à utiliser la liste liée et l'insertion Trier pour insérer chaque fois que nécessaire,

Voici le code modifié à l'origine de geeksforgeeks.org,

Je n'ai pas testé le code, c'est Il suffit de modifier le code tel que pris du site.

xxx


0 commentaires