2011-12-03 3 views
2

나는 얼마 동안 텍스트 편집기에서 작업 해왔다. 처음부터 사용자 정의 편집 컨트롤을 만들었으므로 지금은 기본 사항을 가지고 있습니다. 내가 직면하고있는 문제는 회선 관리에 관한 것입니다. 내 프로그램은 입력 텍스트를 줄 단위로 나누기 때문에 (줄 단위로 텍스트가 인쇄됩니다.) 줄 관리가 매우 중요합니다. std :: vector를 사용하여 줄 위치를 저장했습니다. 내 텍스트 처리를 위해 Piece Table을 사용하고 있지만, 단순화를 위해 문자 배열을 사용한다고 가정 해 보겠습니다. 사용자가 엔터를 누를 때마다 요소를 선 벡터에 추가/삽입합니다. 문제는 사용자가 문자를 삽입 할 때마다 전체 구조가 방해 받는다는 것입니다. 예를 들면 다음과 같습니다 때문에 삽입의텍스트 편집기에서 줄 관리

  0 1 2 3 4 5 6 7 8 9 10 11 
text = ['h','e','l','x','l','o','\n','W','o','r','l','d'] 
state of line vector : 
line[0] = 0 
line[1] = 6 

, 나는 각각의 값을 업데이트해야합니다 :

  0 1 2 3 4 5 6 7 8 9 10 
text = ['h','e','l','l','o','\n','W','o','r','l','d'] 
state of line vector : 
line[0] = 0 
line[1] = 6 

는 이제 사용자가 텍스트 [2] 이후 ('X') 문자를 삽입한다고 가정 해 봅시다 현재 행 뒤의 행 벡터에있는 요소. 삭제시에도 마찬가지입니다. 프로그램에 1000 줄이 있고 사용자가 첫 번째 줄을 편집하면 999 개의 요소 (첫 번째 요소 제외)를 모두 업데이트하는 것은 상당히 비효율적입니다.

내가 생각했던 것은 각 줄을 서로 독립적으로 유지하는 것이 었습니다. 그러나 기존 라인이 두 라인으로 나뉘어지면 합병증이 생길 수 있습니다. 그래서 나는 문제에 대해 좋은 방법이 무엇인지 알고 싶습니다.

편집 : 분명히하기 위해 피스 테이블이라는 데이터 구조를 사용하고 있습니다. 나는 일련의 문자들을 사용하지 않고있다. 다음은 조각 테이블 데이터 구조입니다. http://www.cs.unm.edu/~crowley/papers/sds.pdf

+0

저렴한 삽입물을 지원하려면 벡터 <>가 잘못된 데이터 구조입니다. O (n) 복잡성. <> 목록을 고려 했습니까? –

+0

@HansPassant 목록에 요소 당 줄을 저장한다는 것은 한 줄에서 다른 줄로 이동하는 데 비용이 많이 든다는 뜻입니다. (한 줄을 다른 줄로 옮기는 것보다 일반적으로 줄을 삽입하는 것이 일반적 일 수 있음) –

+0

당신이 풀려고하는 문제를 설명했습니다. 예를 들어, N 번째 라인에 O (1) 액세스가 필요합니까, 아니면 O (N)이 수행합니까? (그렇다면 벡터에 줄의 길이를 유지하고 필요할 경우 추가 할 수 있습니다.) – Neil

답변

3

많은 편집자에 의해 사용되는 고전적인 데이터 구조의 일종을 고려하는 것이 좋습니다

는 " Gap Buffer"입니다. 이것은 기본적으로 활동이 발생하는 커서 주위에있는 작업 공간을 가지기 때문에 로컬 작업이 빠르게 수행됩니다. 그런 다음 커서가 움직이면 갭은 변화가 일어 났을 때 함께 움직입니다.

회선 계산과 관련하여 최신 시스템은 버퍼를 스캔하고 회선을 검색 할 수있을만큼 빠릅니다. 좋은 점은 대부분의 작업에서이 작업을 수행 할 필요가 없으므로 항상 수행하지 않는 것입니다. 또한 버퍼의 실제 줄 (예 : EOL 마커로 끝나는 문자 모음)과 부드러운 줄 (예 : 줄 바꿈 등)이 다릅니다. 단락이 일상적으로 단일 "줄"이지만 페이지 여백으로 줄이는 현대의 워드 프로세서를 생각해보십시오. 물론,이 방법으로 처리 할 수 ​​있습니다.

마지막으로 키보드에서 대부분의 작업을 수행 할 때 상대 위치를 사용하면됩니다 (즉, 새 행을 삽입하는 경우 행의 배열에 새로운 행 마커를 추가하는 것이 간단합니다. 버퍼 내에서). 그러나 여러 줄의 대용량 붙여 넣기 작업을 수행하면 전체 버퍼를 모두 밀어 넣고 전체 버퍼를 다시 계산하는 것이 더 빠를 것입니다 (대안으로, 붙여 넣기를 항상 줄 바꿈하여 삽입 할 수 있습니다. 하나는 정상적인 라인처럼).

거대한 거대한 버퍼 또는 속도가 느린 컴퓨터의 경우 전역 상태 (정확히 얼마나 많은 줄이 버퍼에 있는지, 정확히 어떤 줄이 있는지 등)를 걱정하지 않으려 고 할 수 있습니다 하나의 포인트와 배경에 그 종류의 재 계산을 킥오프. 대부분 일시 중지는 미성년자 일뿐 아니라 (입력하는 경우 짜증나게 할 수도 있음) 인간이 단순히 일시 중지하여 생각을 포착하자마자 따라 잡을 것입니다. 분명히 이것은 디자인을 복잡하게 만들 수 있으며 당분간 현대 하드웨어에 무차별 대입을 사용하는 것이 좋습니다. 내가 질문을 이해한다면

+0

"조각 테이블"은 텍스트 편집기에서 매우 일반적으로 사용되는 데이터 구조이기도합니다. 이 질문에서 언급하는 논문은 갭 버퍼와 조각 테이블을 포함하여 텍스트를 저장하기 위해 텍스트 편집기에서 사용되는 여러 가지 데이터 구조를 설명하고 비교합니다. 안타깝게도 종이의 이미지 링크가 오래되어 버렸지 만 나이가 들어도 놀랍도록 잘 유지됩니다. –

1

벡터가 정상적으로 작동합니다.

동적으로 줄을 할당하고 벡터 저장 줄이 줄에 대한 포인터를 갖는 것을 고려하십시오. 줄을 바꾸는 것은 줄 자체를 옮기는 것보다 훨씬 저렴합니다. 또한 Gap Buffer techniques.

0

, 당신은이 라인을 따라 보조 데이터 구조와 라인의 위치를 ​​추적하고 있습니다 :

line offset length 
    0  0  65 
    1  65  30 
    2  95  50 
    3  145  1 
    4  146  13 
... 

, 당신은 D로 라인 N 변경의 길이가있는 경우 모든 나머지 라인의 오프셋을 d로 갱신한다. 그리고 많은 선이있을 때 그것은 느립니다.

랜드 마크를 추적 할 수 있습니다. 순서의 시작부터 오프셋이되는 대신에, 당신은 그것들을 어떤 랜드 마크에 상대적으로 가지게 할 수 있습니다.

100 줄마다 경계표를 작성한다고 가정합니다. 첫 번째 표식은 파일의 시작 부분에 있기 때문에 첫 번째 100 줄은 동일하게 추적됩니다. 그러나 다음 수 백 라인은 단순히 오프셋을 가지며 랜드 마크는 라인 100의 파일 시작부터 절대 오프셋을 갖습니다.

따라서 라인의 길이를 변경하면 나머지는 오프셋 만 업데이트하면됩니다 해당 랜드 마크에있는 선들과 나머지 랜드 마크의 오프셋. 그것은 여전히 ​​O (n)이지만, 더 빨리 할 수있는 꽤 큰 약수가 있습니다.

하지만 우리는 더 잘할 수 있습니다. 랜드 마크 목록을 유지하는 대신 트리의 나뭇잎이 선이고 루트가 전체 파일을 나타내는 트리에 배치한다고 가정합니다. 주어진 라인의 오프셋을 찾으려면 모든 조상의 오프셋을 함께 추가하십시오. 그리고 행이 변경되면 노드 하나와 해당 조상을 간단히 업데이트하면됩니다. 이것은 약간의 부기를 희생하면서 O (log n)을 준다. 공간 오버 헤드는 이미 사용중인 이중 연결 목록보다 현저히 나쁘지 않습니다.

관련 문제