您的位置:首页 > 产品设计 > UI/UE

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/

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;
}


效果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: