STL 简单 queue 的实现
2016-05-21 21:20
369 查看
我用VS2013写的程序(github ),queue版本的代码位于cghSTL/version/cghSTL-0.3.5.rar
queue是一种先进先出(firstin first out)的数据结构。它有两个个出口,从底端加入元素,从顶端取得元素。但是除了最低端可以加入、最顶端可以删除以外,没有其他办法可以存取queue的元素,换言之,queue不允许遍历。
queue没有遍历行为,故不需要迭代器,这让queue的设计变的非常简单,我们以deque作为缺省情况下的queue底层结构。看懂queue的实现,需要先知道deque是怎么做出来的,关于deque,请看另一篇博客,传送门:STL简单deque的实现
由于queue以deque作为底层容器完成工作,这种具有“修改某接口,形成另一种风貌”的东西,我们称之为adapter(接配器),因此queue往往不被归类为容器,而被归为容器的接配器。
queue的实现需要以下几个文件:
1. globalConstruct.h,构造和析构函数文件,位于cghSTL/allocator/cghAllocator/
2. cghAlloc.h,空间配置器文件,位于cghSTL/allocator/cghAllocator/
3. cghQueue.h,queue的实现,位于cghSTL/sequence
containers/cghQueue/
4. test_cghQueue.cpp,测试代码,位于cghSTL/test/
按照STL的接口规范,正确的顺序是先分配内存然后构造元素。构造函数的实现采用placement new的方式;为了简化起见,我直接调用析构函数来销毁元素,而在考虑效率的情况下一般会先判断元素是否为non-trivial类型。
关于 trivial 和 non-trivial 的含义,参见:stack overflow
classcghAllocator是空间配置器类的定义,主要的四个函数的意义如下:allocate函数分配内存,deallocate函数释放内存,construct构造元素,destroy析构元素。这四个函数最终都是通过调用_allocate、_deallocate、_construct、_destroy这四个内联函数实现功能。
我们自己写的空间配置器必须封装一层STL的标准接口,
构造与析构函数、空间配置器是最最基本,最最底层的部件,把底层搭建好之后我们就可以着手设计queue了。
cghQueue.h
test_cghQueue.cpp:
效果图:
queue是一种先进先出(firstin first out)的数据结构。它有两个个出口,从底端加入元素,从顶端取得元素。但是除了最低端可以加入、最顶端可以删除以外,没有其他办法可以存取queue的元素,换言之,queue不允许遍历。
queue没有遍历行为,故不需要迭代器,这让queue的设计变的非常简单,我们以deque作为缺省情况下的queue底层结构。看懂queue的实现,需要先知道deque是怎么做出来的,关于deque,请看另一篇博客,传送门:STL简单deque的实现
由于queue以deque作为底层容器完成工作,这种具有“修改某接口,形成另一种风貌”的东西,我们称之为adapter(接配器),因此queue往往不被归类为容器,而被归为容器的接配器。
queue的实现需要以下几个文件:
1. globalConstruct.h,构造和析构函数文件,位于cghSTL/allocator/cghAllocator/
2. cghAlloc.h,空间配置器文件,位于cghSTL/allocator/cghAllocator/
3. cghQueue.h,queue的实现,位于cghSTL/sequence
containers/cghQueue/
4. test_cghQueue.cpp,测试代码,位于cghSTL/test/
1.构造与析构
先看第一个,globalConstruct.h构造函数文件/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 功能:全局构造和析构的实现代码 ******************************************************************/ #include "stdafx.h" #include <new.h> #include <type_traits> #ifndef _CGH_GLOBAL_CONSTRUCT_ #define _CGH_GLOBAL_CONSTRUCT_ namespace CGH { #pragma region 统一的构造析构函数 template<class T1, class T2> inline void construct(T1* p, const T2& value) { new (p)T1(value); } template<class T> inline void destroy(T* pointer) { pointer->~T(); } template<class ForwardIterator> inline void destroy(ForwardIterator first, ForwardIterator last) { // 本来在这里要使用特性萃取机(traits编程技巧)判断元素是否为non-trivial // non-trivial的元素可以直接释放内存 // trivial的元素要做调用析构函数,然后释放内存 for (; first < last; ++first) destroy(&*first); } #pragma endregion } #endif
按照STL的接口规范,正确的顺序是先分配内存然后构造元素。构造函数的实现采用placement new的方式;为了简化起见,我直接调用析构函数来销毁元素,而在考虑效率的情况下一般会先判断元素是否为non-trivial类型。
关于 trivial 和 non-trivial 的含义,参见:stack overflow
2.空间配置器
cghAlloc.h是空间配置器文件,空间配置器负责内存的申请和回收。/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 功能:cghAllocator空间配置器的实现代码 ******************************************************************/ #ifndef _CGH_ALLOC_ #define _CGH_ALLOC_ #include <new> #include <cstddef> #include <cstdlib> #include <climits> #include <iostream> namespace CGH { #pragma region 内存分配和释放函数、元素的构造和析构函数 // 内存分配 template<class T> inline T* _allocate(ptrdiff_t size, T*) { set_new_handler(0); T* tmp = (T*)(::operator new((size_t)(size * sizeof(T)))); if (tmp == 0) { std::cerr << "out of memory" << std::endl; exit(1); } return tmp; } // 内存释放 template<class T> inline void _deallocate(T* buffer) { ::operator delete(buffer); } // 元素构造 template<class T1, class T2> inline void _construct(T1* p, const T2& value) { new(p)T1(value); } // 元素析构 template<class T> inline void _destroy(T* ptr) { ptr->~T(); } #pragma endregion #pragma region cghAllocator空间配置器的实现 template<class T> class cghAllocator { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; template<class U> struct rebind { typedef cghAllocator<U> other; }; static pointer allocate(size_type n, const void* hint = 0) { return _allocate((difference_type)n, (pointer)0); } static void deallocate(pointer p, size_type n) { _deallocate(p); } static void deallocate(void* p) { _deallocate(p); } void construct(pointer p, const T& value) { _construct(p, value); } void destroy(pointer p) { _destroy(p); } pointer address(reference x) { return (pointer)&x; } const_pointer const_address(const_reference x) { return (const_pointer)&x; } size_type max_size() const { return size_type(UINT_MAX / sizeof(T)); } }; #pragma endregion #pragma region 封装STL标准的空间配置器接口 template<class T, class Alloc = cghAllocator<T>> class simple_alloc { public: static T* allocate(size_t n) { return 0 == n ? 0 : (T*)Alloc::allocate(n*sizeof(T)); } static T* allocate(void) { return (T*)Alloc::allocate(sizeof(T)); } static void deallocate(T* p, size_t n) { if (0 != n)Alloc::deallocate(p, n*sizeof(T)); } static void deallocate(void* p) { Alloc::deallocate(p); } }; #pragma endregion } #endif
classcghAllocator是空间配置器类的定义,主要的四个函数的意义如下:allocate函数分配内存,deallocate函数释放内存,construct构造元素,destroy析构元素。这四个函数最终都是通过调用_allocate、_deallocate、_construct、_destroy这四个内联函数实现功能。
我们自己写的空间配置器必须封装一层STL的标准接口,
template<classT, class Alloc = cghAllocator<T>> classsimple_alloc
构造与析构函数、空间配置器是最最基本,最最底层的部件,把底层搭建好之后我们就可以着手设计queue了。
3.queue的实现
Queue的底层用cghDeque实现,关于cghDeque,请看另一篇博客,传送门:STL简单deque的实现cghQueue.h
/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 文件名称:queue的实现代码 ******************************************************************/ #ifndef _CGH_DEQUE_QUEUE_ #define _CGH_DEQUE_QUEUE_ #include "cghDeque.h" #include"cghAlloc.h" #include "globalConstruct.h" namespace CGH{ /* 采用cghDeque作为cghQueue的底层实现 */ template<class T, class sequence = cghDeque<T>> class cghQueue{ public: typedef typename sequence::value_type value_type; typedef typename sequence::size_type size_type; typedef typename sequence::reference reference; protected: sequence s; public: cghQueue() :s(){ } // 构造函数 bool empty() const{ return s.empty(); } // queue是否为空 size_type size() { return s.size(); } // queue的长度 reference front(){ return s.front(); } // 前端元素 reference back(){ return s.back(); } // 末端元素 void push(const value_type& x){ s.push_back(x); } // 末端进 void pop(){ s.pop_front(); } // 前端出 }; } #endif
4.测试
测试环节的主要内容已在注释中说明test_cghQueue.cpp:
/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 文件名称:queue的测试代码 ******************************************************************/ #include "stdafx.h" #include "cghQueue.h" using namespace::std; int _tmain(int argc, _TCHAR* argv[]) { using namespace::CGH; cghQueue<int> test; std::cout << "************************压入测试************************" << endl << endl; std::cout << "queue只能从后端弹出" << endl << endl; std::cout << "压入元素:"; for (int i = 0; i < 4; ++i) { std::cout << i << ","; test.push(i); } std::cout << endl << endl << "前端元素:"; std::cout << test.front() << endl; std::cout << endl << "后端元素:"; std::cout << test.back() << endl << endl; std::cout << "队列长度:" << test.size() << endl; std::cout << endl << endl; std::cout << "************************弹出测试************************" << endl << endl; std::cout << "queue只能从前端弹出" << endl; for (int i = 0; i < 4; ++i) { std::cout << endl << "前端元素:"; std::cout << test.front() << endl; std::cout << endl << "后端元素:"; std::cout << test.back() << endl << endl; std::cout << "队列长度:" << test.size() << endl; std::cout << "-------------------" << endl; test.pop(); } std::cout << endl << endl; system("pause"); return 0; }
效果图:
相关文章推荐
- String , StringBuffer, StringBuilder的区别
- mysql 中插入中文出现的 Incorrect string value: '\xE5\xA5\xBD\xE5\xAE\xB6...' from column错误
- XMG 核心动画与UIView动画的区别
- 如何将dataframe转换为rdd类型
- ios开发学习笔记--调用相册或相机(UIImagePickerController)
- LeetCode Everyday: 347. Top K Frequent Elements
- 动态规划——distinct-subsequences t在s中出现的次数
- 微软扫盲贴:Windows 和 GPT 常见问题解答(uefi、GPT、ESP、MSR之类的概念)
- PHP Study- Issue 1 -Redirect Unable to load the module
- 8种删除UICollectionViewCell的动画
- Codeforces Round #316 (Div. 2) D. Tree Requests
- break,continue,与标号
- U3d屏幕自适应
- 02.手把手教你 .Net EasyUI DataGrid(数据表格排序)
- MFC中应用WM_ENDSESSION,WM_QUERYENDSESSION消息截获系统的关机/注销
- POJ-2031-Building a Space Station-(最小生成树 普利姆)
- MVC5 DBContext.Database.SqlQuery获取对象集合到ViewModel集合中(可以利用这个方法给作为前台视图页cshtml页面的@model 源)
- (创建型模式)BUILDER——建造者模式(生成器模式)
- UI基础_UIButton
- android view 的requestLayout和invalidate