2012-02-25 34 views
13

Tôi đang sử dụng một số lớp và một số phương thức tiện ích sử dụng std :: vector.cách nhanh để triển khai pop_front thành std :: vector

Bây giờ tôi cần phải sử dụng từng khung một phương thức pop_front - push_back trên một trong các lớp đó (nhưng chúng đều được liên kết và làm việc cùng nhau vì vậy tôi không thể thay đổi chỉ một).

Hầu hết các hoạt động được lặp qua tất cả các hoạt động của phần tử và push_back, vì vậy những gì tôi nên làm cho công việc tốt nhất là: dĩa kho lưu trữ của các lớp và tiện ích đó, lấy mẫu mọi thứ và sử dụng deque hoặc list.

Nhưng điều này có nghĩa là rất nhiều mã viết lại và rất nhiều thử nghiệm mà sẽ làm cho tôi bỏ lỡ thời hạn.

Vì vậy, tôi cần lời khuyên để viết một pop_front hiệu quả cho một vector kích thước tĩnh (kích thước sẽ không thay đổi).

Tôi đã tìm thấy một cách here:

template<typename T> 
void pop_front(std::vector<T>& vec) 
{ 
    vec.front() = vec.back(); 
    vec.pop_back(); 
    vec.front() = vec.back(); // but should this work? 
} 

Và ý tưởng khác nên là:

template<typename T> 
void pop_front(std::vector<T>& vec, already_allocated_vector vec1) 
{ 
    vec1.clear(); 
    copy(vec.begin(), vec.end()-1, vec1.begin()); 
    copy(vec1.begin(), vec1.end(), vec.begin()); 
} 

là gì nhanh hơn của hai giải pháp này? Bất kỳ giải pháp nào khác?

+0

Ý bạn là gì bởi "kích thước sẽ không thay đổi"? Sau khi thực hiện pop_front, vectơ sẽ có cùng kích thước như trước đây? Nếu vậy, liệu nguyên tố cuối cùng có phải là rác? –

+0

vectơ có cùng kích thước, bởi vì sau một cửa sổ bật lên, tôi đột nhiên nhấn mạnh. mỗi khung hình tôi tạo ra một cửa sổ pop và một push trong cùng một phương thức như vậy trước và sau phương thức này, vector có cùng kích thước – nkint

+4

Trước khi lo lắng về tốc độ, hãy lo lắng về ** độ chính xác **. Tất cả tốc độ trên thế giới có nghĩa là không có gì nếu kết quả bạn nhận được chỉ đơn giản là sai, và theo như tôi có thể nói, cả hai ứng cử viên của bạn là sai. Cái đầu tiên nên được đặt tên là 'pop_back_and_overwrite_front_with_penultimate', và cái thứ hai nên được đặt tên là' invoke_undefined_behavior_and_pop_back'. (Ghi vào 'vec1.begin()' là không xác định vì 'vec1' trống, bạn cần viết' vec1.resize (vec.size() - 1) 'thay vì' vec1.clear() '.) Khi tôi xử lý các hoạt động vectơ, đôi khi tôi vẽ một bức tranh. Có lẽ điều đó cũng sẽ giúp ích cho bạn. –

Trả lời

21

Tôi mong chờ:

template<typename T> 
void pop_front(std::vector<T>& vec) 
{ 
    assert(!vec.empty()); 
    vec.front() = std::move(vec.back()); 
    vec.pop_back(); 
} 

là cách hiệu quả nhất để làm điều này, nhưng nó không duy trì trật tự của các yếu tố trong vector.

Nếu bạn cần phải duy trì trật tự của các yếu tố còn lại trong vec, bạn có thể làm:

template<typename T> 
void pop_front(std::vector<T>& vec) 
{ 
    assert(!vec.empty()); 
    vec.erase(vec.begin()); 
} 

này sẽ có thời gian tuyến tính về số lượng các yếu tố trong vec, nhưng nó là tốt nhất bạn có thể làm mà không thay đổi cấu trúc dữ liệu của bạn.

Không có chức năng nào trong số này sẽ duy trì vector ở kích thước không đổi, vì hoạt động pop_front sẽ theo định nghĩa xóa phần tử khỏi vùng chứa.

+0

tôi cần thứ tự .. – nkint

+0

Tôi nghĩ rằng nó được giả định rằng thứ tự đã được bảo quản kể từ khi' std :: vector :: pop_back' giữ nguyên thứ tự . – HelloGoodbye

+0

không phải là tốt hơn để bao gồm 'vec.push_back (new_value) vec.shrink_to_fit()' sau? –

5

Kể từ pop_front() chỉ xóa phần tử đầu tiên, việc thực hiện trực tiếp là thế này:

template <typename V> 
void pop_front(V & v) 
{ 
    assert(!v.empty()); 
    v.erase(v.begin()); 
} 

Đừng lo lắng về tốc độ cho bây giờ. Nếu bạn muốn quay lại và tối ưu hóa mã, hãy yêu cầu thời gian dự án chuyên dụng.

+2

Điều này trông giống như một chức năng 'pop_everything_but_front' ... – Mankarse

+0

xin lỗi tôi không hiểu mã của bạn nó không chỉ keeo yếu tố đầu tiên? tôi chỉ muốn xóa phần tử đầu tiên, không nên là: v.erase (v.begin(), v.begin() + 1); ? – nkint

+0

@Mankarse: Yeah, d'oh! Cảm ơn! –

3

Bạn cũng có thể IgushArray (https://github.com/igushev/IgushArray) giống như một mảng có hoạt động truy cập liên tục thời gian nhanh, nhưng thao tác chèn/xóa chỉ mất thời gian O (N^1/2). Vì vậy, trong trường hợp của bạn chèn vào đầu sẽ rất hiệu quả ở đây. Hãy cẩn thận, cấu trúc rất nhạy cảm với dự trữ().

template <class T> 
void pop_front(IgushArray<T>& v) 
{ 
    if (!v.empty()) 
    v.erase(v.begin()); 
} 

Trong tùy chọn đầu tiên bạn viết, bạn vi phạm thứ tự các phần tử. Nó là một vấn đề?

Nếu có, hãy sử dụng biến thể tôi đã viết.

Nếu không và thứ tự các phần tử không quan trọng chút nào, có thể tốt hơn nên sử dụng std :: set or std :: multiset.

1

nếu bạn chỉ cố gắng để xóa phần tử đầu tiên sau đó trong chức năng sử dụng:

if (my_vector.size()){ //check if there any elements in the vector array 
    my_vector.erase(my_vector.begin()); //erase the firs element 
} 

nếu bạn muốn cạnh tranh trước pop cho toàn bộ mảng vector (bạn muốn giữ pop ra mọi phần tử từ đầu đến cuối), tôi đề xuất trên:

reverse(my_vector.begin(),my_vector.end()); // reverse the order of the vector array 
my_vector.pop_back(); // now just simple pop_back will give you the results 
Các vấn đề liên quan