Có cấu trúc dữ liệu 'ngăn xếp chuỗi' hỗ trợ các hoạt động chuỗi này không?


28

Tôi đang tìm kiếm một cấu trúc dữ liệu mà các cửa hàng một tập hợp các chuỗi trên một bộ ký tự , khả năng thực hiện các hoạt động sau đây. Chúng tôi biểu thị D ( S ) là cấu trúc dữ liệu lưu trữ các thiết lập của chuỗi S .ΣD(S)S

  • Add-Prefix-Settrên : được cung cấp một số bộ T của chuỗi (có thể trống), có kích thước được giới hạn bởi một hằng số và có độ dài chuỗi được giới hạn bởi một hằng số, trả về D ( { t s | t T , s S } ) . Cả hai hằng bounding là toàn cầu: họ đều giống nhau cho tất cả các đầu vào T .D(S)TD({ts | tT,sS})T
  • Get-Prefixestrên : trả về { a | a s S , a Σ } . Lưu ý rằng tôi không thực sự quan tâm những gì cấu trúc được sử dụng cho bộ này, miễn là tôi có thể liệt kê nội dung của nó trong O ( | Σ | ) thời gian.D(S){a | asS,aΣ}O(|Σ|)
  • Remove-Prefixestrên : trả về D ( { s | a s S , a Σ } ) .D(S)D({s | asS,aΣ})
  • Merge: Cho D ( T ) , lợi nhuận D ( S T ) .D(S)D(T)D(ST)

Bây giờ, tôi thực sự muốn thực hiện tất cả các hoạt động này trong thời gian , nhưng tôi ổn với cấu trúc thực hiện tất cả các hoạt động này trong thời gian o ( n ) , trong đó n là độ dài của chuỗi dài nhất trong kết cấu. Trong trường hợp hợp nhất, tôi muốn thời gian chạy o ( n 1 + n 2 ) , trong đó n 1n cho lần đầu tiên và n 2 the n cho cấu trúc thứ hai.O(1)o(n)no(n1+n2)n1nn2n

Một yêu cầu bổ sung là cấu trúc là bất biến, hoặc ít nhất là các hoạt động trên trả về các cấu trúc 'mới' sao cho con trỏ đến các cấu trúc cũ vẫn hoạt động như trước.

Một lưu ý về khấu hao: điều đó là tốt, nhưng bạn phải coi chừng sự kiên trì. Khi tôi sử dụng lại các cấu trúc cũ mọi lúc, tôi sẽ gặp rắc rối nếu gặp phải trường hợp xấu nhất với một số hoạt động cụ thể trên cùng một cấu trúc (vì vậy bỏ qua các cấu trúc mới mà nó tạo ra).

Tôi muốn sử dụng cấu trúc như vậy trong thuật toán phân tích cú pháp mà tôi đang làm việc; cấu trúc trên sẽ giữ giao diện tôi cần cho thuật toán.

Tôi đã xem xét sử dụng một Trie , nhưng vấn đề chính là tôi không biết làm thế nào để hợp nhất cố gắng một cách hiệu quả. Nếu bộ chuỗi chỉ Add-Prefix-Setbao gồm các chuỗi ký tự đơn, thì bạn có thể lưu trữ các bộ này trong một ngăn xếp, điều này sẽ cung cấp cho bạn thời gian chạy cho ba thao tác đầu tiên. Tuy nhiên, cách tiếp cận này cũng không hoạt động để hợp nhất.O(1)

Cuối cùng, lưu ý rằng tôi không quan tâm đến các yếu tố : đây là hằng số cho tất cả những gì tôi quan tâm.|Σ|


Là các chuỗi chỉ được xây dựng bởi các hoạt động Add-Prefix-Sethoặc bạn bắt đầu với một chuỗi các chuỗi tùy ý?
Joe

2
n1=n2STo(n1+n2)

Bạn bắt đầu với một tập hợp có một chuỗi char duy nhất trong đó, nhưng một chuỗi trống cũng tốt (bạn có thể chỉ Add-Prefix-Settrong đó)
Alex ten Brink

@Joe: đó là một câu hỏi hay - Tôi bắt đầu bị thuyết phục rằng hoạt động hợp nhất gần như phá vỡ mọi cơ hội có được cấu trúc như vậy ...
Alex ten Brink

(n1,n2)

Câu trả lời:


5

Tôi đã suy nghĩ khá lâu, nhưng không tìm thấy vấn đề gì khi thực hiện tất cả các hoạt động của bạn theo cách ngu ngốc nhất có thể trong cấu trúc DAG giống như trie:

Thêm tiền tố-Set

T

O(|T|)

Hợp nhất

Liên kết các gốc của hai cấu trúc: làm cho tất cả các nút con của các gốc con thứ hai của nút thứ nhất. Bây giờ bạn có thể có nhiều cạnh được đánh dấu bằng cùng một ký tự đi từ cùng một nút.

O(1)

Cập nhật lười biếng của root

  1. O(|Σ|)O(1)
  2. O(1)

Tiền tố

Lười cập nhật root. Bây giờ tìm tất cả con của thư mục gốc và báo cáo các chữ cái trên các cạnh sẽ đến chúng.

O(|Σ|)

Xóa tiền tố

Lười cập nhật root. Đoàn kết tất cả con của root và đặt con trỏ gốc cho kết quả của sự hợp nhất này. Lười cập nhật root mới.

O(|Σ|)

Kiên trì

O(1)O(|Σ|)O(logN)N

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.