Ceci est une question d'entrevue. Quelle structure de données utiliseriez-vous pour stocker le texte dans un éditeur de texte?
Sur le bon vieux ZX-Spectrum, un (ou plusieurs, je ne sais pas) texte exditor utilisait une structure très simple.
Il y avait un grand tampon, qui occupait toute la RAM libre. Le texte a été divisé en deux parties au niveau du curseur. Une partie avant le curseur a été placée au début du tampon et le reste à la fin du tampon. Lorsque le texte est saisi, les données sont simplement ajoutées à la fin de la première partie et lorsque le curseur est déplacé, le texte est copié d'avant en arrière.
Disposition du tampon:
Hello, World!
^------Cursor here
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|H|e|l|l|o|,| |W| <free> |o|r|l|d|!|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ^ ^ |
begin cur1 cur2 end
Voilà, comment certaines opérations d'édition ont été effectuées:
Type a char: buffer[cur1++] = character
Backspace: cur1--
Cursor left: buffer[--cur2] = buffer[--cur1]
Cursor right: buffer[cur1++] = buffer[cur2++]
Tampon en action:
Hello, W..............orld!
Press right ^ ^
Hello, Wo..............rld!
Press backspace ^ ^
Hello, W...............rld!
Press 0 ^ ^
Hello, W0..............rld!
^ ^
Une corde est essentiellement un arbre binaire dont les feuilles sont des tableaux de caractères. Un nœud dans l'arborescence a un enfant gauche et un enfant droit - l'enfant gauche est la première partie de la chaîne, tandis que l'enfant droit est la dernière partie de la chaîne. La concaténation de deux cordes implique simplement la création d'un nouveau nœud d'arbre avec les deux cordes comme enfants. Pour garantir l'indexation temporelle logarithmique et les opérations de sous-chaîne, il peut être nécessaire d'équilibrer la corde résultante. Diverses stratégies d'équilibrage sont possibles.
Les principaux avantages des cordes par rapport au stockage de chaînes sous forme de tableaux de caractères sont qu'elles permettent une concaténation beaucoup plus rapide que les chaînes ordinaires et ne nécessitent pas un grand espace mémoire contigu pour stocker une grande chaîne. Les principaux inconvénients sont une plus grande utilisation globale de l'espace et une indexation plus lente, les deux devenant plus graves à mesure que la structure de l'arbre devient plus grande et plus profonde. Cependant, de nombreuses applications pratiques de l'indexation impliquent uniquement une itération sur la chaîne, qui reste rapide tant que les nœuds terminaux sont suffisamment grands pour bénéficier des effets de cache.
Je sais qu'il est trop tard pour une réponse, mais j'ai trouvé The Craft of Text Editing book vraiment utile. Il contient la description de plusieurs modèles de tampons avec leurs avantages et leurs inconvénients. Malheureusement, il ne mentionne pas la structure de données Ropes.
Vous pourriez trouver cela intéressant, même s'il ne répond pas exactement à votre question:
Structure de données la plus efficace pour ajouter des styles au texte
J'espère que la discussion ira dans des endroits fascinants :-)
Comme @Vovanium a déjà mentionné la théorie de base de la façon dont le tampon d'espace peut être utilisé, j'ai mis en œuvre une version de C/C++.
Code:
#include <stdio.h>
#define SZ 1000
char leftArray[SZ], rightArray[SZ];
int leftCount, rightCount;
int cursorPos;
/*
* Private APIs
*/
void printArray(){
for(register int i = 0; i < leftCount; i++){
printf("%c", leftArray[i]);
}
for(register int i = rightCount - 1; i >= 0; i--){
printf("%c", rightArray[i]);
}
printf("\n");
}
void adjust(int pos){
while(leftCount > pos){
rightArray[rightCount++] = leftArray[--leftCount];
}
while(leftCount < pos){
leftArray[leftCount++] = rightArray[--rightCount];
}
}
/*
* Public APIs for Text Editor
*/
void init(){
cursorPos = leftCount = rightCount = 0;
}
void addWord(char Word[], int len){
adjust(cursorPos);
for(register int i = 0; i < len; i++){
leftArray[leftCount++] = Word[i];
}
leftArray[leftCount] = 0;
}
void addBackSpace(){
adjust(cursorPos);
leftCount--;
}
void moveCurson(int newPosition){
cursorPos = newPosition;
}
void subString(int pos, int length, char result[]){
adjust(cursorPos);
int k = 0;
int l = 0;
while(k + pos < leftCount && k < length){
result[k] = leftArray[pos + k];
k++;
}
length -= k;
while( l < length){
result[k++] = rightArray[rightCount - 1 - l];
l++;
}
}