前言:
看到许多面经说,有时候面试官要你自己当场用模板写出自己的vector容器。于是,我也琢磨着怎么自己动手写一个,可是本人才刚刚学C++模板编程不久,会的不多。不过,我恰好在C++ Primer上看到作者实现了自己的Queue,如果Queue自己实现了,相信Vector也不难了吧?当然这个Queue没有标准库queue的全部功能,只是有它的一部分。我想把书上的Queue敲下来,让自己练练手。
首先我们来画一下Queue的结构,这样有利于我们理解Queue的构造,使编程思路更加清晰。
Queue类的定义:
//放到Queue.h文件中
1 //Queue的完整定义 2 3 //先申明Queue类,因为QueueItem类要用到 4 #ifndef _QUEUE_HEAD_ 5 #define _QUEUE_HEAD_ 6 template <class type> class Queue; 7 8 template <class Type> 9 std::ostream& operator<< (std::ostream&, const Queue<Type>&); 10 11 template <class Type> 12 class QueueItem{ 13 //让Queue类成为友元函数,这样Queue里面就可以直接访问QueueItem的私有变量 14 friend class Queue<Type>; 15 //将重载后的 << 函数设置为QueueItem的友元函数,以便访问QueueItem的私有变量 16 friend std::ostream& 17 operator<< <Type> (std::ostream&, const Queue<Type>&); 18 //private 成员变量 19 //复制构造函数 20 QueueItem(const Type &t):item(t),next(0) {}; 21 //真正保存数据的成员变量 22 Type item; 23 //指向下一个节点的指针 24 QueueItem *next; 25 }; //QueueItem类 26 27 //下面定义Queue类 28 29 template <class Type> class Queue { 30 friend std::ostream& 31 operator << <Type> (std::ostream&, const Queue<Type>&); 32 public: 33 //默认构造函数 34 Queue():head(0),tail(0){} 35 //根据迭代器范围进行构造的构造函数 36 template <class It> 37 Queue(It beg, It end):head(0),tail(0){copy_elems(beg,end);} 38 //复制构造函数 39 Queue(const Queue& Q):head(0),tail(0){copy_elem(Q);} 40 //析构函数 41 ~Queue(){destory();} 42 //赋值函数 43 Queue& operator = (const Queue&); 44 //根据迭代器赋值的赋值函数 45 template <class Iter> void assign(Iter,Iter); 46 //返队首元素 47 Type& front(); 48 //根据const重载front函数,以供const对象调用 49 const Type& front() const; 50 //向队尾添加元素 51 void push(const Type&); 52 //删除队首元素 53 void pop(); 54 //判断队列是否为空,如果是空返回1,否则返回1 55 bool empty () const {return head == 0;} 56 private: 57 //指向队首元素的指针 58 QueueItem<Type> *head; 59 //指向队尾元素的指针 60 QueueItem<Type> *tail; 61 //删除队列中所有元素的函数 62 void destory(); 63 //复制队列元素的函数 64 void copy_elems(const Queue&); 65 //根据迭代器范围复制队列元素的函数,模板形式 66 template <class Iter> void copy_elems(Iter,Iter); 67 }; 68 #include "Queue.cc" //实现 69 #endif
Queue类的实现:
//放到Queue.cc文件中
1 //实现 << 的重载的实现 2 template<class Type> std::ostream& 3 operator << (std::ostream &os,const Queue<Type>&q) 4 { 5 os << "<"; 6 QueueItem<Type> *p = q.head; //指向链表的头节点 7 for(;p;p = p->next) 8 { 9 os << p->item << " "; 10 } 11 os << ">"; 12 return os; 13 } 14 15 //Queue的赋值函数 16 template <class Type> //模板标志 17 Queue<Type>& //返回类型 18 Queue<Type>::operator=//作用域 19 (const Queue&org) //参数列表 20 { //函数体 21 if(this == &org) //防止自己赋值给自己 22 return *this; 23 destory(); //先释放掉自己原来占有的内存资源 24 copy_elems(org); //复制元素 25 } 26 27 //成员函数模板 28 template<class Type> //第一个模板是类模板 29 template<class Iter> //第二个模板是成员函数模板 30 void 31 Queue<Type>::assign(Iter beg, Iter end) 32 { 33 destory(); 34 copy_elems(beg,end); 35 } 36 37 //front函数 38 template<class Type> 39 Type& Queue<Type>::front() 40 { 41 return head->item; 42 } 43 44 //const对象调用的const front函数 45 template<class Type> 46 const Type& Queue<Type>::front() const 47 { 48 return head->item; 49 } 50 51 //向队尾添加元素 52 template <class Type> 53 void Queue<Type>::push(const Type& val) 54 { 55 QueueItem<Type> *p = new QueueItem<Type>(val); 56 if(p) 57 { 58 if(empty()) 59 { 60 head = tail = p; 61 } 62 else 63 { 64 tail->next = p; 65 tail = p; 66 } 67 } 68 69 } 70 71 //从队首删除元素 72 template<class Type> 73 void Queue<Type>::pop() 74 { 75 QueueItem<Type> *p = head; 76 head = head->next; 77 delete p; 78 } 79 80 //清空队列 81 template<class Type> 82 void Queue<Type>::destory() 83 { 84 while(!empty()) 85 { 86 pop(); 87 } 88 } 89 90 //根据队列复制元素 91 template<class Type> 92 void Queue<Type>::copy_elems(const Queue &org) 93 { 94 for(QueueItem<Type> *pt = org.head; pt; pt->next) 95 push(pt->item); //复制 96 } 97 98 //根据迭代器范围 99 template<class Type> 100 template<class Iter> 101 void Queue<Type>::copy_elems(Iter beg,Iter end) 102 { 103 while(beg != end) 104 { 105 push(*beg); 106 ++beg; 107 } 108 }
测试Queue功能:
1 #include <iostream> 2 #include <vector> 3 #include "Queue.h" 4 5 using namespace std; 6 7 int main() 8 { 9 Queue<int> qi; 10 int i = 3; 11 //
12 // 13 short a[4] = {0,3,6,9}; 14 vector<int> vi(a,a + 3); 15 Queue<int> qi2(a,a+4); 16 qi.push(i); 17 qi.push(4); 18 qi.push(2); 19 cout << qi << endl; 20 cout << qi2 << endl; 21 qi2.assign(vi.begin(),vi.end()); 22 cout << qi2 << endl; 23 qi.pop(); 24 cout << qi << endl; 25 //cout << qi.front() << endl; 26 //cout << "No Error!" << endl; 27 return 0; 28 }