Cách tốt nhất để theo dõi trung vị là gì?


8

Tôi đã đọc một câu hỏi và tôi đang tìm kiếm đầu vào về cách giải quyết nó:

Các số được tạo ngẫu nhiên và được lưu trữ thành một mảng (mở rộng), Làm thế nào bạn theo dõi trung vị?

Có hai cấu trúc dữ liệu có thể giải quyết vấn đề. Một là cây nhị phân cân bằng, hai là hai đống giữ dấu vết của nửa lớn nhất và nửa nhỏ nhất của các phần tử. Tôi nghĩ rằng hai giải pháp này có cùng thời gian chạy O(n lg n), nhưng tôi không chắc về phán đoán của mình.

Cách tốt nhất để theo dõi trung vị là gì?

Nỗ lực của tôi:

Trong câu hỏi này Tôi nghĩ rằng một đống là cách tốt nhất để theo dõi trung vị. Có hai đống, đống lớn và đống nhỏ, không cần phải tuần tự. Đầu tiên, chúng tôi tính giá trị trung bình của các phần tử trong mảng. Nếu phần tử nhỏ hơn giá trị trung bình, chúng ta đặt num vào heap nhỏ. Ngược lại, chúng tôi đặt num vào đống lớn. Nếu số lượng của đống lớn bằng số lượng của đống nhỏ, thì cái lớn nhất trong đống nhỏ và cái nhỏ nhất trong đống lớn là trung vị. Nếu hai heap có kích thước khác nhau, chúng ta chỉ cần bật phần tử gốc từ heap với kích thước lớn hơn và đẩy nó vào phần gốc của heap kích thước nhỏ hơn. Đối với heap lớn, phần tử gốc là phần tử nhỏ nhất và đối với phần heap nhỏ, phần tử gốc là phần tử lớn nhất. Theo cách này, nếu hai đống có cùng kích thước hoặc chênh lệch kỹ thuật số,

Tôi nghĩ giải pháp này có thời gian chạy là O (m * n), m có nghĩa là thời gian chúng ta điều chỉnh các đống không cân bằng.

Đây có phải là cách tốt nhất để theo dõi trung vị?


Nếu bạn chỉ cần theo dõi trung vị, hai cái về cơ bản có cùng độ phức tạp, nhưng cách tiếp cận dựa trên heap sẽ sử dụng ít bộ nhớ hơn (cấu trúc của nó là ẩn thay vì yêu cầu con trỏ) và nói chung cũng nhanh hơn (vì nó thường được lưu trữ liền kề, thường sẽ cải thiện việc sử dụng bộ đệm).
Jerry Coffin

2
stackoverflow.com/questions/2579912/ sẽ là một giải pháp tuyến tính nếu bạn muốn.
JB King

2
Hehe - có std::nth_elementai không?
Billy ONeal

5
Điều này thực sự nghe giống như một câu hỏi cho SO hơn ở đây.
Đánh dấu B

Giá trị trung bình có thể rất lừa dối đến mức vô nghĩa. Chỉ cần chụp ảnh bạn có rất nhiều số nhỏ (giả sử 1..999) và 10 ^ 8. Giá trị trung bình của 1000 số đó là ~ 10 ^ 5, vì vậy bạn kết thúc bằng việc đặt mọi thứ trừ 10 ^ 8 vào đống nhỏ. Do đó, thuật toán có hành vi xấu nhất trong trường hợp xấu.
user281377

Câu trả lời:


1

Có lẽ có nhiều hơn 2 cấu trúc dữ liệu giải quyết vấn đề này. Hãy xem Trung bình gần đúng và các lượng tử khác trong một lần và với bộ nhớ hạn chế

Họ không sử dụng hai đống. Tôi tưởng tượng bạn có thể sửa đổi thuật toán của họ để định kỳ lấy giá trị trung bình đang chạy. Tất nhiên, một phép tính gần đúng tốt như thế nào, phụ thuộc vào nhiều yếu tố, chứ không phải ít nhất là số lượng dữ liệu đã truyền qua thuật toán.


0

Một giải pháp tốt hơn là sử dụng một danh sách bỏ qua. Vì danh sách mà bạn sẽ chèn luôn được duy trì dưới dạng danh sách được sắp xếp (theo thực tế cách bạn đang xây dựng nó), nên độ phức tạp của việc chèn là O (log n). Bạn sẽ được lợi dụng thực tế là chính lần chèn đầu tiên cung cấp cho bạn trung vị với chi phí bằng không (mục được chèn là trung vị). Sau mỗi lần chèn bổ sung, danh sách của bạn vẫn được sắp xếp và chính trung vị sẽ trôi lên hoặc xuống bởi một chỉ mục duy nhất và so sánh này là O (1).

Tổng độ phức tạp = O (log n)


Tổng độ phức tạp cho mỗi phần tửO(log n)- chèn n phần tử có độ phức tạp củaO(n log n)
Greg Jackson

1
Chắc chắn, nhưng đối với một "trung vị đang chạy", người ta có thể lập luận rằng bạn đang chèn một tập hợp các phần tử không bị ràng buộc, nhưng sẽ rất ít khi nói rằng độ phức tạp là O (log infinite log n). ;-)
Michael chào

Ơ ... ok, câu trả lời của tôi có thể không tốt hơn đống. Heap Fibonacci có chèn O (1) và xóa O (lg n). Tôi chưa bao giờ sử dụng nó.
Michael chào

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.