J'ai reçu une liste de données de chaîne. 10,20,30 sont les numéros de ligne 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
6 Réponses :
Je vais donner les deux solutions que je pourrais proposer, mais cette question est éventuellement ouverte. P>
Utilisez une table de hachage. Les clés sont des numéros de ligne. Les valeurs sont En supposant que vous n'avez pas de notes de ligne extrêmement espacées: utilisez une liste lié 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. P> (chaîne, pointeur à la valeur de la ligne suivante) code>. Cela rend l'accès aléatoire et linéaire rapidement. edit: strong> L'insertion est toujours
o (n) code> avec ceci. Cela aidera seulement avec l'heure d'accès, qui sera
O (1) code>. La deuxième solution a
O (1) code> insertion. P> li>
l code> pour stocker des chaînes. Créez également un tableau distinct
p code> contenant un pointeur sur chaque noeud
k code> -th de la liste. Pour accéder à la ligne
i code>, vérifier
p [plancher (i / k)] code>, saute au nœud qu'il pointe dans
l code> et sauvegarder
i mod k code> fois pour atteindre votre chaîne. L'heure d'accès est donc
O (k) code>. Le temps d'insertion est
o (1) code>. L'utilisation de l'espace pour
n code> cordes est
o (n + max {i} / k) code>. P> li>
ol>
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 i> (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.
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 } } }
Suivissons les suivantes sur vos besoins: P>
pas fort temps réel. strong> (c'est-à-dire que ce n'est pas pour la négociation à haute fréquence ou le contrôle des machines.) p> li>
Il fonctionne sur un PC Les données sont 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. P>
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. P>
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 Le choix se résume donc à ce qui est le plus facile à utiliser. em> pourrait être le tableau. P> {bool utilisé; chargez le texte [80];} code> ou similaire. Vous pouvez également répondre à une longue durée. Lignes - et sauvegarder la mémoire - en ayant juste un membre
char * texte code> et alloué de manière dynamique, ou définissant le texte sous forme de liste liée des morceaux liés.) p>
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. p>
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 p>
Remarque: Si votre collection a de petite taille ou que vous modifiez rarement la structure, vous pouvez simplement utiliser la liste liée. P>
... 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.
Je sais que vous recherchez une structure de données spécialisée, mais que diriez-vous de la structure de données simple em>, mais de le trier paresseusement em>? Vous pouvez ajouter de nouvelles lignes à un tableau dynamique puis trier le tableau (avec Je pense que cela serait mieux parce que toutes les lignes sont probablement faites < em> beaucoup em> 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 em> journal n em>) ). 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. P> 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 em> saisies dans l'ordre; Ensuite, comme chaque ligne est ajoutée: p> 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 em> 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. P> (Si vous voulez faire Un inconvénient de cette approche est que la suppression des lignes em> 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). P> P> qsort code>) lorsque vous devez les imprimer.
qsort code> 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 code> aurait juste besoin d'utiliser ces données supplémentaires pour résoudre les liens des numéros de ligne en double .) P>
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, p>
Je n'ai pas testé le code, c'est Il suffit de modifier le code tel que pris du site. p>
p> p> p> P> code> p>
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;)