Tìm phần tử xảy ra nhiều nhất trong một tệp rất lớn


12

Tôi đã nghe câu hỏi phỏng vấn này hỏi rất nhiều và tôi hy vọng sẽ có một số ý kiến ​​về câu trả lời tốt có thể là gì: Bạn có một tệp lớn hơn 10 GB và bạn muốn tìm hiểu yếu tố nào xảy ra nhiều nhất, cách nào là tốt để làm điều này?

Lặp lại và theo dõi trong bản đồ có lẽ không phải là ý hay vì bạn sử dụng nhiều bộ nhớ và theo dõi khi các mục nhập không phải là lựa chọn tốt nhất kể từ khi câu hỏi này được đặt ra, tệp thường tồn tại.

Những suy nghĩ khác tôi đã bao gồm việc tách tệp sẽ được lặp đi lặp lại và xử lý bởi nhiều luồng và sau đó kết hợp những kết quả đó, nhưng vấn đề bộ nhớ cho các bản đồ vẫn còn đó.


2
Các yếu tố của tập tin là gì? Họ có dây không? Nếu bạn lấy các ký tự cho các phần tử, thì bản đồ sẽ không gặp vấn đề về bộ nhớ. Nếu các yếu tố là từ ngữ, thì một lần nữa tôi nghĩ nó sẽ không thành vấn đề. Nếu bạn có tất cả các chuỗi con có thể, thì bạn có thể gặp vấn đề ...
Nejc

1
Nếu điều kiện là "một phần tử xuất hiện hơn một nửa tổng số phần tử" thì đã có một giải pháp tuyến tính.
st0le

Tôi tin rằng các yếu tố thường là chuỗi. Nhưng tôi không thấy bản đồ không phải là vấn đề. Trong trường hợp xấu hơn khi mọi yếu tố là duy nhất, bạn có cần tăng gấp đôi yêu cầu bộ nhớ không?
Pat

1
Nếu thuật toán ứng cử viên đa số Boyer-Moore được áp dụng, nó chạy trong thời gian tuyến tính và tại chỗ.
Juho

Câu trả lời:


6

Khi bạn có một tệp thực sự lớn và có nhiều phần tử trong đó, nhưng phần tử phổ biến nhất là rất phổ biến - xảy ra phần thời gian - bạn có thể tìm thấy nó trong thời gian tuyến tính với các từ O ( k ) không gian ( hằng số trong ký hiệu O ( ) là rất nhỏ, về cơ bản là 2 nếu bạn không tính dung lượng lưu trữ cho những thứ phụ trợ như băm). Hơn nữa, điều này hoạt động rất tốt với bộ nhớ ngoài, vì tệp được xử lý theo thứ tự một phần tử tại một thời điểm và thuật toán không bao giờ "nhìn lại". Một cách để làm điều này là thông qua một thuật toán cổ điển của Misra và Gries, xem các ghi chú bài giảng này>1/kO(k)O(). Vấn đề bây giờ được gọi là vấn đề người nặng nề (yếu tố thường xuyên là người tuyệt vời nặng).

Giả định rằng phần tử thường xuyên nhất xuất hiện phần thời gian cho k một số nhỏ có vẻ mạnh nhưng đó là một cách cần thiết! Tức là nếu bạn sẽ có quyền truy cập tuần tự vào tệp của mình (và trong trường hợp tệp truy cập ngẫu nhiên rất lớn sẽ quá đắt), bất kỳ thuật toán nào luôn tìm thấy phần tử thường xuyên nhất trong số lượng vượt qua sẽ sử dụng tuyến tính không gian trong số phần tử . Vì vậy, nếu bạn không giả định điều gì đó về đầu vào, bạn không thể đánh bại bảng băm. Giả định rằng yếu tố thường xuyên nhất là rất thường xuyên có lẽ là cách tự nhiên nhất để có được xung quanh kết quả tiêu cực.>1/kk

Dưới đây là một bản phác thảo cho , tức là khi có một yếu tố duy nhất xảy ra hơn một nửa thời gian. Trường hợp đặc biệt này được gọi là thuật toán bỏ phiếu đa số và là do Boyer và Moore. Chúng tôi sẽ giữ một yếu tố duy nhất và một số lượng duy nhất. Khởi tạo số đếm thành 1 và lưu trữ phần tử đầu tiên của tệp. Sau đó xử lý tệp theo trình tự:k=2

  • nếu phần tử hiện tại của tệp giống với phần tử được lưu trữ, hãy tăng số lượng lên một
  • nếu phần tử hiện tại của tệp khác với phần tử được lưu trữ, hãy giảm số lượng một
  • nếu số lượng cập nhật là 0, hãy "loại bỏ" phần tử được lưu trữ và lưu trữ phần tử hiện tại của tệp; tăng số lượng lên 1
  • tiến hành phần tử tiếp theo của tập tin

Một chút suy nghĩ về thủ tục này sẽ thuyết phục bạn rằng nếu tồn tại phần tử "đa số", tức là phần tử xảy ra hơn một nửa thời gian, thì phần tử đó sẽ là phần tử được lưu trữ sau khi toàn bộ tệp được xử lý.

Đối với k chungkk1k1kk

Tất nhiên bạn có thể sử dụng bảng băm để lập chỉ mục k11/kO(k)

Một điều cuối cùng: sau khi bạn tìm thấy k1/kk1


Bạn không thể sử dụng thuật toán Boyer-Moore hoặc Misra-Gries-Demaine. Vấn đề như đã nêu là khác nhau: bạn không tìm kiếm phần tử đa số, nhưng đối với một phần tử có lần xuất hiện> = trong số lần xuất hiện của tất cả các phần tử. Đây là một ví dụ đơn giản. Gọi n là tổng số phần tử, sao cho n = 2k + 1 . Đặt các phần tử k đầu tiên là 0, các phần tử k tiếp theo là 1 và phần tử cuối cùng là 2. Thuật toán Boyer-Moore sẽ báo cáo phần tử cuối cùng, 2, là ứng cử viên đa số tiềm năng. Nhưng, trong trường hợp cụ thể này, đầu ra phải là 0 hoặc 1.
Massimo Cafaro

O(1)Ω(n)

Tôi đã chỉ ra rằng nếu bạn đưa ra một giả định sai, bạn có thể nhận được kết quả sai. Điều gì là tốt hơn, một dấu chân bộ nhớ nhỏ và một kết quả có khả năng không chính xác hoặc kết quả chính xác mặc dù nó làm bạn tốn thêm một số bộ nhớ? Nếu tôi phải chọn một kết quả có khả năng không chính xác, tôi sẽ sử dụng thuật toán ngẫu nhiên thay vì Boyer-Moore cho rằng điều gì đó tôi không biết nó thực sự đúng.
Massimo Cafaro

@MassimoCafaro không phải là một sự đánh đổi mà bạn cần phải thực hiện. như tôi đã chỉ ra một lần vượt qua tập tin dễ dàng xác minh nếu giả định được thỏa mãn!
Sasho Nikolov

@MassimoCafaro và đây chỉ là giải pháp tầm thường! giả định có thể được xác minh với xác suất cao với bản phác thảo CM không có thêm thông qua.
Sasho Nikolov

3

Câu trả lời rõ ràng là tất nhiên để giữ một bản đồ băm và lưu trữ một bộ đếm về sự xuất hiện của các yếu tố khi bạn di chuyển qua tệp như Nejc đã đề xuất. Đây là (về độ phức tạp thời gian) là giải pháp tối ưu.

Θ(nlogn).


Bạn có thể nói rõ hơn về phương pháp mã hóa Huffman? Tôi đã viết một bộ mã hóa Huffman trước đây nhưng đã được một lúc, chính xác thì bạn sẽ sử dụng nó như thế nào trong trường hợp này?
Pat

@Pat Đừng bao giờ nhắc rằng phần đó là quá sớm vào buổi sáng và bằng cách nào đó tôi nghĩ rằng nó sẽ có ý nghĩa để nén đầu vào.
Jernej

1

Nếu phần tử phổ biến nhất phổ biến hơn phần tử phổ biến tiếp theo bởi một mức đáng kể và số lượng phần tử khác nhau nhỏ so với kích thước tệp, bạn có thể lấy mẫu ngẫu nhiên một vài phần tử và trả về phần tử phổ biến nhất trong mẫu của bạn.


Hơn nữa, nếu có một số lượng nhỏ các yếu tố xảy ra nhiều lần, bạn có thể tìm thấy chúng bằng cách lấy mẫu, và sau đó chỉ đếm chính xác các yếu tố này.
Tối đa
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.