2010-11-16 42 views
33

Đây là câu hỏi phỏng vấn. Bạn sẽ sử dụng cấu trúc dữ liệu nào để lưu trữ văn bản trong trình soạn thảo văn bản?Cấu trúc dữ liệu cho trình soạn thảo văn bản

+1

Xin xem: [Lưu Trữ lý thuyết biên tập] (http: // stackoverflow.com/questions/3169440/text-editor-theory/3169491) –

Trả lời

31

Trên bộ xử lý văn bản ZX-Spectrum cũ (hoặc hơn nữa, tôi không biết) đã sử dụng cấu trúc rất đơn giản.

Có một bộ đệm lớn, chiếm toàn bộ RAM miễn phí. Văn bản được chia thành hai phần tại con trỏ. Phần trước con trỏ, được đặt ở đầu bộ đệm và phần còn lại ở cuối bộ đệm. Khi nhập văn bản, dữ liệu chỉ được thêm vào phần cuối của phần đầu tiên và khi di chuyển con trỏ, văn bản được sao chép ra và quay lại. bố trí

Buffer:

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

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

Đó là, làm thế nào một số chỉnh sửa hoạt động đã được thực hiện:

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

Backspace:  cur1-- 

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

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

Buffer trong hành động:

   Hello, W..............orld! 
Press right  ^   ^
      Hello, Wo..............rld! 
Press backspace  ^   ^
      Hello, W...............rld! 
Press 0   ^   ^
      Hello, W0..............rld! 
        ^   ^
+7

Để tham khảo: Đây được gọi là "bộ đệm gab". Hầu hết các triển khai không di chuyển bộ đệm khi bạn di chuyển con trỏ. Họ chỉ thực hiện thao tác chèn/xóa. –

+0

@Aaron Digulla: Cảm ơn, bổ sung tốt. Cả hai triển khai đều có lý do của chúng. – Vovanium

+14

Có lỗi đánh máy ở đó: nó được gọi là ** khoảng trống đệm ** Và đây là [thông tin thêm từ Wikipedia] (http://en.wikipedia.org/wiki/Gap_buffer) –

29

Rope

Một sợi dây cơ bản là cây nhị phân có lá là mảng ký tự. Một nút trong cây có một con trái và một con phải - con trái là phần đầu tiên của chuỗi, trong khi con phải là phần cuối cùng của chuỗi. Nối hai dây chỉ đơn giản là liên quan đến việc tạo ra một nút cây mới với cả hai dây thừng như trẻ em. Để đảm bảo lập chỉ mục thời gian logarit và các hoạt động chuỗi con, dây dẫn có thể cần được cân bằng. Có thể có nhiều chiến lược cân bằng khác nhau.

Ưu điểm chính của dây so với lưu trữ chuỗi là mảng ký tự là chúng cho phép nối nhanh hơn nhiều so với chuỗi thông thường và không yêu cầu dung lượng bộ nhớ tiếp giáp lớn để lưu trữ chuỗi lớn. Những bất lợi chính là sử dụng không gian tổng thể lớn hơn và lập chỉ mục chậm hơn, cả hai đều trở nên nghiêm trọng hơn khi cấu trúc cây trở nên lớn hơn và sâu hơn. Tuy nhiên, nhiều ứng dụng thực tế của việc lập chỉ mục chỉ liên quan đến phép lặp qua chuỗi, mà vẫn còn nhanh miễn là các nút lá đủ lớn để hưởng lợi từ các hiệu ứng bộ nhớ cache.

+1

+1 cho tôi biết cấu trúc tôi đã phát minh lại (sic), được mô tả và đề xuất trong một trong các bài đăng của tôi được gọi là chính thức :-) – thkala

+0

@thkala: thanh toán Để làm một số nghiên cứu đầu tiên - không có gì mới dưới mặt trời ;-) –

+0

Cũng như nối, dây thường tương đối tốt (so với lưu trữ liền kề hoàn toàn) cho nhiều thao tác xóa, chèn và thay thế, đặc biệt là gần đầu tài liệu hoặc ở đâu phát triển bộ nhớ tiếp giáp sẽ yêu cầu di chuyển trong bộ nhớ. –

6

Tôi biết đó là quá muộn cho một câu trả lời, nhưng tôi tìm thấy The Craft of Text Editing cuốn sách thực sự hữu ích. Nó chứa mô tả của một số mô hình bộ đệm với ưu và nhược điểm của chúng. Thật không may, nó không đề cập đến cấu trúc dữ liệu Ropes.

1

Khi @Vovanium đã đề cập đến lý thuyết cơ bản về cách bộ đệm khoảng cách có thể được sử dụng, tôi đã triển khai phiên bản 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++; 
    } 
} 
Các vấn đề liên quan