Tiết kiệm khi khởi tạo mảng


19

Gần đây tôi đã đọc rằng có thể có các mảng không cần khởi tạo, nghĩa là có thể sử dụng chúng mà không phải mất thời gian cố gắng đặt từng thành viên về giá trị mặc định. tức là bạn có thể bắt đầu sử dụng mảng như thể nó đã được khởi tạo bởi giá trị mặc định mà không phải khởi tạo nó. (Xin lỗi, tôi không nhớ tôi đã đọc nó ở đâu).

Ví dụ như tại sao điều đó có thể gây ngạc nhiên:

Giả sử bạn đang cố gắng mô hình hóa trường hợp xấu nhất hashtable (cho mỗi lần chèn / xóa / tìm kiếm) của các số nguyên trong phạm vi [ 1 , n 2 ] .O(1)[1,n2]

Bạn có thể phân bổ một mảng có kích thước bit và sử dụng các bit riêng lẻ để thể hiện sự tồn tại của một số nguyên trong hàm băm. Lưu ý: phân bổ bộ nhớ được coi là O ( 1 ) thời gian.n2O(1)

Bây giờ, nếu bạn hoàn toàn không phải khởi tạo mảng này, bất kỳ chuỗi thao tác nói trên hàm băm này bây giờ là trường hợp xấu nhất O ( n ) .nO(n)

Vì vậy, trong thực tế, bạn có một triển khai băm "hoàn hảo", cho một chuỗi hoạt động sử dụng không gian Θ ( n 2 ) , nhưng chạy trong thời gian O ( n ) !nΘ(n2)O(n)

Thông thường người ta sẽ mong đợi thời gian chạy của bạn ít nhất là tồi tệ như việc sử dụng không gian của bạn!

Lưu ý: Ví dụ trên có thể được sử dụng để triển khai một tập hợp thưa hoặc ma trận thưa thớt, vì vậy nó không chỉ là lợi ích lý thuyết, tôi cho rằng.

Vì vậy, câu hỏi là:

Làm thế nào có thể có một mảng như cấu trúc dữ liệu cho phép chúng ta bỏ qua bước khởi tạo?


@Aryabhata Tài liệu tham khảo bạn đề cập là gì?
uli

1
"Sử dụng bộ nhớ" không giống như "đã phân bổ nhưng không bao giờ truy cập bộ nhớ", do đó tôi nghĩ rằng "nghịch lý" thúc đẩy không hoàn toàn tồn tại.
Raphael

1
Tôi nghĩ rằng đoạn đầu tiên khá rõ ràng: có một giá trị mặc định, mà không thực sự dành thời gian để điền vào mảng với giá trị mặc định. Câu trả lời, trong trường hợp người khác có thời gian viết nó trước khi tôi làm, thì đây là scholar.google.co.uk/. Có một lời giải thích rất ngắn gọn trên blog của tôi rgrig.blogspot.co.uk/2008/12/array -puheads-Solution.html
rgrig

@uli: Đây là một câu hỏi hạt giống, tôi thực sự đọc nó một thời gian dài trở lại.
Aryabhata

@Raphael: Vẫn còn ngạc nhiên khi bạn nghe về một điều như vậy lần đầu tiên. Hầu hết các nghịch lý không phải là :-)
Aryabhata

Câu trả lời:


15

Đây là một mẹo rất chung chung, có thể được sử dụng cho các mục đích khác ngoài băm. Dưới đây tôi đưa ra một triển khai (bằng mã giả).

Đặt ba vectơ chưa khởi tạo , PV có kích thước n mỗi cạnh. Chúng tôi sẽ sử dụng chúng để thực hiện các hoạt động theo yêu cầu của cấu trúc dữ liệu của chúng tôi. Chúng tôi cũng duy trì một biến p o s . Các hoạt động được thực hiện như sau:APVnpos

init:
  pos <- 0

set(i,x):
if not(V[i] < pos and P[V[i]] = i) 
  V[i] <- pos, P[pos] <- i, pos <- pos + 1
A[i] <- x

get(i):
if (V[i] < pos and P[V[i]] = i) 
  return A[i] 
else 
  return empty 

Mảng chỉ lưu trữ các giá trị được truyền qua thủ tục s e t . Các mảng VP hoạt động như các chứng chỉ có thể cho biết nếu một vị trí nhất định trong A đã được khởi tạo.AsetVPA

Lưu ý rằng tại mọi thời điểm, các phần tử trong nằm trong khoảng từ 0 đến p o s - 1 được khởi tạo. Do đó chúng tôi có thể sử dụng một cách an toàn các giá trị như một giấy chứng nhận cho các giá trị khởi tạo trong Một . Với mỗi vị trí i trong A được khởi tạo, có một phần tử tương ứng trong vectơ P có giá trị bằng i . Điều này được chỉ ra bởi V [ i ] . Do đó, nếu chúng ta nhìn vào phần tử tương ứng, P [ V [ i ] ] và giá trị của nó là iP0pos1AiAPiV[i]P[V[i]]i, chúng tôi biết rằng đã được khởi tạo (vì P không bao giờ nói dối, vì tất cả các yếu tố mà chúng tôi đang xem xét đều được khởi tạo). Tương tự, nếu A [ i ] không được khởi tạo, thì V [ i ] có thể trỏ đến một vị trí trong P ngoài phạm vi 0 .. p o s - 1 , khi chúng tôi biết chắc chắn rằng nó không được khởi tạo hoặc có thể trỏ đến một vị trí trong phạm vi đó. Nhưng P [ j ] đặc biệt này tương ứng với một vị trí khác trong A , và do đóA[i]PA[i]V[i]P0..pos1P[j]A , vì vậy chúng tôi biết rằng A [ i ] chưa được khởi tạo.P[j]iA[i]

Thật dễ dàng để thấy rằng tất cả các hoạt động này được thực hiện trong thời gian liên tục. Ngoài ra, không gian được sử dụng là cho mỗi vectơ và O ( 1 ) cho biến p o s , do đó tổng O ( n ) .O(n)O(1)posO(n)


P[V[i]]iA[i]

Đó là nhưng sau đó pos sẽ nhỏ hơn V [i] bây giờ phải không? Vì nếu không thì sẽ không có cơ hội. Vì có pos cao hơn V [i], điều đó có nghĩa là chúng tôi đã đặt cụ thể giá trị của P tại chỉ số V [i] thành một giá trị cụ thể mà chúng tôi đã chọn, cụ thể là i.
sói

Lưu ý rằng đây là một ví dụ cổ điển về những điều không thể thực hiện trong (di động) C.
TLW
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.