Delete operations for various containers in STL

Source: Internet
Author: User

In an application, it is often unavoidable to delete certain elements in the container. This does not seem to be a difficult problem. We first write a loop to iterate over the elements in the container, and if the iteration element is the element to be deleted, delete it. The code looks like this:

Vector<int> Intcontainer;  
..... 
for (Vector<int>::iterator is = Intcontainer.begin ();
        It! = Intcontainer.end ();
        ++it)  
{  
        if (*it = =)   
                    intcontainer.erase (it);  
}  

The original intent of writing this code is to remove the element with a value of 25 in the vector, but unfortunately it is wrong to do so, which leads to bizarre undefined behavior. Because when an element of a container is deleted, all iterators that point to that element are invalidated. When Intcontainer.erase (IT) returns, it has lapsed. What an unreliable thing it is to perform a self-increment operation for a failed it in the for loop. Since this does not work, we can resort to the remove algorithm provided by STL. Use the Remove algorithm to achieve the purpose of deleting elements.

Vector<int> Intcontainer;  
.....
size_t before_size = Intcontainer.size ();  
Remove (Intcontainer.begin (), Intcontainer.end (), +);  
size_t after_size = Intcontainer.size ();

Running the program later found that Before_size and After_size were the same, stating that the element was not actually deleted. The above procedure is written in the knowledge of the remove algorithm. The remove algorithm in the STL moves forward the element that should not be deleted, and then returns an iterator that points to the element that should be deleted, that's all. So if you want to really delete this element, you must also call erase after you call remove, which is the idiom for the "erase_remove" of the STL container element deletion.

Vector<int> Intcontainer;  
.....
Intcontainer.erase (Remove (Intcontainer.begin (),
            intcontainer.end (), +),
        intcontainer.end ());

Erase-remove's idiom applies to contiguous memory containers, such as Vector,deque and string, and it applies To list, but it's not our recommended method because using the list member function, remove, is more efficient, and the code is as follows:

List<int> List_int;  
 ....  
 List_int.remove (25);  

If it's an associative container. The Standard association container does not have a remove member function and is compiled with the Remove function of the STL algorithm. Therefore, the Remove form above does not apply to standard associative containers. In this case, the workaround is to call erase:

Map<int, int> Mapcontainer;  
...  
Mapcontainer.erase (25);  

For standard associative containers, this method of deleting elements is simple and effective, with a time complexity of O (Logn).

When we need to delete an element that is not an element, but one that has a certain condition, we just need to replace remove with remove_if.

BOOL Is2beremove (int value)  
{  
        return value <;  
}  
Vector<int> Nvec;  
List<int> nList;  
....  

Nvec.erase (Remove_if (Nvec.begin (), Nvec.end (), is2beremove),
        nvec.end ());  
Nlist.remove_if (Is2beremove);

Summarize The following to delete the element with a specific value in the container:

If the container is a vector, string, or deque, use the Erase-remove idiom. If the container is a list, use List::remove. If the container is a standard associative container, use its erase member function. Delete elements in the container that meet certain conditions:

If the container is a vector, string, or deque, use the erase-remove_if idiom. If the container is a list, use list::remove_if. If the container is a standard associative container, use the Remove_copy_if&swap combination algorithm, or design a traversal delete algorithm yourself.

Focus on the following content, after learning aoj0121 thoughts

The Remove function of the STL and the Remove member function of the list

If you read a book today, just record it. This may be a cliché, right vote as an example of alertness.

We all know that STL has two very important components, containers and algorithms.

An algorithm is a function that is associated with an iterator and a container to accomplish some work.

The separation of the algorithm and the container provides a lot of flexibility for the program design, but it also brings some negative effects, and this is an example of the problem I'm talking about here.

The STL algorithm has a remove function, and the list itself has a remove function, the function is the same, remove an element, then we should use which one.

Take a look at the following procedure

<span style= "FONT-SIZE:14PX;" >list<int> numbers;

    for (int number = 0; number <= 6; number + +) {
        Numbers.push_front (number);
        Numbers.push_back (number);
    }

    Copy (Numbers.begin (), Numbers.end (),
            ostream_iterator<int> (cout, ""));
    cout << Endl;

    Remove algorithm is remove element but not erase the element from container
    //It'll return the logical Desinat Ion of container
    list<int>::iterator endofnumbers = Remove (Numbers.begin (), Numbers.end (), 3);

    Copy (Numbers.begin (), Numbers.end (),
            ostream_iterator<int> (cout, ""));
    cout << endl;</span>

What is the output?

The first line must be 6 5 4 3 2 1 0 0 1 2 3 4 5 6, then the second row outputs what.

If you have not read the STL carefully, you will certainly think that remove (Number.begin (), Numbers.end (), 3) removes all elements with a value of 3. So the output is: 6 5 4 2 1 0 0 1 2 4 5 6.

However, let's look at its true output:

6 5 4 2 1 0 0 1 2 4 5 6 5 6

You might be surprised why you'll end up with 5 and 62 more numbers.

Let's take a look at the principle of the remove algorithm.

The Remove algorithm does not directly delete the element, but instead uses the following element instead of the previous element, which means that if I remove 2 from the 1234 sequence, the returned sequence is 1344 (3 is copied to 2, 4 is copied to 3).

So the above example would explain that the two 3 elements are not removed, but instead overwrite the previous elements with the elements that follow . The extra two numbers were not removed.

So how do we really get the removal done? The Remove function returns an iterator that is the logical end of the sequence, which is the endofnumbers in my code, which points to the second 5 on the bottom.

So we're going to use the erase function of list to complete the removal of elements

Numbers.erase (Endofnumbers, Numbers.end ());

So we finished our work, a little bit of twists and turns ...

In fact, we can put these two steps together, for example, if I want to then remove all elements with a value of 2

Numbers.erase (Remove (Numbers.begin (), Numbers.end (), 2), Numbers.end ());

So we can one step.

But this is good.

Not good.

As you'll see, the Remove function works by copying rather than moving the pointer (because the function is manipulating an iterator and the C + + iterator does not have a delete operation defined), which brings up the problem: we use list because it's very efficient to modify, so change the pointer. And here we copy the elements, if in the vector, it might be efficient, because vectors are copied anyway, and for list is not so, it will greatly reduce our efficiency.

So what do we do?

The answer is to use list's own remove function

Numbers.remove (1);

We can delete all elements that have a value of 1.

That is, if you want to delete the elements in the list, we should use the list's remove member function instead of the remove algorithm.

Summary

As we all know, STL is a product of efficiency, reusability, flexibility compromise, in which efficiency is essential, so the STL has banned some inefficient operations (such as list random access) and encouraged you to use other containers.

However, in the algorithm, for flexibility, STL still sacrifices something , such as our example.

Personally, STL as an integral part of the C + + standard library, features and C + + itself is identical, powerful and complex, some places difficult to understand, a lot of details need to learn to pay attention to, we have to learn to avoid falling into some traps, such as this example is an efficiency trap.

Other pitfalls are error handling, and the STL itself does not prescribe too much error handling, and most of the error handling is given to us for simple reasons: performance is paramount , and if a thing has no error checking itself, we can wrap a class with error checking But if this thing has its own error-checking, then there is no way to improve its efficiency. This is also a design principle for many C and C + + libraries.

So, most of the time, we need to go into the details and then decide what to do. Because C + + is the case: there are many ways to go, we need to choose the best way for ourselves.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.