同vector一樣,list也是常用的一種STL容器。
list爲雙線列表,能夠快讀的插入和刪除元素,在實際項目中也是應用廣泛,但不支持隨機訪問,已有接口不夠豐富,或是缺少常用的接口,於是本文意在原list基礎上,改進或新增應用接口。
本文源碼見【完整代碼】章節,或GitHub:https://github.com/deargo/cpphelper。
list介紹
list 也是順序容器的一種,它是一個雙向鏈表(doubly-linked list)。
list將元素按順序存儲在鏈表中,表的每個元素中都有一個指針指向後一個元素,也有一個指針指向前一個元素,如下圖所示。
當然,list的用法和vector很類似,也擁有順序容器中的常用方法,但需要注意的是,list不支持使用下標隨機存取元素。
在 list 容器中,在已經定位到要增刪元素的位置的情況下,只需修改幾個指針而已,增刪元素能在常數時間內完成。如下圖所示,在 ai 和 ai+1 之間插入一個元素,只需要修改 ai 和 ai+1 中的指針即可:
所以它和向量(vector)相比,能夠快速的插入和刪除,但是,隨機訪問卻比較慢。
接口改進
list的許多函數,其用法都與 vector 類似,除了順序容器都有的成員函數外,還獨有push_front、pop_front、sort、remove、unique、merge、splice等接口,這給我們提供了遍歷,但部分接口不夠豐富,需要拓展。
由於自身結構的問題,list不支持隨機訪問,所以不支持隨機訪問迭代器,不支持下標操作符 [ ]、at等隨機訪問接口。雖然隨機訪問不夠效率,代價大,但還是不免使用到這種場景,需要新增。
完整代碼
本文源碼見【完整代碼】章節,或GitHub:https://github.com/deargo/cpphelper。
#pragma once
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
#include <list>
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
#include <assert.h>
namespace CppHelper
{
template<class Type , class Alloc = std::allocator<Type> >
class CList : public std::list<Type,Alloc>{
using StdList = std::list<Type,Alloc>;
public:
explicit CList(const Alloc& alloc = Alloc()):StdList(alloc) {} //默認構造函數
explicit CList(typename CList::size_type n, const Type& val = Type(), const Alloc& alloc = Alloc()):StdList(n,val,alloc){} //容量構造函數
CList(CList&& other):StdList(std::forward<CList>(other)){ } //拷貝構造函數
CList(const std::list<Type,Alloc>& vec){ StdList::assign(vec.begin(), vec.end()); } //可用std::list初始化
template <class InitIterator> //可用迭代器初始化
CList (InitIterator first, InitIterator last, const Alloc& alloc = Alloc()):StdList(first,last,alloc){}
explicit CList(const std::set<Type>& set){ StdList::assign(set.begin(), set.end()); } //可用std::set初始化
explicit CList(const std::vector<Type>& vec){ StdList::assign(vec.begin(), vec.end()); } //可用std::vector初始化
public:
operator std::list<Type,Alloc>(){ return *this; } //類型轉換函數,可直接轉換爲std::list
bool operator == (const CList& other) const{ return StdList::size()==other.size() && std::equal(StdList::begin(),StdList::end(),other.begin()); }
bool operator !=(const CList& other) const { return StdList::size()!=other.size() || false == std::equal(StdList::begin(),StdList::end(),other.begin()); }
Type& operator [](typename CList::size_type index){ assert(index<StdList::size()); typename CList::iterator it = CList::begin(); while(index--) ++it; return *it; }
const Type& operator [](typename CList::size_type index) const { assert(index<StdList::size());typename CList::const_iterator it = CList::begin(); while(index--) ++it; return *it; }
CList& operator =(const CList& other){StdList::assign(other.begin(), other.end()); return *this;} //賦值構造函數
CList& operator +(const CList& other){ push_back(other); return *this; }
CList& operator +=(Type&& value){ push_back(std::forward<Type>(value)); return *this; }
CList& operator +=(const CList& other){ push_back(other); return *this; }
CList& operator<<(Type&& value){ push_back(std::forward<Type>(value)); return *this; }
CList& operator<<(const CList& other){ push_back(other); return *this; }
CList& operator<<(const std::set<Type>& set){ push_back(set); return *this; }
CList& operator<<(const std::vector<Type>& vec){ push_back(vec); return *this; }
public:
void append(Type&& value){ push_back(std::forward<Type>(value)); }
void append(const CList& other){ push_back(other); }
void append(const std::set<Type>& set){ push_back(set); }
void append(const std::vector<Type>& vec){ push_back(vec); }
const Type& at(typename CList::size_type index) const{ return this->operator[](index); }
bool contains(Type&& value) const
{
return std::find(StdList::begin(), StdList::end(),std::forward<Type>(value)) != StdList::end();
}
template <class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
bool contains(Type&& value,CompareFunction compareFunction) const
{
return std::find_if(StdList::begin(), StdList::end(),
std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)))
!= StdList::end();
}
void copy(const CList& other){ CList::assign(other.begin(),other.end());}
void copy(typename CList::size_type n, Type&& value) {StdList::assign(n,std::forward<Type>(value));}
template <class CopyIterator>
void copy(CopyIterator first,CopyIterator last) { CList::assign(first,last); }
template <class CopyIterator, class Function>
void copy(CopyIterator first,CopyIterator last, Function func)
{
StdList::clear();
while (first!=last) {
if(func(*first))
{
StdList::emplace_back(*first);
}
++first;
}
}
template <class CopyIterator>
void copy(CopyIterator first, typename CList::size_type n)
{
StdList::clear();
while (n) {
StdList::emplace_back(*first);
--n;
++first;
}
}
typename CList::size_type count(Type&& value) const
{
return std::count(StdList::begin(), StdList::end(),std::forward<Type>(value));
}
template <class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
typename CList::size_type count(Type&& value,CompareFunction compareFunction) const
{
return std::count_if(StdList::begin(), StdList::end(),
std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)));
}
bool equal(const CList& other) const { return this->operator==(other); }
template <class CompareIterator>
bool equal(CompareIterator compareIterator) const
{
return std::equal(StdList::begin(),StdList::end(),compareIterator);
}
template <class CompareIterator, class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
bool equal(CompareIterator compareIterator,CompareFunction compareFunction) const
{
return std::equal(StdList::begin(),StdList::end(),compareIterator,compareFunction);
}
void fill(Type&& value, typename CList::iterator first=StdList::begin(), typename CList::iterator last=StdList::end()) { std::fill(first,last,std::forward<Type>(value)); }
void fill(typename CList::size_type n, Type&& value, typename CList::iterator first=StdList::begin()) { std::fill_n(first,n,std::forward<Type>(value)); }
typename CList::iterator find(Type&& value)
{
return std::find(StdList::begin(), StdList::end(),std::forward<Type>(value));
}
typename CList::const_iterator find(Type&& value) const
{
return std::find(StdList::begin(), StdList::end(),std::forward<Type>(value));
}
template <class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
typename CList::iterator find(Type&& value,CompareFunction compareFunction)
{
return std::find_if(StdList::begin(), StdList::end(),
std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)));
}
template <class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
typename CList::const_iterator find(Type&& value,CompareFunction compareFunction ) const
{
return std::find_if(StdList::begin(), StdList::end(),
std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)));
}
const Type& first() const{ return *StdList::begin(); }
template <class Function>
Function for_each(Function func){ return std::for_each(StdList::begin(), StdList::end(),func); }
int index(Type&& value) const {
for (int idx = 0; idx <(int)StdList::size();++idx){
if (this->operator[](idx)==std::forward<Type>(value)) return idx;
}
return -1;
}
template <class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
int index(Type&& value,CompareFunction compareFunction) const {
for (int idx = 0; idx <(int)StdList::size();++idx){
if (compareFunction(this->operator[](idx),std::forward<Type>(value))) return idx;
}
return -1;
}
void insert(typename CList::size_type index, Type&& value)
{
typename StdList::iterator it=StdList::begin();
while (index --) ++it;
StdList::insert(it, std::forward<Type>(value));
}
const Type& last() const{ return this->operator[](StdList::size() - 1); }
void prepend(Type&& value) { StdList::emplace(StdList::begin(), std::forward<Type>(value)); }
void push_back(Type&& value){ StdList::emplace_back(std::forward<Type>(value)); }
void push_back(const CList& other){ StdList::insert(StdList::end(),other.begin(),other.end());}
void push_back(const std::set<Type>& set){ StdList::insert(StdList::end(),set.begin(),set.end()); }
void push_back(const std::vector<Type>& vec){ StdList::insert(StdList::end(),vec.begin(),vec.end()); }
void push_front(Type&& value) { StdList::emplace(StdList::begin(), std::forward<Type>(value)); }
void remove(Type&& value) { StdList::remove(std::forward<Type>(value)); }
template <class CompareFunction> //需要傳入類似 bool (*compareFunction)(Type&& v1, Type&& v2) 的二元謂詞函數,v1爲element-value,v2爲input-value
void remove(Type&& value, CompareFunction compareFunction)
{
StdList::remove_if(std::bind(compareFunction,std::placeholders::_1,std::forward<Type>(value)));
}
void removeAll(){ StdList::clear(); }
void removeAt(unsigned int index)
{
typename StdList::iterator it=StdList::begin();
while (index --) ++it;
StdList::erase(it);
}
void removeFirst(){ StdList::pop_front(); }
void removeLast(){ StdList::pop_back(); }
void removeRange(unsigned int from, unsigned int to)
{
typename StdList::iterator first=StdList::begin(),last=StdList::begin();
while (from --) ++first;
while (to --) ++last;
StdList::erase(first,last);
}
void replace(unsigned int index, Type&& value){ this->operator[](index) = std::forward<Type>(value); }
void swap (std::list<Type,Alloc>& other){ return StdList::swap(other);}
void swap (unsigned int index1,unsigned int index2){ return std::swap(this->operator[](index1),this->operator[](index2));}
const Type& takeAt(unsigned int index) const{ return this->operator[](index); }
const Type& takeFirst() const { return *StdList::begin(); }
const Type& takeLast() const { return this->operator[](StdList::size() - 1); }
std::list<Type> toStdList() const { return *this; }
std::vector<Type> toStdVec() const{ return std::vector<Type>(StdList::begin(),StdList::end());}
std::set<Type> toStdSet() const{ return std::set<Type>(StdList::begin(),StdList::end());}
const Type& value(unsigned int index) const { return this->operator[](index); }
};
}
測試代碼
typedef std::set<int> StdSet;
typedef std::list<int> StdList;
typedef std::vector<int> StdVec;
typedef CppHelper::CList<int> NewList;
#define TEST_list_bool(b) (b ? "true" : "false")
#define TEST_list_exec(flage,code) cout << "line["<< __LINE__ << "]: "<< flage << code << endl
#define TEST_list_show(flage,val) cout << "line["<< __LINE__ << "]: "<< flage ;\
for(auto it = val.begin();it!=val.end();++it) cout << *it << " ";\
if(val.empty()) cout << "empty";\
cout << endl
int arr[] = {1,2,3,4,5,6,7,8,9};
StdSet stdSet{11,12,13,14,15,16,17,18,19};
StdList stdList{21,22,23,24,25,26,27,28,29};
StdVec stdVec1{31,32,33,34,35,36,37,38,39};
NewList newList1;
NewList newList2(10);
NewList newList3(stdSet);
NewList newList4(stdList);
NewList newList5(stdVec1);
NewList newList6(arr,arr+9);
TEST_list_show(" stdSet: ",stdSet);
TEST_list_show("stdList: ",stdList);
TEST_list_show("stdVec1: ",stdVec1);
TEST_list_show("newList1: ",newList1);
TEST_list_show("newList2: ",newList2);
TEST_list_show("newList3: ",newList3);
TEST_list_show("newList4: ",newList4);
TEST_list_show("newList5: ",newList5);
TEST_list_show("newList6: ",newList6);
TEST_list_exec("newList3 == newList4 ? : ",TEST_list_bool(newList3 == newList4));
TEST_list_exec("newList3 != newList4 ? : ",TEST_list_bool(newList3 != newList4));
newList1 = newList3;
newList1 += newList4;
newList1 << 100 << 200<< 300;
TEST_list_show("newList1: ",newList1);
TEST_list_exec("newList1.size() : ",newList1.size());
newList1.clear();
TEST_list_exec("newList1.size() : ",newList1.size());
TEST_list_show("newList1: ",newList1);
newList1.append(555);
newList1.append(newList3);
newList1.append(stdSet);
newList1.append(stdList);
TEST_list_show("newList1: ",newList1);
TEST_list_exec("newList1.at(11) : ",newList1.at(11));
newList1.contains(200,[](const int& v1,int v2){ return v1>v2;});
TEST_list_exec("newList1.contains(555) : ",TEST_list_bool(newList1.contains(555)));
TEST_list_exec("newList1.contains(>200): ",TEST_list_bool(newList1.contains(200,[](const int& v1,int v2){ return v1>v2;})));
TEST_list_exec("newList1.count(11) : ",newList1.count(11));
TEST_list_exec("newList1.count(>28): ",newList1.count(28,[](int v1, int v2){ return v1>v2;}));
newList1.clear();
newList1.resize(20);
TEST_list_show("newList3 : ",newList3);
TEST_list_show("newList1 : ",newList1);
newList1.copy(newList3);
TEST_list_show("newList1.copy1: ",newList1);
newList1.copy(3,111);
TEST_list_show("newList1.copy2: ",newList1);
newList1.copy(newList3.begin(),newList3.end());
TEST_list_show("newList1.copy3: ",newList1);
newList1.copy(newList3.begin(),newList3.end(),[](int v){ return v>15; });
TEST_list_show("newList1.copy4: ",newList1);
newList1.copy(newList3.begin(),7);
TEST_list_show("newList1.copy5: ",newList1);
TEST_list_exec("newList1.count(15) : ",newList1.count(15));
TEST_list_exec("newList1.count(>15): ",newList1.count(15,[](int v1,int v2){ return v1>v2; }));
TEST_vec_show("newList1 : ",newList1);
TEST_vec_show("newList3 : ",newList3);
TEST_vec_exec("newList1.equal1(newList3) : ",TEST_vec_bool(newList1.equal(newList3)));
TEST_vec_exec("newList1.equal2(newList3) : ",TEST_vec_bool(newList1.equal(newList3.begin())));
TEST_vec_exec("newList1.equal3(newList3) : ",TEST_vec_bool(newList1.equal(newList3.begin(),[](int v1,int v2){ return v1==v2; })));
newList1.clear();
newList1.resize(5);
TEST_list_show("newList1 : ",newList1);
newList1.fill(111,newList1.begin(),newList1.end());
TEST_list_show("newList1.fill-1 : ",newList1);
newList1.resize(10);
newList1.fill(5,222,newList1.begin());
TEST_list_show("newList1.fill-2 : ",newList1);
newList1.copy(newList3);
TEST_list_show("newList1 : ",newList1);
TEST_list_exec("newList2.find(13) : ",*(newList1.find(13)));
TEST_list_exec("newList2.find(<=13): ",*(newList1.find(13,[](int vecVal,int findVal){ return vecVal<=findVal;})));
cout << "newList1.for_each: ";
newList1.for_each([](int v){ cout << v << " "; });
cout << endl;
TEST_list_exec("newList1.index(15) : ",newList1.index(15));
TEST_list_exec("newList1.index(<100 && >=15) : ",newList1.index(15,[](int vecVal,int findVal){ return vecVal<100&& vecVal>=findVal;}));
TEST_list_show("newList1 : ",newList1);
newList1.insert(3,333);
TEST_list_show("newList1.insert(3,333): ",newList1);
TEST_list_show("newList1 : ",newList1);
newList1.insert(newList1.size(),NewList::value_type(666));
TEST_list_exec("newList1.last() : ",newList1.last());
newList1.prepend(333);
TEST_list_exec("newList1.first(): ",newList1.first());
TEST_list_show("newList1 : ",newList1);
newList1.clear();
TEST_list_show("newList1 : ",newList1);
TEST_list_show("newList3 : ",newList3);
TEST_list_show(" stdSet: ",stdSet);
TEST_list_show("stdList: ",stdList);
newList1.push_back(11);
newList1.push_back(newList3);
newList1.push_back(stdSet);
newList1.push_back(stdList);
newList1.push_front(444);
TEST_list_show("newList1 : ",newList1);
newList1.remove(11);
TEST_list_show("newList1 remove-1 : ",newList1);
newList1.remove(15,[](int vecVal,int findVal){ return vecVal < findVal+2 && vecVal >= findVal-2;});
TEST_list_show("newList1 remove-2 : ",newList1);
newList1.removeRange(3,6);
TEST_list_show("newList1 remove-3 : ",newList1);
newList1.removeFirst();
newList1.removeLast();
newList1.removeAt(3);
TEST_list_show("newList1 remove-4 : ",newList1);
TEST_list_exec("newList1.size() : ",newList1.size());
newList1.removeAll();
TEST_list_show("newList1 removeAll : ",newList1);
TEST_list_exec("newList1.size() : ",newList1.size());
newList1 = newList3;
TEST_list_show("newList1=newList3 : ",newList1);
newList1.replace(3,333);
TEST_list_show("newList1.replace(3,333): ",newList1);
TEST_list_show("newList3 : ",newList3);
newList1.swap(newList3);
TEST_list_show("newList1.swap(newList3) : ",newList1);
TEST_list_show("newList3 : ",newList3);
newList1.swap(3,7);
TEST_list_show("newList1.swap(3,7) : ",newList1);
TEST_list_exec("newList1.takeAt(3) : ",newList1.takeAt(3));
TEST_list_exec("newList1.takeFirst() : ",newList1.takeFirst());
TEST_list_exec("newList1.takeLast() : ",newList1.takeLast());
TEST_list_exec("newList1.value(7) : ",newList1.value(7));
TEST_list_show("newList5 : ",newList5);
TEST_list_show("stdSet : ",stdSet);
TEST_list_show("stdList : ",stdList);
TEST_list_show("stdVec1 : ",stdVec1);
stdSet = newList5.toStdSet();
stdVec1 = newList5.toStdVec();
stdList = newList5.toStdList();
TEST_list_show("stdSet : ",stdSet);
TEST_list_show("stdList : ",stdList);
TEST_list_show("stdVec1 : ",stdVec1);