Duy trì việc đặt hàng hiệu quả trong đó bạn có thể chèn các phần tử vào giữa hai bất kỳ yếu tố nào khác trong đơn hàng?


8

Hãy tưởng tượng tôi có một thứ tự trên một loạt các yếu tố như vậy:

nhập mô tả hình ảnh ở đây

Trong đó một mũi tên có nghĩa là X < Y . Nó cũng là bắc cầu: ( X < Y )( Y < Z )XYX<Y .(X<Y)(Y<Z)(X<Z)

Để trả lời hiệu quả các truy vấn như , một số loại nhãn hoặc cấu trúc dữ liệu là bắt buộc. Ví dụ: bạn có thể đánh số các nút từ trái sang phải và do đó bạn có thể chỉ cần so sánh số nguyên để trả lời truy vấn: A ? < DMột<?D . Nó sẽ trông giống như thế này:Một<?D1<4T

nhập mô tả hình ảnh ở đây

Trong đó số là thứ tự, và chữ cái chỉ là một cái tên.

Nhưng điều gì sẽ xảy ra nếu bạn cần chèn các phần tử "ở giữa" hai phần tử khác theo thứ tự, như vậy:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Làm thế nào bạn có thể duy trì một thứ tự như vậy? Với cách đánh số đơn giản, bạn gặp phải vấn đề là không có số nguyên "ở giữa" để sử dụng.2,3

Câu trả lời:


7

Điều này được gọi là vấn đề "bảo trì trật tự" . Có một giải pháp tương đối đơn giản sử dụng thời gian khấu hao cho cả truy vấn và chèn. Bây giờ, bằng cách "tương đối đơn giản", ý tôi là bạn phải hiểu một số khối xây dựng, nhưng một khi bạn có được những thứ đó, phần còn lại không khó để nhìn thấy.Ôi(1)

http://cifts.csail.mit.edu/6.851/spring12/lectures/L08.html

Ý tưởng cơ bản là cấu trúc dữ liệu hai cấp. Cấp cao nhất giống như giải pháp cây AVL của Realz Slaw, nhưng

  • Các nút được gắn nhãn trực tiếp với các chuỗi bit có độ dài với thứ tự khớp với thứ tự của chúng trong cây. So sánh như vậy mất thời gian không đổiÔi(lgn)

  • Một cây có số vòng quay ít hơn cây AVL được sử dụng, như cây vật tế thần hoặc cây cân bằng trọng lượng, do đó việc tái định cư xảy ra ít thường xuyên hơn.

Tầng dưới cùng là lá của cây. Mức đó sử dụng cùng độ dài của nhãn, , nhưng chỉ giữ các mục O ( lg n ) trong mỗi lá trong một danh sách được liên kết đơn giản. Điều này cung cấp cho bạn đủ bit bổ sung để tích cực lại.Ôi(lgn)Ôi(lgn)

Lá nhận được tất cả quá lớn hay quá nhỏ chèn, gây ra một sự thay đổi ở cấp cao nhất, trong đó có O ( lg n ) khấu hao theo thời gian ( Ω ( n ) thời gian trường hợp xấu nhất). Khấu hao, đây chỉ là O ( 1 )Ôi(lgn)Ôi(lgn)Ω(n)Ôi(1) .

Các cấu trúc phức tạp hơn tồn tại để thực hiện cập nhật trong thời gian trường hợp xấu nhất .Ôi(1)


7

Thay vì đánh số đơn giản, bạn có thể trải đều các số trên một phạm vi lớn (kích thước không đổi), chẳng hạn như tối thiểu số nguyên và tối đa của một số nguyên CPU. Sau đó, bạn có thể tiếp tục đặt các số "ở giữa" bằng cách lấy trung bình hai số xung quanh. Nếu các số trở nên quá đông (ví dụ: bạn kết thúc với hai số nguyên liền kề và không có số nào ở giữa), bạn có thể thực hiện đánh số lại một lần cho toàn bộ đơn hàng, phân phối lại các số theo phạm vi.

Tất nhiên, bạn có thể chạy vào giới hạn rằng tất cả các số trong phạm vi của hằng số lớn được sử dụng. Thứ nhất, đây thường không phải là vấn đề, vì kích thước số nguyên trên máy đủ lớn để nếu bạn có nhiều yếu tố hơn thì có thể nó sẽ không phù hợp với bộ nhớ. Nhưng nếu đó là một vấn đề, bạn chỉ cần đánh số lại chúng với phạm vi số nguyên lớn hơn.

Nếu thứ tự đầu vào không phải là bệnh lý, phương pháp này có thể khấu hao số lần gia hạn.

Trả lời câu hỏi

Một so sánh số nguyên đơn giản có thể trả lời truy vấn .(X<?Y)

Ôi(1)Ôi(đăng nhập|Tôinteger|)

Chèn

Ôi(1)

Ôi(1)Ôi(n)

Tránh đánh số lại

Bạn có thể sử dụng số float thay cho số nguyên, vì vậy khi bạn nhận được hai số nguyên "liền kề", chúng có thể được tính trung bình. Do đó, bạn có thể tránh đánh số lại khi phải đối mặt với hai số nguyên: chỉ cần chia chúng làm đôi. Tuy nhiên, cuối cùng loại dấu phẩy động sẽ hết độ chính xác và hai phao "liền kề" sẽ không thể tính trung bình (trung bình của các số xung quanh có thể sẽ bằng một trong các số xung quanh).

Bạn có thể sử dụng tương tự số nguyên "vị trí thập phân", trong đó bạn duy trì hai số nguyên cho một phần tử; một cho số và một cho số thập phân. Bằng cách này, bạn có thể tránh đánh số lại. Tuy nhiên, số nguyên thập phân cuối cùng sẽ tràn.

Sử dụng danh sách các số nguyên hoặc bit cho mỗi nhãn hoàn toàn có thể tránh việc đánh số lại; điều này về cơ bản tương đương với việc sử dụng các số thập phân với độ dài không giới hạn. So sánh sẽ được thực hiện theo từ vựng và thời gian so sánh sẽ tăng theo chiều dài của danh sách liên quan. Tuy nhiên, điều này có thể làm mất cân bằng việc ghi nhãn; một số nhãn có thể chỉ yêu cầu một số nguyên (không có số thập phân), một số nhãn khác có thể có một danh sách dài (số thập phân dài). Đây là một vấn đề và việc đánh số lại cũng có thể giúp ích ở đây, bằng cách phân phối lại cách đánh số (ở đây liệt kê các số) trên một phạm vi đã chọn (phạm vi ở đây có thể có nghĩa là độ dài của danh sách) để sau khi đánh số lại, các danh sách đều có cùng độ dài .


Phương pháp này thực sự được sử dụng trong thuật toán này ( triển khai , cấu trúc dữ liệu có liên quan ); trong quá trình thuật toán, một thứ tự tùy ý phải được giữ và tác giả sử dụng số nguyên và đánh số lại để thực hiện điều này.


Cố gắng bám vào các con số làm cho không gian chính của bạn bị hạn chế phần nào. Thay vào đó, người ta có thể sử dụng các chuỗi có độ dài thay đổi, sử dụng logic so sánh "a" <"ab" <"b". Vẫn còn hai vấn đề cần giải quyết A. Các khóa có thể trở nên dài tùy ý B. So sánh các khóa dài có thể trở nên tốn kém


3

Bạn có thể duy trì cây AVL không có khóa hoặc tương tự.

Nó sẽ hoạt động như sau: Cây duy trì một trật tự trên các nút giống như cây AVL thường làm, nhưng thay vì khóa xác định nút "nên" nằm ở đâu, không có khóa và bạn phải chèn rõ ràng các nút "sau "Một nút khác (hay nói cách khác" ở giữa "hai nút), trong đó" sau "có nghĩa là nó xuất hiện sau nút theo thứ tự theo thứ tự của cây. Do đó, cây sẽ duy trì trật tự cho bạn một cách tự nhiên và nó cũng sẽ cân bằng, do các phép quay được tích hợp sẵn của AVL. Điều này sẽ giữ cho mọi thứ được phân phối tự động.

Chèn

Ôi(1)

Ôi(đăng nhậpn)

Trả lời câu hỏi

(X<?Y)XY

Ôi(đăng nhậpn)Ôi(1)Ôi(đăng nhậpn)Ôi(đăng nhậpn)Ôi(1)

Trình diễn thao tác chèn

Để chứng minh, bạn có thể chèn một số yếu tố theo thứ tự của chúng từ danh sách trong câu hỏi:

Bước 1

D

Danh sách:

liệt kê bước 1

Cây:

cây bước 1

Bước 2

C<C<D

Danh sách:

liệt kê bước 2

Cây:

cây bước 2

CDC<D

Bước 3

Một<Một<C

Danh sách:

liệt kê bước 3

Cây:

cây bước 3 trước khi luân chuyển

Xoay AVL:

cây bước 3 sau khi luân chuyển

Bước 4

BMột<B<C

Danh sách:

liệt kê bước 4

Cây:

cây bước 4

Không cần quay.

Bước 5

ED<E<

Danh sách:

liệt kê bước 5

Cây:

cây bước 5

Bước 6

FB<F<C

BBFB

Danh sách:

liệt kê bước 6

Cây:

cây bước 6 trước khi luân chuyển

Xoay AVL:

cây bước 6 sau khi luân chuyển

Trình diễn hoạt động so sánh

Một<?F

ancestors(A) = [C,B]
ancestors(F) = [C,B]
last_common_ancestor = B
B.left = A
B.right = F
... A < F #left is less than right

D<?F

ancestors(D) = [C]
ancestors(F) = [C,B]
last_common_ancestor = C
C.left = D
C.right = B #next ancestor for F is to the right
... D < F #left is less than right

B<?Một

ancestors(B) = [C]
ancestors(A) = [B,C]
last_common_ancestor = B
B.left = A
... A < B #left is always less than parent

Nguồn đồ thị


@saadtaame đã sửa và thêm nguồn tệp chấm ở phía dưới. Cảm ơn đã chỉ ra điều này.
Realz Slaw
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.