1. 程式人生 > >set、vector與list的構造與排序的耗時測試

set、vector與list的構造與排序的耗時測試

隨機數 rand mem while += 賦值 ring alt 個數

測試目標

測試在成員個數不斷遞增的情況下,set、vector與list的構造與排序的耗時變化,找出set耗時連續超過其他容器耗時的成員個數


測試方式

  • set使用直接插入

  • vector使用assign構造並使用全局sort排序

  • list使用assign構造與成員sort的排序之間

  • 比較的是耗時時間大小,對耗時的具體值不關心,因為不同的機器配置不一樣


測試結論

由於設定的連續超過次數不同,得到的成員個數值也不同,並且隨著連續超過上限的增加而增加,因此現在得到的成員個數值並不準確,如:

在連續超過上限為10時,成員個數最大在700左右

在連續超過上限為20時,成員個數最大在2000左右

但有一點可以肯定:set的邊插入邊排序效率,沒有vector與list的賦值或排序高,如果有海量數據排序的情況,用vector或list的賦值後排序的性能相對於set比較好。


測試代碼

// 主邏輯 main.cpp
#include "TimeConsume.h"
#include "Random.h"
#include <unistd.h>
#include <vector>
#include <list>
#include <set>
#include <algorithm>
#include <iostream>
#include <cstdint>
#include <string>
using namespace std;

// set耗時是否連續超出其他容器
bool is_continue_beyond(uint64_t vector_time, uint64_t list_time, uint64_t set_time, uint64_t beyond_num) {
    static uint64_t s_beyond_num = beyond_num; 
    if (set_time > list_time && set_time > vector_time) {
	--s_beyond_num;
    } else {
	s_beyond_num = beyond_num;
    }

    return s_beyond_num == 0;
}

int main(int argc, char** argv) {

    uint64_t member_count_num = 0;
    uint64_t member_add_num = 0;
    uint64_t beyond_num = 0;
    if (argc != 4) {
	cout << "input: " << argv[0] << " member_start_num member_add_num beyond_num" << endl;
	return -1;
    } else {
	member_count_num = strtoull(argv[1], NULL, 10);
	member_add_num = strtoull(argv[2], NULL, 10);
	beyond_num = strtoull(argv[3], NULL, 10);
    }

    uint64_t vector_time = 0;
    uint64_t list_time   = 0;
    uint64_t set_time    = 0;

    while (!is_continue_beyond(vector_time, list_time, set_time, beyond_num)) {
	vector<uint64_t > input_random_num; // 使用一樣的隨機數據
	Random random;
	random.SetRandomNum<vector<uint64_t> >(member_count_num, input_random_num);

	// 構造排序函數
	vector<uint64_t> monitor_vector; // 外部定義容器,防止構造析構帶來的時間計算
	auto vector_sort = [&]() {
	    monitor_vector.assign(input_random_num.begin(), input_random_num.end());
	    sort(monitor_vector.begin(), monitor_vector.end());
	};

	list<uint64_t> monitor_list;
	auto list_sort = [&]() {
	    monitor_list.assign(input_random_num.begin(), input_random_num.end());
	    monitor_list.sort();
	};

	set<uint64_t> monitor_set;
	auto set_sort = [&](){
	    monitor_set.insert(input_random_num.begin(), input_random_num.end());
	};

	// 統計排序時間
        TimeConsume vector_time_consume(vector_sort);
        TimeConsume list_time_consume(list_sort);
        TimeConsume set_time_consume(set_sort);

	vector_time = vector_time_consume.GetFnTime();
	list_time = list_time_consume.GetFnTime();
	set_time = set_time_consume.GetFnTime();

	cout << "count:" << member_count_num<< "\t" << "vector_time:" << vector_time << "\t" << "list_time:" << list_time << "\t" << "set_time:" << set_time << endl;
	sleep(0.5);
	member_count_num += member_add_num;
    }
    return 0;
}
/*
TimeConsume.h
用於獲得程序運行的時間消耗,支持函數對象(C++11新標準)
獲得的耗時為微秒級
*/
#ifndef TIME_CONSUME_H
#define TIME_CONSUME_H

#include <sys/time.h>
#include <ctime>
#include <functional>
using std::function;

#define SEC_RATIO_MSEC 1000
#define SEC_RATIO_USEC (1000*SEC_RATIO_MSEC)

class TimeConsume {
public:
    TimeConsume(const function<void()> &monitor_fn = [](){;})
	: m_monitor_fn(monitor_fn) {
	    Clear();
    }

    ~TimeConsume()
    {;}

    // 設置耗時監控的函數對象
    inline function<void()> SetMonitorFn(const function<void()> &monitor_fn()) {
    	auto old_monitor_fn = m_monitor_fn;
    	m_monitor_fn = monitor_fn;
    	return old_monitor_fn;
    }

    // 記錄開始監控的時間點
    inline void Start() {
	    gettimeofday(&m_start, NULL);
    }
    
    // 記錄結束監控的時間點
    inline void End() {
	    gettimeofday(&m_end, NULL);
    }

    // 依據開始和結束監控的時間點,得到微秒級耗時
    inline uint64_t GetIntervalTime() {
    	if ((m_end.tv_sec > m_start.tv_sec)
    	    || (m_end.tv_sec == m_start.tv_sec && m_end.tv_usec >= m_start.tv_usec)) {
    	    return (m_end.tv_sec - m_start.tv_sec)*SEC_RATIO_USEC + (m_end.tv_usec - m_start.tv_usec); 
    	} else {
    	    return 0;
    	}
    }

    // 獲得監控函數對象的微秒級運行耗時
    inline uint64_t GetFnTime() {
        Clear();
    	Start();
    	m_monitor_fn();
    	End();
    	return GetIntervalTime();
    }

protected:
    // 格式化內部相關值
    inline void Clear() {
    	m_start.tv_sec = 0;
    	m_start.tv_usec = 0;
    	m_end.tv_sec = 0;
    	m_end.tv_usec = 0;
    }

private:
    struct timeval m_start;
    struct timeval m_end;
    function<void()> m_monitor_fn;
};
#endif
/*
Random.h
可以向STL 容器裏填充指定個數的隨機值,取值範圍在[0-RAND_MAX],RAND_MAX為最大值的整數常量表達式。此值依賴實現。保證此值至少為32767
*/
#ifndef RANDOM_H
#define RANDOM_H

#include <ctime>
#include <iterator>
using std::inserter;

class Random {
public:
    Random() {
	srand(time(NULL));
    }

    ~Random()
    {;}

    template <typename  ContainerT>
    inline void SetRandomNum(uint64_t count, ContainerT &container) {
	auto iter = inserter(container, container.end());
	for (uint64_t i = 0; i < count; ++i) {
	    iter = rand();
	}
    }
};

如果對測試有什麽疑問或建議,歡迎大家來討論

set、vector與list的構造與排序的耗時測試