标签:
我用VS2013写的程序(github ),list版本的代码位于cghSTL/version/cghSTL-0.3.2.rar
相较于vector的连续线性空间,list就显得复杂许多,它的好处是每次插入或删除一个元素,就配置或释放一个元素空间。因此,list对于空间的运用有绝对的精准,一点不浪费。Vector的插入操作可能造成内存的重新配置,但是List不会。
List不再能够像vector一样以普通指针作为迭代器,因为其节点不保证在存储空间在连续存在。由于list是一个双向链表,迭代器必须具有前移、后移的能力,所以list提供的是Bidirectional iterators。
list的实现需要以下几个文件:
1. globalConstruct.h,构造和析构函数文件,位于cghSTL/allocator/cghAllocator/
2. cghAlloc.h,空间配置器文件,位于cghSTL/allocator/cghAllocator/
3. _cghList.h,list节点的实现,位于cghSTL/sequence containers/cghList/
4. ListIterator.h,迭代器的实现,位于cghSTL/sequence containers/cghList/
5. ListNode.h,list双向链表的实现,位于cghSTL/sequence containers/cghList/
6. test_cghList.cpp,测试文件,位于cghSTL/test/
先看第一个,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类型,non-trivial的元素可以直接释放内存,可以理解为non-trivial全部分配在栈上,不用我们操心,由程序自动回收,trivial的元素要分配在堆上,需要手工调用析构函数来销毁,然后释放内存。
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<class T, class Alloc = cghAllocator<T>> class simple_alloc
构造与析构函数、空间配置器是最最基本,最最底层的部件,把底层搭建好之后我们就可以着手设计list了。
先看第一个,list的节点实现代码:
/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 功能:_cghList中元素的实现代码 ******************************************************************/ #ifndef _CGH_LIST_NODE_ #define _CGH_LIST_NODE_ namespace CGH{ // 定义双向链表节点类型 template<typename T> struct __list_node { typedef void* void_pointer; void_pointer prev; // 指向前一个节点 void_pointer next; // 指向后一个节点 T data; // 节点的数据域 }; } #endif
我们设计的是双向list,每个节点包含了两个指针,分别指向前一个节点和后一个节点,同时data代表节点的数据域。
接下来设计list的迭代器:
/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 功能:_cghList的迭代器的实现代码 ******************************************************************/ #ifndef _CGH_LIST_ITERATOR_ #define _CGH_LIST_ITERATOR_ #include "ListNode.h" #include <memory> namespace CGH{ template<class T, class Ref, class Ptr> struct __list_iterator { typedef __list_iterator<T, T&, T*> iterator; typedef __list_iterator<T, Ref, Ptr> self; typedef T value_type; typedef Ptr pointer; typedef Ref reference; typedef __list_node<T>* link_type; typedef size_t size_type; typedef ptrdiff_t difference_type; link_type node; // 联系迭代器和链表节点的纽带 #pragma region 构造函数 __list_iterator(link_type x) : node(x){} __list_iterator(){} __list_iterator(const iterator& x) :node(x.node){} #pragma endregion #pragma region 迭代器的基本操作 bool operator==(const self& x) const { return node == x.node; } bool operator!=(const self& x) const { return node != x.node; } reference operator*() const { return (*node).data; } reference operator->() const { return &(operator*()); } // 迭代器前进一个节点 self& operator++() { node = (link_type)((*node).next); return *this; } self operator++(int) { self tmp = *this; ++*this; return tmp; } // 迭代器递减1,后退一个节点 self& operator--() { node = (link_type)((*node).prev); return *this; } self operator--(int) { self tmp = *this; --*this; return tmp; } #pragma endregion }; } #endif
根据功能,我把迭代器划分成了两个region,第一个region是迭代器的构造函数,第二个region是迭代器的基础操作,比如前进后退,判断是否相等…。遗憾的是CSDN的代码编辑器不给力,网页上不能根据region折叠代码,有些童鞋看到大量代码会产生畏惧感,我们平时写代码要注意层次,划分region,功能分明,这样读起来会好很多。
现在我们有了list节点和list迭代器,接着把节点和迭代器组合在一起,构成list:
/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 功能:_cghList的实现代码 ******************************************************************/ #ifndef _CGH__LIST_ #define _CGH__LIST_ #include "ListNode.h" #include "cghAlloc.h" #include "globalConstruct.h" #include "ListIterator.h" namespace CGH{ template<class T, class Alloc = cghAllocator<T>> class _cghList{ protected: typedef __list_node<T> list_node; public: typedef list_node* link_type; typedef size_t size_type; typedef typename __list_iterator<T, T&, T*>::iterator iterator; #pragma region 内存控制、节点构造与析构 protected: link_type node; // _cghList中唯一的节点指针,指向_cghList的尾部 typedef simple_alloc<list_node, Alloc> list_node_allocator; // 定义空间配置器 link_type get_node(){ return list_node_allocator::allocate(); } // 申请一个节点的内存空间 void put_node(link_type p){ list_node_allocator::deallocate(p); } // 释放一个节点的内存空间 /* 创建一个节点: 1.调用get_node申请节点内存; 2.调用construct构造节点 */ link_type create_node(const T& x) { link_type p = get_node(); construct(&p->data, x); return p; } /* 销毁一个节点: 1.调用destroy析构节点; 2.调用put_node释放内存 */ void destroy_node(link_type p) { destroy(&p->data); put_node(p); } public: /* 构造函数: 调用empty_initialize */ _cghList(){ empty_initialize(); } protected: /* 构造一个空链表: 1.申请一个节点内存 2.初始化尾节点 */ void empty_initialize() { node = get_node(); node->next = node; node->prev = node; } #pragma endregion public: #pragma region 链表的查询操作 /* 返回头节点: _cghList中的node成员变量保存了链表的尾指针 链表的尾指针不参与运算,仅标识链表结尾 */ iterator begin()const { return (link_type)((*node).next); } /* 返回尾节点: _cghList中的node成员变量保存了链表的尾指针 链表的尾指针不参与运算,仅标识链表结尾 */ iterator end()const{ return node; } /* 判断链表是否为空: _cghList中的node成员变量保存了链表的尾指针 链表的尾指针不参与运算,仅标识链表结尾 */ bool empty() const{ return node->next == node; } /* 返回链表长度: _cghList中的node成员变量保存了链表的尾指针 链表的尾指针不参与运算,仅标识链表结尾 */ size_type size() const { size_type result = 0; iterator first = begin(); iterator last = end(); while (first != last) { ++first; ++result; } return result; } #pragma endregion #pragma region 插入链表元素,包括头插和尾插 /* 插入到链表头部 */ void push_back(const T& x){ insert(end(), x); } /* 插入到链表尾部 */ void push_front(const T& x){ insert(begin(), x); } /* 执行具体的插入操作 */ iterator insert(iterator position, const T& x) { link_type tmp = create_node(x); tmp->next = position.node; tmp->prev = position.node->prev; (link_type(position.node->prev))->next = tmp; position.node->prev = tmp; return tmp; } #pragma endregion #pragma region 删除链表元素 /* 删除指定位置的链表节点 */ iterator erase(iterator position) { link_type next_node = link_type(position.node->next); link_type prev_node = link_type(position.node->prev); prev_node->next = next_node; next_node->prev = prev_node; destroy_node(position.node); return iterator(next_node); } /* 删除链表头节点 */ void pop_front(){ erase(begin()); } /* 删除链表尾节点 */ void pop_back() { iterator tmp = end(); erase(--tmp); } /* 清除整个链表 */ void clear() { link_type cur = (link_type)node->next; //拿到头结点 while (cur != node) { iterator tmp = cur; cur = (link_type)cur->next; destroy_node(tmp.node); } node->next = node; node->prev = node; } /* 移除节点值为 value 的链表节点 */ void remove(const T& value) { iterator first = begin(); iterator last = end(); while (first != last) { iterator next = first; ++next; if (*first == value)erase(first); first = next; } } /* 清除链表中连续存放的有相同节点值的元素 */ void unique(const T& value) { iterator first = begin(); iterator last = end(); if (first == last)return; iterator next = first; while (++next != last) { if (*first == *next) { erase(next); } else { first = next; } next = first; } } #pragma endregion }; } #endif
按照功能,我把list分为了4个region:
1. 内存控制、节点构造与析构;
2. 链表的查询操作;
3. 插入链表元素,包括头插和尾插;
4. 删除链表元素;
注释写的很详细,只是CSDN的代码编辑器太渣,网页上不能根据region折叠代码,有些童鞋看到大量代码会产生畏惧感,list的结构我截图如下:
最后我们测试一下_cghList,测试代码如下:
/******************************************************************* * Copyright(c) 2016 Chen Gonghao * All rights reserved. * * chengonghao@yeah.net * * 文件名称:_cghList的测试代码 ******************************************************************/ #include "stdafx.h" #include "cghAlloc.h" #include "globalConstruct.h" #include "_cghList.h" using namespace::std; int _tmain(int argc, _TCHAR* argv[]) { using namespace::CGH; _cghList<int> list; int i = 0; list.push_back(1); // 在list尾部插入1 list.push_back(2); // 在list尾部插入2 list.push_back(2); // 在list尾部插入2 list.push_back(2); // 在list尾部插入2 list.push_front(3); // 在list头部插入1 std::cout << "-----------------插入元素----------------" << endl; std::cout << "在list尾部依次插入1、2、2、2,在list头部插入3" << endl; // 取得list的长度 std::cout << "list的长度:" << list.size() << endl; // 遍历list for (_cghList<int>::iterator iter = list.begin(); iter != list.end(); iter++) { std::cout << "第" << i << "个元素:" << *iter << endl; i++; } std::cout << endl << endl << "-----------------值保留一个值等于2的元素----------------" << endl; // 值保留一个值等于2的元素 list.unique(2); // 取得list的长度 std::cout << "list的长度:" << list.size() << endl; // 遍历list i = 0; for (_cghList<int>::iterator iter = list.begin(); iter != list.end(); iter++) { std::cout << "第" << i << "个元素:" << *iter << endl; i++; } std::cout << endl << endl << "-----------------删除值等于2的元素----------------" << endl; list.remove(2);// 删除值等于2的元素 // 取得list的长度 std::cout << "list的长度:" << list.size() << endl; // 遍历list i = 0; for (_cghList<int>::iterator iter = list.begin(); iter != list.end(); iter++) { std::cout << "第" << i << "个元素:" << *iter << endl; i++; } std::cout << endl << endl << "-----------------清空list----------------" << endl; list.clear(); // 清空 // 取得list的长度 std::cout << "list的长度:" << list.size() << endl; // 遍历list i = 0; for (_cghList<int>::iterator iter = list.begin(); iter != list.end(); iter++) { std::cout << "第" << i << "个元素:" << *iter << endl; i++; } system("pause"); return 0; }
标签:
原文地址:http://blog.csdn.net/chengonghao/article/details/51442035