2012-05-19 47 views
33

Để tìm giá trị trung bình của mảng chưa được phân loại, chúng ta có thể tạo một thời gian tối thiểu trong thời gian O (nlogn) cho n phần tử và sau đó chúng ta có thể trích xuất từng phần tử n/2 trung vị. Nhưng cách tiếp cận này sẽ mất thời gian O (nlogn).Tìm giá trị trung bình của mảng chưa phân loại

Chúng ta có thể thực hiện tương tự bằng một số phương pháp trong thời gian O (n) không? Nếu có thể, hãy nói hoặc đề nghị một số phương pháp.

+0

bản sao có thể có của [Cách tìm phần tử lớn nhất thứ k trong một mảng chiều dài không được sắp xếp n trong O (n)?] (Http: // stackoverflow .com/questions/251781/how-to-find-the-kth-lớn nhất-yếu tố-in-an-unsorted-array-of-length-n-in-on) –

+7

Hãy nhớ rằng nếu nó có O (nlogn) thì bạn cũng có thể sắp xếp mảng và chia chỉ mục bằng 2. – Zombies

+2

heap xây dựng mất O (n) thời gian không phải O (nlogn) – JerryGoyal

Trả lời

31

Bạn có thể sử dụng thuật toán Median of Medians để tìm trung vị của một mảng chưa được phân loại theo thời gian tuyến tính.

+0

Đó là gần đúng nhưng nên hoạt động khá tốt. –

+7

@KevinKostlan Nó thực sự không phải là gần đúng, đó là trung bình thực sự và nó tìm thấy nó trong thời gian tuyến tính.Lưu ý rằng sau khi tìm thấy trung vị của các trung vị (được đảm bảo lớn hơn ít nhất 30% các phần tử và nhỏ hơn ít nhất 30% các phần tử), bạn phân chia mảng bằng cách sử dụng trục xoay đó. Sau đó, bạn recurse (nếu cần thiết) vào một trong những mảng đó là nhiều nhất là 70 70 kích thước của mảng ban đầu để tìm trung thực sự (hoặc trong trường hợp chung là k-thống kê). – dcmm88

10

Quickselect hoạt động trong O (n), điều này cũng được sử dụng trong bước phân vùng của Quicksort.

+4

Tôi không nghĩ quickselect sẽ nhất thiết phải cung cấp cho các trung bình trong ONLY ONE chạy. Nó phụ thuộc vào sự lựa chọn của bạn. – Yashasvi

+0

Thật không may, chọn nhanh để tìm trung bình sẽ có O (n^2) trong trường hợp xấu nhất. Điều này xảy ra khi chúng ta giảm mảng bằng chỉ 1 phần tử trong mỗi lần lặp của QuickSelect. Hãy xem xét một mảng đã được sắp xếp và chúng tôi luôn chọn đúng phần lớn nhất là trục xoay. Tôi biết điều này là hơi ngu ngốc để làm như vậy nhưng đây là trường hợp tồi tệ nhất. –

0

Có thể thực hiện bằng thuật toán Quickselect trong O (n), tham khảo số liệu thống kê thứ tự K (thuật toán ngẫu nhiên).

9

Thuật toán chọn nhanh có thể tìm phần tử nhỏ nhất thứ k của một mảng theo thời gian chạy tuyến tính (O(n)). Đây là một thực hiện trong python:

import random 

def partition(L, v): 
    smaller = [] 
    bigger = [] 
    for val in L: 
     if val < v: smaller += [val] 
     if val > v: bigger += [val] 
    return (smaller, [v], bigger) 

def top_k(L, k): 
    v = L[random.randrange(len(L))] 
    (left, middle, right) = partition(L, v) 
    # middle used below (in place of [v]) for clarity 
    if len(left) == k: return left 
    if len(left)+1 == k: return left + middle 
    if len(left) > k: return top_k(left, k) 
    return left + middle + top_k(right, k - len(left) - len(middle)) 

def median(L): 
    n = len(L) 
    l = top_k(L, n/2 + 1) 
    return max(l) 
0

Như wikipedia nói, trung bình-of-trung vị là về mặt lý thuyết o (N), nhưng nó không được sử dụng trong thực tế vì các nguyên cần thiết của việc tìm kiếm trụ "tốt" làm cho nó quá chậm .
http://en.wikipedia.org/wiki/Selection_algorithm

Đây là nguồn Java cho một thuật toán Quickselect để tìm các yếu tố k'th trong một mảng:

/** 
* Returns position of k'th largest element of sub-list. 
* 
* @param list list to search, whose sub-list may be shuffled before 
*   returning 
* @param lo first element of sub-list in list 
* @param hi just after last element of sub-list in list 
* @param k 
* @return position of k'th largest element of (possibly shuffled) sub-list. 
*/ 
static int select(double[] list, int lo, int hi, int k) { 
    int n = hi - lo; 
    if (n < 2) 
     return lo; 

    double pivot = list[lo + (k * 7919) % n]; // Pick a random pivot 

    // Triage list to [<pivot][=pivot][>pivot] 
    int nLess = 0, nSame = 0, nMore = 0; 
    int lo3 = lo; 
    int hi3 = hi; 
    while (lo3 < hi3) { 
     double e = list[lo3]; 
     int cmp = compare(e, pivot); 
     if (cmp < 0) { 
      nLess++; 
      lo3++; 
     } else if (cmp > 0) { 
      swap(list, lo3, --hi3); 
      if (nSame > 0) 
       swap(list, hi3, hi3 + nSame); 
      nMore++; 
     } else { 
      nSame++; 
      swap(list, lo3, --hi3); 
     } 
    } 
    assert (nSame > 0); 
    assert (nLess + nSame + nMore == n); 
    assert (list[lo + nLess] == pivot); 
    assert (list[hi - nMore - 1] == pivot); 
    if (k >= n - nMore) 
     return select(list, hi - nMore, hi, k - nLess - nSame); 
    else if (k < nLess) 
     return select(list, lo, lo + nLess, k); 
    return lo + k; 
} 

Tôi chưa bao gồm nguồn gốc của sự so sánh và trao đổi phương pháp, vì vậy nó dễ dàng để thay đổi mã để làm việc với Object [] thay vì double [].

Trong thực tế, bạn có thể mong đợi mã trên là o (N).

+1

swap ???????????????? – Bohdan

13

Tôi đã upvoted câu trả lời @dasblinkenlight vì thuật toán Median of Medians trong thực tế giải quyết được vấn đề này trong thời gian O (n). Tôi chỉ muốn thêm rằng vấn đề này có thể được giải quyết trong O (n) thời gian bằng cách sử dụng heaps cũng. Xây dựng một đống có thể được thực hiện trong thời gian O (n) bằng cách sử dụng từ dưới lên. Hãy xem bài viết sau đây để biết giải thích chi tiết Heap sort

Giả sử rằng mảng của bạn có N phần tử, bạn phải tạo hai vùng: MaxHeap chứa phần tử N/2 đầu tiên (hoặc (N/2) +1 nếu N là lẻ) và MinHeap chứa các phần tử còn lại. Nếu N là lẻ thì trung bình của bạn là phần tử tối đa của MaxHeap (O (1) bằng cách lấy giá trị cực đại). Nếu N là chẵn, thì trung bình của bạn là (MaxHeap.max() + MinHeap.min())/2 điều này cũng lấy O (1). Do đó, chi phí thực của toàn bộ hoạt động là hoạt động xây dựng heaps là O (n).

BTW Thuật toán MaxHeap/MinHeap này cũng hoạt động khi bạn không biết số phần tử mảng trước (nếu bạn phải giải quyết cùng một vấn đề cho luồng số nguyên ví dụ). Bạn có thể xem thêm chi tiết về cách giải quyết vấn đề này trong bài viết sau Median Of integer streams

+3

Tại sao tính năng này hoạt động? Giả sử mảng của bạn là [3, 2, 1]. Sau đó chúng tôi sẽ đặt 2 đầu tiên trong một vùng tối đa: [3, 2], do đó 3 sẽ là gốc, do đó, 2, con của nó phải nhỏ hơn nó. Và, chúng ta sẽ có [1] trong đống tối thiểu. Theo thuật toán này, chúng ta sẽ chọn tối đa (root), của maxHeap là trung bình của chúng ta. Điều này sẽ không cho chúng ta 3? – Arkidillo

+0

Đó là trường hợp xấu hơn O (n^2), không phải O (n). Khi đề cập đến độ phức tạp của Big O của thuật toán, mà không chỉ rõ trường hợp, nó thường được giả định rằng bạn đang đề cập đến thời gian tồi tệ hơn. – Rick

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