web-dev-qa-db-ja.com

テキストエディターのデータ構造

これはインタビューの質問です。テキストエディターにテキストを保存するには、どのデータ構造を使用しますか?

42
Michael

古き良きZX-Spectrumでは、1つ(またはそれ以上、私にはわかりません)のテキストエクスダイターが非常に単純な構造を使用していました。

大きなバッファが1つあり、すべての空きRAMを占めていました。テキストはカーソルで2つの部分に分割されました。カーソルの前の部分はバッファの先頭に配置され、残りはバッファの末尾に配置されました。テキストを入力すると、最初の部分の最後にデータが追加され、カーソルを移動すると、テキストが前後にコピーされます。

バッファレイアウト:

Hello, World!
        ^------Cursor here

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|H|e|l|l|o|,| |W| <free>  |o|r|l|d|!|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                ^         ^        |
begin           cur1      cur2    end

つまり、いくつかの編集操作が行われた方法です。

Type a char:    buffer[cur1++] = character

Backspace:      cur1--

Cursor left:    buffer[--cur2] = buffer[--cur1]

Cursor right:   buffer[cur1++] = buffer[cur2++]

動作中のバッファ:

             Hello, W..............orld!
Press right          ^             ^
             Hello, Wo..............rld!
Press backspace       ^             ^
             Hello, W...............rld!
Press 0              ^              ^
             Hello, W0..............rld!
                      ^             ^
38
Vovanium

ロープ

ロープは基本的に、葉が文字の配列であるバイナリツリーです。ツリーのノードには、左の子と右の子があります。左の子は文字列の最初の部分で、右の子は文字列の最後の部分です。 2つのロープの連結には、両方のロープを子として持つ新しいツリーノードの作成が含まれます。対数時間のインデックス作成とサブストリング操作を保証するには、結果として生じるロープのバランスをとる必要がある場合があります。さまざまなバランス戦略が可能です。

文字列を文字配列として格納する場合と比較したロープの主な利点は、通常の文字列よりもはるかに高速な連結を可能にし、大きな文字列を格納するために大きな連続したメモリ空間を必要としないことです。主な欠点は、全体的なスペース使用量が増加し、インデックス作成が遅くなることです。どちらも、ツリー構造が大きく、深くなるほど深刻になります。ただし、インデックス作成の多くの実用的なアプリケーションは、文字列の反復のみを含みます。これは、リーフノードがキャッシュ効果の恩恵を受けるのに十分な大きさである限り、高速のままです。

33
Peter Alexander

答えが遅すぎるのはわかっていますが、 The Craft of Text Editing の本は本当に役に立ちました。いくつかの長所と短所を含むいくつかのバッファモデルの説明が含まれています。残念ながら、Ropesのデータ構造については触れられていません。

6
roman-kashitsyn

それはあなたの質問に正確に答えていない場合でも、これは興味深いかもしれません:

テキストにスタイルを追加するための最も効率的なデータ構造

議論が魅力的な場所に行くことを願っています:-)

5
thkala

@Vovaniumでギャップバッファーの使用方法の基本的な理論をすでに説明したので、C/C++のバージョンを実装しました。

コード:

#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++;
    }
}
3