简体   繁体   中英

array, std::list, std::vector inserting time

I am making a test program to measure time for storage of each container. The following is my code for the test.

#include <list>
#include <vector>
#include <iostream>
#include <iomanip>
#include <string>
#include <ctime>
#include <cstdlib>
using namespace std;

void insert(list<short>& l, const short& value);
void insert(vector<short>& v, const short& value);
void insert(short arr[], int& logicalSize, const int& physicalSize, const short& value);

int main() {
    clock_t start, end;
    srand(time(nullptr));

    const int SIZE = 50000;
    const short RANGE = 10000;
    list<short> l;
    vector<short> v;
    short* arr = new short[SIZE];
    int logicalSize = 0;

    // array
    start = clock();
    cout << "Array storage time test...";
    for (int i = 0; i < SIZE; i++) {
        try {
            insert(arr, logicalSize, SIZE, (short)(rand() % (2 * RANGE + 1) - RANGE));
        } catch (string s) {
            cout << s << endl;
            system("pause");
            exit(-1);
        }
    }
    end = clock();
    cout << "Time: " << difftime(end, start) << endl << endl;

    // list
    cout << "List storage time test...";
    start = clock();
    for (int i = 0; i < SIZE; i++) {
        insert(l, (short)(rand() % (2 * RANGE + 1) - RANGE));
    }
    end = clock();
    cout << "Time: " << difftime(end, start) << endl << endl;

    // vector
    cout << "Vector storage time test...";
    start = clock();
    for (int i = 0; i < SIZE; i++) {
        insert(v, (short)(rand() % (2 * RANGE + 1) - RANGE));
    }
    end = clock();
    cout << "Time: " << difftime(end, start) << endl << endl;



    delete[] arr;
    system("pause");
    return 0;
}

void insert(list<short>& l, const short& value) {
    for (auto it = l.begin(); it != l.end(); it++) {
        if (value < *it) {
            l.insert(it, value);
            return;
        }
    }
    l.push_back(value);
}

void insert(vector<short>& v, const short& value) {
    for (auto it = v.begin(); it != v.end(); it++) {
        if (value < *it) {
            v.insert(it, value);
            return;
        }
    }
    v.push_back(value);
}

void insert(short arr[], int& logicalSize, const int& physicalSize, const short& value) {
    if (logicalSize == physicalSize) throw string("No spaces in array.");
    for (int i = 0; i < logicalSize; i++) {
        if (value < arr[i]) {
            for (int j = logicalSize - 1; j >= i; j--) {
                arr[j + 1] = arr[j];
            }
            arr[i] = value;
            logicalSize++;
            return;
        }
    }
    arr[logicalSize] = value;
    logicalSize++;
}

However, when I execute the code, the result seems a little different from the theory. The list should be fastest, but the result said that insertion in the list is slowest. Can you tell me why?

Inserting into a vector or array requires moving everything after it; so if at a random spot, requires an average of 1.5 accesses to each element. 0.5 to find the spot, and 0.5*2 (read and write) to do the insert.

Inserting into a list requires 0.5 accesses per element (to find the spot).

This means the vector is only 3 times more element accesses.

Lists nodes are 5 to 9 times larger than vector "nodes" (which are just elements). Forward iteration requires reading 3 to 5 times as much memory (element 16 bits and pointer 32 to 64 bits).

So the list solution reads/writes more memory! Worse, it is sparser (with the back pointer), and it may not be arranged in a cache-friendly way in memory (vectors are contiguous; list nodes may be a mess in linear space) thus messing with cpu memory cache predictions and loads and etc.

List is very rarely faster than vector; you have to be inserting/deleting many times more often than you iterate over the list.

Finally vector uses exponential allocation with reserved unused space. List allocates each time. Calling new is slow, and often not much slower when you ask for bigger chunks than when you ask for smaller ones. Growing a vector by 1 at a time 1000 times results in about 15 allocations (give or take); for list, 1000 allocations.

Insertion in a list is blisteringly fast, but first you have to find there you want to insert. This is where list comes out a loser.

It might be helpful to stop and read Why is it faster to process a sorted array than an unsorted array? sometime around now because it covers similar material and covers it really well.

With a vector or array each element comes one after the next. Prediction is dead easy, so the CPU can be loading the cache with values you won't need for a while at the same time as it is processing the current value.

With a list predictability is shot, you have to get the next node before you can load the node after that, and that pretty much nullifies the cache. Without the cache you can see an order of magnitude degradation in performance as the CPU sits around waiting for data to be retrieved from RAM.

Bjarne Stroustrup has a number of longer pieces on this topic . The keynote video is definitely worth watching.

One important take-away is take Big-O notation with a grain of salt because it is measuring a the efficiency of the algorithm, not how well the algorithm takes advantage of the hardware.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM