4 序列式容器

4.2 vector

template <class T, class Alloc = alloc>
class vector{
	typedef T value_type; typedef value_type* iterator;
	protected:
	iterator start; // 表示目前使用空間的頭
	iterator finish; // 表示目前使用空間的尾
	iterator end_of_storage;// 表示目前可用空間的尾
	...
};


成员函数举例:注意其中的内存管理

void vector<T, Alloc>::insert(iterator position, size_type n, const T& x)
{
	if (n != 0) { // 當n != 0 才進行以㆘所有動作
		if (size_type(end_of_storage - finish) >= n) {
			// 備用空間大於等於「新增元素個數」
			T x_copy = x;
			// 以㆘計算安插點之後的現有元素個數
			const size_type elems_after = finish - position;
			iterator old_finish = finish;
			if (elems_after > n) {
				// 「安插點之後的現有元素個數」大於「新增元素個數」
				uninitialized_copy(finish - n, finish, finish);
				finish += n; // 將vector 尾端標記後移
				copy_backward(position, old_finish - n, old_finish);
				fill(position, position + n, x_copy); // 從安插點開始填入新值
			}
			else {
				// 「安插點之後的現有元素個數」小於等於「新增元素個數」
				uninitialized_fill_n(finish, n - elems_after, x_copy);
				finish += n - elems_after;
				uninitialized_copy(position, old_finish, finish);
				finish += elems_after;
				fill(position, old_finish, x_copy);
			}
		}
		else {
			// 備用空間小於「新增元素個數」(那就必須配置額外的記憶體)
			// 首先決定新長度:舊長度的兩倍,或舊長度+新增元素個數。
			const size_type old_size = size();
			const size_type len = old_size + max(old_size, n);
			// 以㆘配置新的vector 空間
			iterator new_start = data_allocator::allocate(len);
			iterator new_finish = new_start;
			__STL_TRY {
				// 以㆘首先將舊vector 的安插點之前的元素複製到新空間。
				new_finish = uninitialized_copy(start, position, new_start);
				// 以㆘再將新增元素(初值皆為n)填入新空間。
				new_finish = uninitialized_fill_n(new_finish, n, x);
				// 以㆘再將舊vector 的安插點之後的元素複製到新空間。
				new_finish = uninitialized_copy(position, finish, new_finish);
			}
			# ifdef __STL_USE_EXCEPTIONS
			catch(...) {
				// 如有異常發生,實現"commit or rollback" semantics.
				destroy(new_start, new_finish);
				data_allocator::deallocate(new_start, len);
				throw;
			}
			# endif /* __STL_USE_EXCEPTIONS */
			// 以㆘清除並釋放舊的vector
			destroy(start, finish);   //全局函数
			deallocate();
			// 以㆘調整水位標記
			start = new_start;
			finish = new_finish;
			end_of_storage = new_start + len;
		}
	}
}


4.3 list

1、list的节点(node)

template <class T>
struct __list_node{
	typedef void* void_pointer;
	void_pointer prev;// 型別為void*。其实可設為__list_node<T>*
	void_pointer next;
T data;
};


2、list的迭代器

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 bidirectional_iterator_tag iterator_category;
	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;// 迭代器內部當然要有㆒個原生指標,指向list的節點
	// constructor
	__list_iterator(link_type x) : node(x) {}
	__list_iterator() {}
	__list_iterator(const iterator& x) : node(x.node) {}
	bool operator==(const self& x) const { return node == x.node; }
	bool operator!=(const self& x) const { return node != x.node; }
	// 以㆘對迭代器取值(dereference),取的是節點的資料值。
	reference operator*() const { return (*node).data; }
	// 以㆘是迭代器的成員存取(member access)運算子的標準作法。
	pointer operator->() const { return &(operator*()); }
	// 對迭代器累加1,就是前進㆒個節點
	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;
	}
};


 

3、list——实现为一个环状双向列表

template <class T, class Alloc = alloc> // 預設使用alloc 為配置器
class list{
protected:
	typedef __list_node<T> list_node;
public:
	typedef list_node* link_type;
protected:
	link_type node; // 只要㆒個指標,便可表示整个环状双向链表,node指向置于尾端的空节点	
	...
public:	
	iterator begin() { return (link_type)((*node).next); }
	iterator end() { return node; }	
};

4、元素操作
insert, push_front, push_back, erase, pop_front, pop_back, clear, remove, unique, splice, merge, reverse, sort

template <class T, class Alloc>
void list<T, Alloc>::unique() {
	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; // 修正區段范围
	}
}


list不能使用STL算法的sort(),必须使用自己的成员函数sort,因为STL算法sort()只接受RandomAccessIterator。

// 將[first,last) 內的所有元素搬移到position 之前。它是spice(), reserve(), merge()的基础。
void transfer(iterator position, iterator first, iterator last)

// “本函式採用quick sort”。这是书中原话,我觉得更像是归并排序的迭代形式。
template <class T, class Alloc>
void list<T, Alloc>::sort() {
	// 以㆘判斷,如果是空白串列,或僅有㆒個元素,就不做任何動作。
	// 使用size() == 0 || size() == 1 來判斷,雖然也可以,但是比較慢。
	if (node->next == node || link_type(node->next)->next == node)
		return;
	// ㆒些新的lists,做為㆗介資料存放區
	list<T, Alloc> carry;
	list<T, Alloc> counter[64];
	int fill = 0;
	while (!empty()) {
		carry.splice(carry.begin(), *this, begin());
		int i = 0;
		while(i < fill && !counter[i].empty()) {
			counter[i].merge(carry);
			carry.swap(counter[i++]);
		}
		carry.swap(counter[i]);
		if (i == fill) ++fill;
	}
	for (int i = 1; i < fill; ++i)
		counter[i].merge(counter[i-1]);
	swap(counter[fill-1]);
}

4.4 deque

虽然deque也提供random access iterator,但是并不是普通指针,所以尽可能使用vector。对deque进行的排序操作,为了最高效率,可将deque先完整复制到一个vector上,将vector排序后(利用STL sort算法),再复制会deque。

 

1、deque的中控器

deque采用一块所谓的map(不是STL的map容器),为一小块连续空间,其中每个元素都是指针,指向较大的连续线性空间(缓冲器),缓冲区才是deque的存储空间主体。

 

2、deque的迭代器

template <class T, class Ref, class Ptr,size_t BufSiz>
struct __deque_iterator{ // 未繼承std::iterator
	typedef __deque_iterator<T, T&, T*, BufSiz>  iterator;
	typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator;
	static size_t buffer_size() {return __deque_buf_size(BufSiz, sizeof(T)); }
	// 未繼承std::iterator,所以必須自行撰寫五個必要的迭代器相應型別(第3章)
	typedef random_access_iterator_tag iterator_category;
	typedef T value_type;
	typedef Ptr pointer;
	typedef Ref reference;
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	typedef T** map_pointer;
	typedef __deque_iterator self;
	// 保持與容器的聯結
	T* cur; // 此迭代器所指之緩衝區㆗的現行(current)元素
	T* first; // 此迭代器所指之緩衝區的頭
	T* last; // 此迭代器所指之緩衝區的尾(含備用空間)
	map_pointer node; // 指向管控㆗心
	...
};

// 以下實現隨機存取。迭代器可以直接跳躍n個距離。
self& operator+=(difference_type n) {
	difference_type offset = n + (cur - first);
	if (offset >= 0 && offset < difference_type(buffer_size()))
		// 標的位置在同㆒緩衝區內
		cur += n;
	else {
		// 標的位置不在同㆒緩衝區內
		difference_type node_offset =
			offset > 0 ? offset / difference_type(buffer_size())
				: -difference_type((-offset - 1) / buffer_size()) - 1;
		// 切換至正確的節點(亦即緩衝區)
		set_node(node + node_offset);
		// 切換至正確的元素
		cur = first + (offset - node_offset * difference_type(buffer_size()));
	}
	return *this;
}
// 參考 More Effective C++, item22: Consider using op= instead of
// stand-alone op.    A = B + n;
self operator+(difference_type n) const {
	self tmp = *this;
	return tmp +=n; // 喚起operator+=
}

 

3、deque的数据结构

template <class T, class Alloc = alloc, size_t BufSiz = 0>
class deque{
public:  // Basic types
	typedef T value_type;
	typedef value_type* pointer;
	typedef size_t size_type;
	typedef __deque_iterator<T, T&, T*, BufSiz> iterator;
protected:  // Internal typedefs
	// 元素的指標的指標(pointer of pointer of T)
	typedef pointer* map_pointer;
protected:  // Data members
	iterator start; // 表現第㆒個節點。
	iterator finish; // 表現最後㆒個節點
	map_pointer map; // 指向map,map是塊連續空間,其內的每個元素
	// 都是㆒個指標(稱為節點),指向㆒塊緩衝區。
	size_type map_size; // map內可容納多少指標。
	...
};
 
reference back() {
	iterator tmp = finish;
	--tmp; // 喚起__deque_iterator<>::operator--
	return *tmp;// 喚起__deque_iterator<>::operator*
	// 以㆖㆔行何不改為:return *(finish-1);
	// 因為__deque_iterator<> 沒有為(finish-1) 定義運算子?!
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值