细节改善效率:判断STL序列容器是否为空

readme

判断一个STL容器是否为空,是十分常见的一种操作,常见的方法有两种,一种是判断container.size()是否为0,另一种是判断是否container.empty()。今天通过这篇博客对比一下这两种方式的效率。

两种容器区别

按照内存使用方式区可以将序列容器分为两种:连续内存容器;基于节点的容器。连续内存容器将所有的节点保存在一块连续的内存空间内,例如vector,string等等。基于节点的容器,每个节点保存在一块单独的内存内,例如list,slist等等。以下以vector和list为代表进行详细分析。
对于vector,empty()函数就是判断size()是否为0,二者做的事一样,而vector作为连续内存容器,size()函数复杂度常数。而对于list,empty()函数复杂度依然是常数,但是size()却不是,因为list容器中节点的个数必须通过遍历一遍才能知道。

测试程序

//common.h
#ifndef _COMMON_H_
#define _COMMON_H_

#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <utility>
#include <algorithm>
#include <vector>
#include <iterator>
#include <sys/time.h>

using namespace std;
#endif
//Timer.h
#ifndef _TIMER_H
#define _TIMER_H

#include <sys/time.h>
#include "common.h"

class Timer
{
public:
    Timer(string strCallInfo = "Timer", bool us_need = false)
    {
        _desc = strCallInfo;
        _us_need = us_need;
        gettimeofday(&_begin, NULL);
        gettimeofday(&_end, NULL);
    };

    ~Timer()
    {
        gettimeofday(&_end,NULL);
        printf("%s, cost %ldms\n", _desc.c_str(), (_end.tv_sec - _begin.tv_sec) * 1000 + (_end.tv_usec - _begin.tv_usec) / 1000);
        if (_us_need)
        {
            printf("%s, cost %ldus\n", _desc.c_str(), (_end.tv_sec - _begin.tv_sec) * 1000000 + _end.tv_usec - _begin.tv_usec);
        }
    };
private:
    Timer(){};
    string  _desc;
    bool _us_need;

    timeval _begin;
    timeval _end;
};

#endif

//empty_vs_size.cpp
#include "common.h"
#include "Timer.h"

const int list_size = 1000000;
list<int> test_list;
vector<int> test_vec;

int main(void)
{
    for (int i = 0; i < list_size; ++i)
    {
        test_list.push_back(i);
        test_vec.push_back(i);
    }

    {
        Timer timer("vector size() cost");
        for (int i = 0; i < 1024; ++i)
        {
            if (test_vec.size() == 0)
            { 
                continue;
            }
        }
    }

    {
        Timer timer("vector empty() cost");
        for (int i = 0; i < 1024; ++i)
        {
            if (test_vec.empty())
            { 
                continue;
            }
        }
    }

    {
        Timer timer("list size() cost");
        for (int i = 0; i < 1024; ++i)
        {
            if (test_list.size() == 0)
            { 
                continue;
            }
        }
    }

    {
        Timer timer("list empty() cost");
        for (int i = 0; i < 1024; ++i)
        {
            if (test_list.empty())
            { 
                continue;
            }
        }
    }
    return 0;
}

编译和执行结果

g++ -o empty_vs_size empty_vs_size.cpp -O0 -g -Wall -std=c++11
./empty_vs_size 
list size() cost, cost 6036ms
list empty() cost, cost 0ms
vector size() cost, cost 0ms
vector empty() cost, cost 0ms

g++ -o empty_vs_size empty_vs_size.cpp -O2 -g -Wall -std=c++11
./empty_vs_size 
list size() cost, cost 0ms
list empty() cost, cost 0ms
vector size() cost, cost 0ms
vector empty() cost, cost 0ms

测试程序解释

测试代码很简单,可以直观的从运行结果看到对于判断list是否为空而言,empty()效率要远好与size()。而对于判断vector是否为空而言,empty()和size()效率是一样的。
而对于不同的编译优化参数而言也有不同的测试结论。上述结论基于不进行任何编译后话的前提下,也即是g++ -O0。而对于适合上线的编译优化参数,例如g++ -O2,不管判断list是否为空还是判断vector是否为空,size()和empty()的效率都是一样的,至少未发现明显差距。对于编译器的优化行为,不在这边博客讨论范围内,不做进一步研究。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值