c++ STL 学习记录 草稿。
非常丑陋的尝试实现stl。慢慢修改吧。
1)简单实现 vector和list。
2)思索如何开始编写算法。
1,所有容器继承一个抽象容器。那么算法就可以使用抽象基类的next方法来遍历元素。 容器间耦合太高,放弃。
2,所有容器的元素T继承一个基类,算法使用基类的next方法来遍历元素。应该是可以的。做到一半,实现多态时,必须太多指针样子,好像跟stl的使用相差太远。看书发现stl是用模板模拟多态。或者说是模板的正宗,优雅的多态形式。
3,使用模板的更优雅的多态思想来实现容器的迭代器。
3)后面的改进,在于迭代器修改为pointerlike的类。还有书上谈到把各自的迭代器放入到容器类中?以免迭代器暴露太多容器细节。为什么不可以用容器的public方法?
第一版
main
#include <iostream> #include "myvecotr.h" #include "al.h" #include <algorithm> #include <vector> #include "mylist.h" using namespace std; class Book { public: Book(int _id,const string& _name):id(_id),name(_name){} int GetInt() { return id; } string GetName() { return name; } bool operator==(const Book& rhg) { bool ret=false; if(rhg.id==this->id && rhg.name==this->name) { ret=true; } return ret; } private: int id; string name; }; int main() { Book cc(1,"c++"); Book cc2(5,"c"); Book cc3(3,"c#"); cout<<"*************stl*********************"<<endl; vector<Book> books2; books2.push_back(cc); books2.push_back(cc2); books2.push_back(cc3); vector<Book>::iterator myit=books2.begin(); cout<<myit->GetName()<<endl; cout<<"*************list*********************"<<endl; MyList<Book> bookList; bookList.push_back(cc); bookList.push_back(cc2); bookList.push_back(cc3); cout<<bookList.GetHead()->GetV()->GetName()<<endl; ListIterator<Book> FF= myFind(bookList.getFirstIterator(),bookList.getIterator(2),cc3); cout<<FF.GetP()->GetV()->GetName()<<endl; myVector<Book> books; books.push_back(cc); books.push_back(cc2); books.push_back(cc3); cout<<"*************vector*********************"<<endl; myVector<Book>::iterator rnt=myFind(books.GetBegin(),books.GetEnd(),cc2); cout<<rnt->GetName()<<endl; return 0; }
mylist.h
#ifndef MYLIST_H_INCLUDED #define MYLIST_H_INCLUDED #include <memory> #include <stdexcept> #include <iostream> using namespace std; ////////////////////listnode. template<typename T> class ListNode { public: ListNode( T*,ListNode*); void SetNext(ListNode*); ListNode* GetNext(); bool IsEmpty(); T* GetV(); private: T* value; ListNode* next; }; template<typename T> ListNode<T>::ListNode( T* v,ListNode* n):value(v),next(n){} template<typename T> void ListNode<T>::SetNext(ListNode* n) { next=n; } template<typename T> ListNode<T>* ListNode<T>::GetNext() { return next; } template<typename T> bool ListNode<T>::IsEmpty() { if(value==0 && next==0) { return true; } else { return false; } } template<typename T> T* ListNode<T>::GetV() { return value; } /////////////////////////////////list iterator //1)必须有正确的+号操作和!=操作.2)必须有全局的元素和迭代器==的重载. template<typename T> class ListIterator { public: ListIterator(ListNode<T>* v):myP(v){} ListIterator operator+(int index) { ListNode<T>* pListNode=myP; for(int i=0;i!=index;++i) { if(pListNode->GetNext()!=0) { pListNode=pListNode->GetNext(); } else { break; } } return ListIterator(pListNode); } bool operator!=(const ListIterator& rht) { return myP!=rht.myP; } ListNode<T>* GetP() { return myP; } private: ListNode<T>* myP; }; template<typename T> bool operator==( ListIterator<T>& lht, T& rht) { return rht==*(lht.GetP()->GetV()); } /////////////////////////////////mylist template<typename T> class MyList { public: MyList():head(0),size(0){} void push_back(const T& v) { ListNode<T>* tempNode=new ListNode<T>(new T(v),0); if(head==0) { head=tempNode; ++size; } else { ListNode<T>* temp=head; while(temp->GetNext()!=0) { temp=temp->GetNext(); } temp->SetNext(tempNode); ++size; } } ListNode<T>* GetHead() { return head; } ListIterator<T> getFirstIterator() { return ListIterator<T>(head); } ListIterator<T> getIterator(int i) { ListNode<T>* rnt=0; if(i>=0) { ListNode<T>* temp=head; for(int index=0;index!=i;++index) { ListNode<T>* temp2=temp->GetNext(); if(temp2!=0) { temp=temp2; cout<<temp<<endl; } else { break; } } rnt=temp; } return ListIterator<T>(rnt); } ~MyList() { ListNode<T>* temp=head; while(temp!=0) { ListNode<T>* del=temp; temp=temp->GetNext(); delete del->GetV(); delete del; } } private: int size; ListNode<T>* head; }; #endif // MYLIST_H_INCLUDED
myvector.h
#ifndef MYVECTOR_H_INCLUDED #define MYVECTOR_H_INCLUDED //allocator<T> a; 定义一个T类型的allocator对象。 //a.allocate(n); 申请n个T大小的,未分配的空间。类似(T*) malloc(sizeof(T)*n) //a.deallocate(p,n) 释放内存,p为T*,n为释放的T类型对象的数量。注意:T类型对象本身,如有需要释放的资源,必须先释放,a.deallocate(p,n)只是释放对象本身的内存,而对象的建立又额外申请的资源,需要另外处理。 //a.construct(p,t) 复制构造,用t来复制构造。相当于 new (p) T(t),这个是placement new的用法 new(place_address) type(initializer-list) //a.destroy(p) 调用pd对象的析构函数。 //uninitialized_copy(startit,endit,it) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的迭代器地址。 //uninitialized_fill(startit,endit,obj) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的对象。 使用复制构造函数填充内存 //uninitialized_fill_n(startit,endit,obj,n) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的对象。 n,要复制的数量。 使用复制构造函数填充内存 //因为是模板,有类型参数,类的方法编译的时候,不能确定所占用的栈大小.必须使用的时候才能确定,而且不同的T类型,有不同的方法地址.所以申明定义放到一起 #include <memory> #include <stdexcept> #include <iostream> #include "myitertor.h" using namespace std; template<typename T> class myVector{ public: //如果分配错误呢? myVector():pbegin(myalloc.allocate(defautlSize)),pend(pbegin),pcapcity(pbegin+defautlSize),Vsize(0),Vcapcity(defautlSize){} typedef T* iterator; void push_back(const T& _obj) { if(pend>=pcapcity) { T* pTempAlloc=myalloc.allocate(Vcapcity*2); T* pPrep=pbegin; if(pTempAlloc!=0) { uninitialized_copy(pbegin,pend,pTempAlloc); pbegin=pTempAlloc; pend=pbegin+Vsize; pcapcity=pbegin+(Vcapcity*2); Vsize=Vsize; Vcapcity+=Vcapcity; //清理原资源. destroyS(pPrep,pPrep+Vsize,pPrep+Vsize); } else { throw runtime_error("error allocator!"); } } myalloc.construct(pend,_obj); ++pend; ++Vsize; } void erase(unsigned int index) { if(index>=0&& index<Vsize) { myalloc.destroy(pbegin+index);//手动调用对象析构 for(int i=index+1;i!=Vsize;++i)//往前覆盖.最后一个对象占用的内存,不管了.pend往前移动就好. { uninitialized_copy(pbegin+i,pbegin+i+1,pbegin+i-1); } --Vsize; --pend; } else { throw runtime_error("index over range."); } } ~myVector() { destroyS(pbegin,pend,pcapcity); } myVector(const myVector& _obj) { pbegin=myalloc.allocate(_obj.Vcapcity); pend=pbegin+_obj.Vsize; pcapcity=pbegin+_obj.Vcapcity; Vsize=_obj.Vsize; Vcapcity=_obj.Vcapcity; uninitialized_copy(_obj.pbegin,_obj.pend,pbegin); } myVector& operator=(const myVector& _obj) { if(&_obj!=this) { destroyS(pbegin,pend,pcapcity); pbegin=myalloc.allocate(_obj.Vcapcity); pend=pbegin+_obj.Vsize; pcapcity=pbegin+_obj.Vcapcity; Vsize=_obj.Vsize; Vcapcity=_obj.Vcapcity; uninitialized_copy(_obj.pbegin,_obj.pend,pbegin); } return *this; } int size() { return pend-pbegin; } int capcity() { return pcapcity-pbegin; } void showInfo() { cout<<"pbegin:"<<(void *)pbegin<<". size:"<<Vsize<<". capcity"<<Vcapcity<<". pend:"<<(void *)pend<<endl; T* pb=pbegin; for(pb;pb!=pend;++pb) { cout<<*pb<<endl; } } T& operator[](int index) { return *(pbegin+index); } T* GetBegin() { return pbegin; } T* GetEnd() { return pend; } private: static allocator<T> myalloc; const static int defautlSize=3; T* pbegin; T* pend; T* pcapcity; unsigned int Vcapcity; unsigned int Vsize; void destroyS(T* PS,T* PE,T* PC) { T* pb=PS; for(pb;pb!=PE;++pb) { myalloc.destroy(pb);//仅仅调用析构函数. } myalloc.deallocate(PS,PC-PS); } }; //int book::pid=6 template<typename T> allocator<T> myVector<T>::myalloc=allocator<T>(); template<typename T> bool operator==(T* a,T v) { bool rnt; if(*a==v) { rnt=true; } else { rnt=false; } return rnt; } #endif // MYVECTOR_H_INCLUDED
al.h
#ifndef AL_H_INCLUDED #define AL_H_INCLUDED #include "myitertor.h" //1)必须有正确的+号操作和!=操作.2)必须有全局的元素和迭代器==的重载. template<typename T,typename MyInputIterator> MyInputIterator myFind(MyInputIterator start,MyInputIterator end, T& value) { for(start;start!=end;start=start+1) { if(start==value)// { break; } } return start; } #endif // AL_H_INCLUDED
hashtable:
自己写的 hashtable,不过hash函数还是stl的hash ,而且冲突时的链表也是直接使用stl的list。
之前写了几次总放弃,重要是考虑太多,自己造hash的轮子,总感觉不适用,一直停在那里。又考虑list 的具体细节。还要和这里配合。
感觉造轮子前,先使用木头,而不要先造斧头,去砍树。这样造个轮子都要很耗精力。
等轮子造好了,再去造斧头。再去造炉子,再去造火。要不然会总停在某个点上。
造轮子的目的其实是理解。方便选择适合的场景使用适当的数据结构。
最终的目的是使用标准的轮子。而不是自己的轮子。
从难学。从易用。切记。。。
#include <iostream> #include "stdio.h" #include <memory> #include <unistd.h> #include <thread> #include <vector> #include <algorithm> #include <memory.h> #include <map> #include <list> #include <ext/hash_map> using namespace std; using namespace __gnu_cxx; struct Good { int gid; string goodName; int value; }; namespace __gnu_cxx { template<> struct hash<string> { size_t operator()(const string& s) const { return __stl_hash_string(s.c_str()); } }; } template<typename T> class HashTable { public: class Hashv { public: string key; T value; }; HashTable(int32_t v) { ht=new list<Hashv>[v]; ht_size=v; } int32_t hash(const string& _key) { std::hash<string> sh; size_t hv= sh(_key); hv=hv%ht_size; return hv; } bool Add(const string& key,const T& _v) { int32_t _hash_index=hash(key); Hashv temp; temp.key=key; temp.value=_v; ht[_hash_index].push_back(temp); return true; } T Search(string _key) { int32_t _hash_index=hash(_key); T ret; if(ht[_hash_index].size()==1) { ret= ht[_hash_index].begin()->value; } else { for(auto obj : ht[_hash_index]) { if(obj.key==_key) { ret= obj.value; } } } return ret; } ~HashTable() { delete[] ht; } private: list<Hashv> * ht; int32_t ht_size; }; void main2(); int main() { //map map<int,Good> good_buff; for(int i=0;i<10000;++i) { Good temp; temp.gid=i; temp.goodName="test"; temp.value=i%100+1; good_buff.insert(map<int,Good>::value_type(temp.gid,temp)); } int gid=405; if(good_buff.find(gid)!=good_buff.end()) { cout<<good_buff[gid].value<<endl; } //simple hashtable HashTable<Good> myhash(100); Good temp; temp.gid=3; temp.goodName="test"; temp.value=31; myhash.Add("3",temp); Good temp2; temp2.gid=4; temp2.goodName="test"; temp2.value=41; myhash.Add("4",temp2); Good ss=myhash.Search("4"); cout<<ss.value<<endl; //stl hash map. hash_map<string,Good> stlhash; stlhash.insert(hash_map<string,Good>::value_type("test",temp)); stlhash.insert(hash_map<string,Good>::value_type("test2",temp)); hash_map<string,Good>::iterator ss2=stlhash.find("test"); cout<<ss2->second.value<<endl; int cmd; cin>>cmd; }