2013-08-11 47 views
7

Tôi đang cố gắng đưa ra một thuật toán dưới dạng một hàm chấp nhận hai tham số, một mảng và kích thước của mảng. Tôi muốn nó trả về chế độ của mảng và nếu có nhiều chế độ, hãy trả về giá trị trung bình của chúng. Chiến lược của tôi là lấy mảng và đầu tiên sắp xếp nó. Sau đó đếm tất cả các lần xuất hiện của một số. trong khi con số đó xảy ra, hãy thêm một số để đếm và lưu số đó trong một mảng m. Vì vậy, m đang giữ tất cả các số đếm và một mảng q khác đang giữ giá trị cuối cùng mà chúng ta so sánh.Thuật toán để tính toán chế độ

Ví dụ: là danh sách của tôi là {1, 1, 1, 1, 2, 2, 2} sau đó tôi sẽ phải m[0] = 4 q[0] = 1 and then m[1] = 3 and q[1] = 2.

để chế độ là q[0] = 1;

tiếc là tôi đã không thành công cho đến nay. hy vọng ai đó có thể giúp đỡ.

float mode(int x[],int n) 
{ 
    //Copy array and sort it 
    int y[n], temp, k = 0, counter = 0, m[n], q[n]; 

    for(int i = 0; i < n; i++) 
     y[i] = x[i]; 

    for(int pass = 0; pass < n - 1; pass++) 
     for(int pos = 0; pos < n; pos++) 
      if(y[pass] > y[pos]) { 
       temp = y[pass]; 
       y[pass] = y[pos]; 
       y[pos] = temp; 
      } 

    for(int i = 0; i < n;){ 
     for(int j = 0; j < n; j++){ 
      while(y[i] == y[j]) { 
       counter++; 
       i++; 
      } 
     } 
     m[k] = counter; 
     q[k] = y[i]; 
     i--; //i should be 1 less since it is referring to an array subscript 
     k++; 
     counter = 0; 
    } 

} 
+0

Bạn không trả lại bất cứ điều gì từ chức năng của bạn. Nó là khá không rõ ràng với tôi những gì bạn có nghĩa là với * chế độ * và/hoặc những gì kết quả của chức năng nên được. Nếu nó phải là trung bình của tất cả các giá trị, chỉ có thể 'trả về std :: tích lũy (x, x + n, 0,0)/n;'. BTW, C++ không có mảng có kích thước thay đổi. Tuy nhiên, bạn có thể sử dụng 'std :: vector y (n);' thay vào đó. –

+0

@ DietmarKühl Chức năng chưa hoàn thành. Theo chế độ tôi có nghĩa là giá trị xảy ra thường xuyên nhất trong mảng. Tôi không sử dụng một mảng có kích thước biến vì kích thước của mảng là tham số n. –

+0

Bạn có thể muốn xem 'std :: map' hoặc 'std :: unordered_map' để đếm số lần mỗi giá trị xuất hiện. Thay vào đó, thay vào đó, thay vào đó, hãy sử dụng tùy chọn Boost ['bimap'] (http://www.boost.org/doc/libs/release/libs/bimap/doc/html/index.html). –

Trả lời

4

Mặc dù bạn có một số câu trả lời tốt rồi, tôi quyết định gửi khác. Tôi không chắc nó có thực sự bổ sung thêm nhiều thứ mới hay không, nhưng tôi hoàn toàn không chắc chắn nó cũng vậy. Nếu không có gì khác, tôi chắc chắn nó sử dụng tiêu đề tiêu chuẩn hơn bất kỳ câu trả lời nào khác. :-)

#include <vector> 
#include <algorithm> 
#include <unordered_map> 
#include <map> 
#include <iostream> 
#include <utility> 
#include <functional> 
#include <numeric> 

int main() { 
    std::vector<int> inputs{ 1, 1, 1, 1, 2, 2, 2 }; 

    std::unordered_map<int, size_t> counts; 
    for (int i : inputs) 
     ++counts[i]; 

    std::multimap<size_t, int, std::greater<size_t> > inv; 
    for (auto p : counts) 
     inv.insert(std::make_pair(p.second, p.first)); 

    auto e = inv.upper_bound(inv.begin()->first); 

    double sum = std::accumulate(inv.begin(), 
     e, 
     0.0, 
     [](double a, std::pair<size_t, int> const &b) {return a + b.second; }); 

    std::cout << sum/std::distance(inv.begin(), e); 
} 

So với @ câu trả lời Dietmar, điều này cần được nhanh hơn nếu bạn có nhiều sự lặp lại trong các con số, nhưng ý chí của ông có thể được nhanh hơn nếu các con số là chủ yếu độc đáo.

+0

Rất đẹp. Một cải tiến nhỏ sẽ là thay thế đối số thứ 2 thành 'std :: accumulate()' bằng 'e' mà bạn đã tính toán. –

+0

@j_random_hacker: Rất tiếc - vâng, cảm ơn. Đã sửa. –

+0

@JerryCoffin Điều này rất ấn tượng! Bạn có thể đề xuất bất kỳ cuốn sách nào trên thư viện chuẩn không? Có vẻ như tôi có thể giải quyết rất nhiều vấn đề của tôi nếu có kiến ​​thức về các công cụ bạn đã sử dụng. Vấn đề là hầu hết các cuốn sách tôi đã gặp phải đọc giống như một tài liệu tham khảo hơn là một hướng dẫn. Tôi cần một cái gì đó mà sẽ cho tôi thực hành những công cụ này nhưng cũng giải thích những gì lớp của các vấn đề các công cụ này giải quyết và khi sử dụng chúng. Hãy cho tôi biết nếu bạn có bất cứ điều gì trong tâm trí! –

1

Đây là phiên bản làm việc của mã của bạn. m lưu trữ các giá trị trong mảng và q lưu trữ số đếm của chúng. Cuối cùng nó chạy qua tất cả các giá trị để có được số lượng tối đa, tổng của các chế độ và số lượng các chế độ riêng biệt.

float mode(int x[],int n) 
{ 
    //Copy array and sort it 
    int y[n], temp, j = 0, k = 0, m[n], q[n]; 

    for(int i = 0; i < n; i++) 
     y[i] = x[i]; 

    for(int pass = 0; pass < n - 1; pass++) 
     for(int pos = 0; pos < n; pos++) 
      if(y[pass] > y[pos]) { 
       temp = y[pass]; 
       y[pass] = y[pos]; 
       y[pos] = temp; 
      } 

    for(int i = 0; i < n;){ 
     j = i; 
     while (y[j] == y[i]) { 
      j++; 
     } 
     m[k] = y[i]; 
     q[k] = j - i; 
     k++; 
     i = j; 
    } 

    int max = 0; 
    int modes_count = 0; 
    int modes_sum = 0; 
    for (int i=0; i < k; i++) { 
     if (q[i] > max) { 
      max = q[i]; 
      modes_count = 1; 
      modes_sum = m[i]; 
     } else if (q[i] == max) { 
      modes_count += 1; 
      modes_sum += m[i]; 
     } 
    } 

    return modes_sum/modes_count; 
} 
2

Nếu bạn chỉ muốn đếm số lần xuất hiện sau đó tôi đề nghị bạn sử dụng một std::map hoặc std::unordered_map.

Nếu bạn đang lập bản đồ bộ đếm cho từng giá trị khác nhau, thì việc đếm số lần xuất hiện bằng cách sử dụng std::map là dễ dàng vì mỗi khóa chỉ có thể được chèn một lần. Để liệt kê các số riêng biệt trong danh sách của bạn, chỉ cần lặp qua bản đồ.

Dưới đây là một ví dụ về cách bạn có thể làm điều đó:

#include <cstddef> 
#include <map> 
#include <algorithm> 
#include <iostream> 

std::map<int, int> getOccurences(const int arr[], const std::size_t len) { 
    std::map<int, int> m; 
    for (std::size_t i = 0; i != len; ++i) { 
     m[arr[i]]++; 
    } 
    return m; 
} 

int main() { 
    int list[7]{1, 1, 1, 1, 2, 2, 2}; 
    auto occurences = getOccurences(list, 7); 
    for (auto e : occurences) { 
     std::cout << "Number " << e.first << " occurs "; 
     std::cout << e.second << " times" << std::endl; 
    } 
    auto average = std::accumulate(std::begin(list), std::end(list), 0.0)/7; 
    std::cout << "Average is " << average << std::endl; 
} 

Output:

Number 1 occurs 4 times 
Number 2 occurs 3 times 
Average is 1.42857 
3

Dựa trên những nhận xét, có vẻ như bạn cần phải tìm các giá trị đó xảy ra thường xuyên nhất và nếu có là nhiều giá trị xuất hiện cùng một lượng thời gian, bạn cần tạo ra mức trung bình của các giá trị này. Có vẻ như, điều này có thể dễ dàng được thực hiện bằng std::sort() sau bởi một phát hiện traversal nơi các giá trị thay đổi và giữ một vài đếm chạy:

template <int Size> 
double mode(int const (&x)[Size]) { 
    std::vector<int> tmp(x, x + Size); 
    std::sort(tmp.begin(), tmp.end()); 
    int size(0); // size of the largest set so far 
    int count(0); // number of largest sets 
    double sum(0); // sum of largest sets 
    for (auto it(tmp.begin()); it != tmp.end();) { 
     auto end(std::upper_bound(it, tmp.end(), *it)); 
     if (size == std::distance(it, end)) { 
      sum += *it; 
      ++count; 
     } 
     else if (size < std::distance(it, end)) { 
      size = std::distance(it, end); 
      sum = *it; 
      count = 1; 
     } 
     it = end; 
    } 
    return sum/count; 
} 
+0

Tôi biết thật khủng khiếp khi nghĩ về nó ngay bây giờ, nhưng bạn thực sự chỉ sử dụng giới hạn trên, vì vậy 'upper_bound' có lẽ phù hợp hơn. Xin lỗi tôi đã không đọc kỹ hơn lần đầu tiên. –

+0

@JerryCoffin: Bạn nói đúng và tôi nên chú ý đến bản thân mình. Điều đó nói rằng, việc sử dụng 'std :: find_if()' sẽ tạo ra một thuật toán tuyến tính cho đường truyền sau 'std :: sort()' trong khi sử dụng 'std :: equal_range()' hoặc 'std :: upper_bound() 'kết quả trong hành vi trường hợp xấu nhất' O (n log n) '. Tất nhiên, 'std :: sort()' đã là 'O (n)' nghĩa là độ phức tạp tổng thể không tệ hơn. –

+0

Câu hỏi cơ bản là liệu bạn có muốn thấy một giá trị riêng lẻ lặp lại nhiều hơn trung bình (N) lần. Nếu nó được lặp lại ít hơn log (N) lần, chúng ta có thể mong đợi ít so sánh hơn bằng cách sử dụng 'find_if'. Nếu nó lớn hơn log (N), chúng ta có thể mong đợi ít hơn với 'upper_bound'. –

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