2011-01-13 30 views
14

Cụ thể: đưa ra một băm (hoặc một chỉ số mảng), làm thế nào để máy nhận được dữ liệu trong thời gian không đổi?Bản đồ mảng và bản đồ băm liên tục trong thời gian truy cập của chúng như thế nào?

Dường như với tôi rằng thậm chí đi qua tất cả các vị trí bộ nhớ khác (hoặc bất kỳ thứ gì) sẽ mất một khoảng thời gian bằng số lượng vị trí đã qua (do đó thời gian tuyến tính). Một đồng nghiệp đã cố gắng dũng cảm để giải thích điều này với tôi nhưng phải từ bỏ khi chúng tôi đi xuống mạch.

Ví dụ:

my_array = new array(:size => 20) 
my_array[20] = "foo" 
my_array[20] # "foo" 

Tiếp cận của "foo" ở vị trí 20 là hằng số vì chúng tôi biết rằng những xô "foo" là như thế nào chúng tôi một cách kỳ diệu có được để xô mà không đi qua tất cả những người khác trên đường. ? Để đến nhà số 20 trên một khối, bạn sẽ vẫn phải vượt qua số 19 khác ...

+1

Bạn biết làm thế nào đĩa đĩa cứng quay xung quanh và xung quanh? Vâng, RAM không di chuyển ;-) –

+0

Nó sẽ là không đổi nếu bạn ngay lập tức có thể nhảy đến nhà # 20. Đó là cách hoạt động của RAM. Truy cập ngẫu nhiên so với truy cập tuần tự. Trong trường hợp này, ngẫu nhiên có nghĩa là bạn có thể đọc từ bất kỳ vị trí bộ nhớ "ngẫu nhiên" nào mà không phải đọc bộ nhớ trước đó. Cũng vậy với văn bản. – SRM

Trả lời

17

Làm cách nào chúng tôi kỳ diệu nhận được rằng xô mà không vượt qua tất cả những người khác trên đường?

"Chúng tôi" không "chuyển sang thùng. Cách RAM hoạt động thể chất giống như phát sóng số của nhóm trên một kênh mà tất cả các nhóm nghe và một số có số được gọi sẽ gửi cho bạn nội dung của nó.

Tính toán xảy ra trong CPU. Về lý thuyết, CPU là cùng một "khoảng cách" từ tất cả các vị trí bộ nhớ (trong thực tế nó không phải, vì bộ nhớ đệm, mà có thể có một tác động rất lớn về hiệu suất).

Nếu bạn muốn biết chi tiết về chi tiết, hãy đọc "What every programmer should know about memory".

+1

Liên kết rất thú vị, cảm ơn! – keithcelt

10

Sau đó, để hiểu bạn phải xem cách tổ chức và truy cập bộ nhớ. Bạn có thể phải xem cách hoạt động của address decoder. Vấn đề là, bạn KHÔNG phải đi qua tất cả các địa chỉ khác để đến địa chỉ bạn muốn trong bộ nhớ. Bạn thực sự có thể nhảy đến cái bạn muốn. Nếu không, máy tính của chúng tôi sẽ thực sự rất chậm.

+0

nhưng trong trường hợp của một hashmap, làm thế nào để bạn biết mà muốn bạn cần phải đi đến? Ý tôi là, nếu tôi có một bản đồ ánh xạ chuỗi thành int, và tôi muốn truy cập my_map ["dog"], làm sao tôi biết được chỉ mục nào của mảng kết hợp mà tôi cần phải đi? – seb

+0

Chìa khóa "chó" được băm để tạo ra một số nguyên là chỉ mục của giá trị trong bản đồ. –

6

Không giống như máy turing, bộ nhớ sẽ phải truy cập bộ nhớ tuần tự, máy tính sử dụng bộ nhớ truy cập ngẫu nhiên hoặc RAM, có nghĩa là nếu chúng biết mảng bắt đầu và họ biết chúng muốn truy cập phần tử thứ 20 của mảng biết phần nào của bộ nhớ để xem xét.

Nó ít giống như lái xe xuống một con phố và hơn thế nữa như chọn đúng vị trí thư cho căn hộ của bạn trong hộp thư dùng chung.

+0

Tốt tương tự ... –

+0

Tôi nghĩ về nó như đặt hàng một cuốn sách từ các ngăn xếp của thư viện trường đại học. Ai đó chịu trách nhiệm phân phối nó vào một thời điểm nhất định được quảng cáo bởi thư viện. Họ có thể hoặc không thể đi bộ dọc theo một hoặc nhiều hàng sách. Tôi khá chắc chắn rằng họ không nhất thiết phải đi qua tất cả các cuốn sách với một số danh mục giữa cuốn sách này, và cuốn sách trước đó tôi yêu cầu. Nhưng đây không phải là vấn đề của tôi, bởi vì ngay cả khi họ đi bộ dọc theo ngăn xếp, họ vẫn làm đủ nhanh để đưa sách của tôi đến phòng đọc trong một số chu kỳ CPU cố định, độc lập với số danh mục của nó. Xin lỗi, giờ. –

1

2 điều rất quan trọng:

  1. my_array có thông tin về nơi ở máy tính bộ nhớ phải nhảy để có được mảng này.
  2. chỉ mục * loại sizeof được bù trừ từ đầu mảng.

1 + 2 = O (1), nơi dữ liệu có thể được tìm thấy

-1

Big O không làm việc như thế. Nó được coi là một thước đo bao nhiêu tài nguyên tính toán được sử dụng bởi một thuật toán và chức năng cụ thể. Nó không có nghĩa là để đo lường số lượng bộ nhớ được sử dụng và nếu bạn đang nói về đi qua bộ nhớ đó, nó vẫn là một thời gian liên tục. Nếu tôi cần phải tìm khe thứ hai của một mảng thì đó là vấn đề bổ sung một bù đắp cho một con trỏ. Bây giờ, nếu tôi có một cấu trúc cây và tôi muốn tìm một nút cụ thể bạn đang nói về O (log n) bởi vì nó không tìm thấy nó trên pass đầu tiên. Trung bình phải mất O (log n) để tìm nút đó.

-1

Hãy thảo luận điều này trong các điều khoản C/C++; có một số công cụ bổ sung để biết về mảng C# nhưng nó không thực sự liên quan đến vấn đề này.

Với một loạt các giá trị số nguyên 16-bit:

short[5] myArray = {1,2,3,4,5}; 

gì thực sự xảy ra là máy tính đã phân bổ một khối không gian trong bộ nhớ. Khối bộ nhớ này được dành riêng cho mảng đó, chính xác là kích thước cần thiết để giữ mảng đầy đủ (trong trường hợp của chúng tôi 16 * 5 == 80 bit == 10 byte), và tiếp giáp. Những sự kiện này là givens; nếu có hoặc không có điều gì trong số đó là đúng trong môi trường của bạn tại bất kỳ thời điểm nào, bạn thường gặp rủi ro cho chương trình của bạn bị lỗi do truy cập một lần.

Vì vậy, với cấu trúc này, biến số myArray thực sự là, đằng sau hậu trường, là địa chỉ bộ nhớ của sự bắt đầu của khối bộ nhớ. Điều này cũng thuận tiện, sự khởi đầu của phần tử đầu tiên. Mỗi phần tử bổ sung được xếp hàng trong bộ nhớ ngay sau lần đầu tiên, theo thứ tự. Khối bộ nhớ phân bổ cho myArray có thể trông như thế này:

00000000000000010000000000000010000000000000001100000000000001000000000000000101 
^    ^   ^   ^   ^
myArray([0]) myArray[1]  myArray[2]  myArray[3]  myArray[4] 

Nó được coi là một hoạt động liên tục thời gian để truy cập vào một địa chỉ bộ nhớ và đọc một hằng số của byte. Như trong hình trên, bạn có thể lấy địa chỉ bộ nhớ cho mỗi thứ nếu bạn biết ba điều; sự bắt đầu của khối bộ nhớ, kích thước bộ nhớ của mỗi phần tử và chỉ mục của phần tử bạn muốn. Vì vậy, khi bạn yêu cầu myArray[3] trong mã của bạn, yêu cầu được trở thành một địa chỉ bộ nhớ bằng phương trình sau đây:

myArray[3] == &myArray+sizeof(short)*3; 

Như vậy, với một tính liên tục theo thời gian, bạn đã tìm thấy địa chỉ bộ nhớ của phần tử thứ tư (chỉ số 3), và với một hoạt động liên tục khác (hoặc ít nhất được xem như vậy; độ phức tạp truy cập thực tế là chi tiết phần cứng và đủ nhanh mà bạn không nên quan tâm), bạn có thể đọc bộ nhớ đó. Đây là, nếu bạn đã từng tự hỏi, tại sao các chỉ mục của các bộ sưu tập trong hầu hết các ngôn ngữ kiểu C bắt đầu từ số không; phần tử đầu tiên của mảng bắt đầu tại vị trí của mảng, không có offset (sizeof (bất cứ điều gì) * 0 == 0)

Trong C#, có hai sự khác biệt đáng chú ý. C# mảng có một số thông tin tiêu đề được sử dụng cho CLR. Header đến trước trong khối bộ nhớ, và kích thước của tiêu đề này là không đổi và được biết đến, vì vậy phương trình giải quyết chỉ có một sự khác biệt quan trọng:

myArray[3] == &myArray+headerSize+sizeof(short)*3; 

C# không cho phép bạn để tham khảo trực tiếp bộ nhớ trong quản lý của nó môi trường, nhưng bản thân thời gian chạy sẽ sử dụng một cái gì đó như thế này để thực hiện truy cập bộ nhớ ngoài heap. Một điều thứ hai, cũng phổ biến đối với hầu hết các hương vị của C/C++, là một số loại nhất định luôn được xử lý bằng "tham chiếu". Bất cứ điều gì bạn phải sử dụng từ khóa new để tạo là một kiểu tham chiếu (và có một số đối tượng, như chuỗi, cũng là kiểu tham chiếu mặc dù chúng trông giống như kiểu giá trị trong mã). Một kiểu tham chiếu, khi được khởi tạo, được đặt trong bộ nhớ, không di chuyển và thường không được sao chép. Bất kỳ biến đại diện cho đối tượng đó là như vậy, đằng sau hậu trường, chỉ là địa chỉ bộ nhớ của đối tượng trong bộ nhớ. Mảng là kiểu tham chiếu (nhớ myArray chỉ là một địa chỉ bộ nhớ). Mảng của các kiểu tham chiếu là các mảng của các địa chỉ bộ nhớ này, do đó truy cập một đối tượng là một phần tử trong một mảng là một quá trình gồm hai bước; đầu tiên bạn tính toán địa chỉ bộ nhớ của phần tử trong mảng và nhận được điều đó.Đó là một địa chỉ bộ nhớ khác, đó là vị trí của đối tượng thực tế (hoặc ít nhất là dữ liệu có thể thay đổi của nó; cách các kiểu hợp chất được cấu trúc trong bộ nhớ là toàn bộ các sâu khác có thể có). Đây vẫn là một hoạt động liên tục thời gian; chỉ cần hai bước thay vì một bước.

+0

Điều gì về mảng thưa thớt? Chúng có thể được truy cập trong thời gian không? – CoDEmanX

Các vấn đề liên quan