Tôi có một std :: vector <int> và tôi muốn xóa phần tử thứ n. Làm thế nào để làm điều đó?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Tôi có một std :: vector <int> và tôi muốn xóa phần tử thứ n. Làm thế nào để làm điều đó?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Câu trả lời:
Để xóa một yếu tố, bạn có thể làm:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);
Hoặc, để xóa nhiều phần tử cùng một lúc:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);
operator+
là không nhất thiết phải định nghĩa cho vòng lặp trên các loại thùng chứa khác, như list<T>::iterator
(bạn không thể làm list.begin() + 2
trên một std::list
, bạn phải sử dụng std::advance
cho điều đó)
std::find_if
Phương thức xóa trên std :: vector bị quá tải, vì vậy có thể gọi nó rõ ràng hơn
vec.erase(vec.begin() + index);
khi bạn chỉ muốn xóa một yếu tố duy nhất.
vec.begin()
được giá trị nào là hợp lệ.
vec.erase(0)
nó không hoạt động, nhưng vec.erase(vec.begin()+0)
(hoặc không có +0) thì không.
vec.erase(0)
thực sự có thể biên dịch nếu 0
tình cờ được hiểu là hằng số con trỏ null ...
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
Tôi không nói là tốt hơn, chỉ hỏi về lợi ích cá nhân và trả lại kết quả tốt nhất mà câu hỏi này có thể nhận được.
vector<T>::iterator
là một trình vòng lặp truy cập ngẫu nhiên, phiên bản của bạn vẫn ổn và có thể rõ ràng hơn một chút. Nhưng phiên bản mà Max đã đăng sẽ hoạt động tốt nếu bạn thay đổi vùng chứa sang một phiên bản khác không hỗ trợ các trình vòng lặp truy cập ngẫu nhiên
Các erase
phương pháp sẽ được sử dụng theo hai cách:
Xóa phần tử đơn:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
Xóa phạm vi của các yếu tố:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
Trên thực tế, erase
chức năng hoạt động cho hai hồ sơ:
Loại bỏ một yếu tố
iterator erase (iterator position);
Loại bỏ một loạt các yếu tố
iterator erase (iterator first, iterator last);
Vì std :: vec.begin () đánh dấu sự khởi đầu của container và nếu chúng ta muốn xóa phần tử thứ i trong vector của mình, chúng ta có thể sử dụng:
vec.erase(vec.begin() + index);
Nếu bạn nhìn kỹ, vec.begin () chỉ là một con trỏ đến vị trí bắt đầu của vectơ của chúng ta và thêm giá trị của i vào nó sẽ tăng con trỏ đến vị trí i, vì vậy thay vào đó chúng ta có thể truy cập con trỏ đến phần tử thứ i bằng cách:
&vec[i]
Vì vậy, chúng tôi có thể viết:
vec.erase(&vec[i]); // To delete the ith element
Nếu bạn có một vectơ không có thứ tự, bạn có thể tận dụng thực tế là nó không có thứ tự và sử dụng thứ tôi thấy từ Dan Higgins tại CPPCON
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
Vì thứ tự danh sách không thành vấn đề, chỉ cần lấy phần tử cuối cùng trong danh sách và sao chép nó lên trên cùng của mục bạn muốn xóa, sau đó bật và xóa mục cuối cùng.
iterator + index
sẽ thực sự đưa bạn trở lại vị trí lặp ở chỉ số đó, điều này không đúng với tất cả các container lặp. Nó cũng phức tạp liên tục thay vì tuyến tính bằng cách tận dụng con trỏ trở lại.
unordered_remove
và unordered_remove_if
trừ khi nó đã xảy ra và tôi đã bỏ lỡ nó, điều này xảy ra ngày càng thường xuyên hơn trong những ngày này :)
std::remove
sắp xếp lại vùng chứa sao cho tất cả các thành phần cần loại bỏ ở cuối, không cần thực hiện thủ công như thế này nếu bạn đang sử dụng C ++ 17.
std::remove
giúp thế nào? cppreference tuyên bố rằng ngay cả trong C ++ 17, tất cả các remove
tình trạng quá tải đều yêu cầu một vị từ và không có chỉ số nào.
Nếu bạn làm việc với các vectơ lớn (kích thước> 100.000) và muốn xóa nhiều phần tử, tôi khuyên bạn nên làm một cái gì đó như thế này:
int main(int argc, char** argv) {
vector <int> vec;
vector <int> vec2;
for (int i = 0; i < 20000000; i++){
vec.push_back(i);}
for (int i = 0; i < vec.size(); i++)
{
if(vec.at(i) %3 != 0)
vec2.push_back(i);
}
vec = vec2;
cout << vec.size() << endl;
}
Mã này lấy mỗi số trong vec không thể chia cho 3 và sao chép nó vào vec2. Sau đó, nó sao chép vec2 trong vec. Nó là khá nhanh. Để xử lý 20.000.000 phần tử, thuật toán này chỉ mất 0,8 giây!
Tôi đã làm điều tương tự với phương pháp xóa, và nó mất rất nhiều thời gian:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
Để xóa một phần tử, sử dụng cách sau:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
Để có cái nhìn tổng quan rộng hơn, bạn có thể truy cập: http://www.cplusplus.com/reference/vector/vector/erase/
Tôi đề nghị đọc nó vì tôi tin rằng đó là những gì bạn đang tìm kiếm. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Nếu bạn sử dụng ví dụ
vec.erase(vec.begin() + 1, vec.begin() + 3);
bạn sẽ xóa phần tử thứ n của vectơ nhưng khi bạn xóa phần tử thứ hai, tất cả các phần tử khác của vectơ sẽ bị dịch chuyển và kích thước vectơ sẽ là -1. Đây có thể là vấn đề nếu bạn lặp qua vectơ vì kích thước vectơ () đang giảm. Nếu bạn gặp vấn đề như liên kết được cung cấp này, hãy đề xuất sử dụng thuật toán hiện có trong thư viện C ++ tiêu chuẩn. và "xóa" hoặc "remove_if".
Hy vọng rằng điều này đã giúp
Các câu trả lời trước cho rằng bạn luôn có một chỉ mục được ký. Đáng buồn thay, std::vector
sử dụng size_type
để lập chỉ mục, vàdifference_type
cho số học lặp, vì vậy chúng không hoạt động cùng nhau nếu bạn bật "-Wconversion" và bạn bè được bật. Đây là một cách khác để trả lời câu hỏi, trong khi có thể xử lý cả ký và không dấu:
Để xóa:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
Để:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}
Đây là một cách khác để làm điều này nếu bạn muốn xóa một phần tử bằng cách tìm giá trị này với giá trị của nó trong vector, bạn chỉ cần thực hiện điều này trên vector.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
nó sẽ loại bỏ giá trị của bạn từ đây. cảm ơn
cách nhanh nhất (đối với các cuộc thi lập trình theo độ phức tạp thời gian () = hằng số)
có thể xóa mục 100M trong 1 giây;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
và cách dễ đọc nhất:
vec.erase(vec.begin() + pos);
vector<int>::iterator
không nhất thiết phải giống nhưint *