(顺序容器类)双端队列应用:一个非常长的整数类

deque类可能的字段:

template <class T>
class deque
{
	T *map[NUMS];
	// 映射数组(指针数组): 指向保存项的连续存储块
	// 块: 大小相同,其中能保存的项的数量是————1KB/项的大小
protected:
	class iterator
	{
		T *first;	// 指向包含项 X 的块的第一个项
		T *current;	// 指向项 X 的指针
		T *last;	// 指向包含项 X 的块的尾部的下一个单元的指针
		T **node;	// 指向 map 中单元的指针,其中 map 指向包含项 X 的块首
	};
	static iterator start;	// 指向双端队列的第一个存储块
	static iterator finish;	// 指向双端队列的最后一个存储块
};
deque类的实现:

假设每个块能保存五个项,并且deque对象pets包含了11个这样的项,依次是:"dog", "cat", "pig", "gerbil", "canary", "duck", "cow", "horse", "parrot", "fox", "rabbit"。图1显示了如何表示deque对象pets,使用问号指示未使用的单元。



然后执行

pets.pop_front();

pets.push_back("mouse");

pets.push_back("iguana"); // 超出块尾,必须分配一个新的块


假设双端队列迭代器 itr 位于图2的双端队列中的项 ”duck"。图3显示了迭代器 itr、start、finish 的字段的值。(带反斜线的框表示紧随块尾之后 的单元)


然后执行 pets[9] = "goose";,过程如下

1)项 0 在第一块中的偏移量是4 —— start.current  - start.first = 4

2)所求块号是 2 —— (项 0 的偏移量4 + 下标9)/ 块的大小5 = 2

3)所求块的偏移量是 3 —— (项 0 的偏移量4 + 下标9)% 块的大小5 = 3

因此块2中偏移量为3的位置上的项 “rabbit" 被替换成 ”goose"。


当所有映射指针指向的块都被使用而又需要另一个块时,map大小将加倍,并且旧的指针将位于新的map数组的中间。


deque好于vector的地方:

1)调整大小时没有项的移动。

当在deque的头尾插入时需要一个额外的块(或者map太小了),不需要移动deque的任何一项; vector中调整大小需要移动所有的项;

2)deque可在头和尾快速插入。

vector只适合尾部快速插入,vector甚至没有 push_front() 和 pop_front()方法

3)deque可回收未使用的块。

vector只会增长,不会收缩。

4)对内部的插入和删除,deque比vector少几次数据移动。

deque差于vector的地方:

deque需要模运算将下标转换成块地址。实际上,除非大多数操作都位于或接近容器的开头,否则 vector 是比 deque 快的。


由于deque和vector的大部分方法相同,只需将 vector 的 “一个非常长的整数类”  少许改动,可以正常运行。

头文件中:

vector<char> digits;  改成  deque<char> digits;

实现文件中修改 operator+如下:

very_long_int very_long_int::operator+(const very_long_int& other_very_long) const
{
	very_long_int sum;	// 和(返回值)
	int carry = 0,		// 进位值
		small_size,		// *this和other_very_long对象位数较小者
		big_size,		// *this和other_very_long对象位数较大者
		value;			// *this和other_very_long对象位数相加的和
	if (digits.size() > other_very_long.digits.size()){
		big_size = digits.size();
		small_size = other_very_long.digits.size();
	}
	else{
		big_size = other_very_long.digits.size();
		small_size = digits.size();
	}
	deque<char>::const_iterator iter1 = digits.end(),
		iter2 = other_very_long.digits.end();	//const_iterator用于遍历const容器
	for (int i = 0; i < big_size; i++){
		if (i < small_size){
			iter1--; iter2--;
			value = *iter1 + *iter2 + carry;
			carry = value / 10;		// 是否产生进位
			sum.digits.push_front(value % 10);	// 双端队列头部插入
		}	// 个位数为 sum.digits[0],应为 sum.digits[sum.digits.size()-1];
		else if (big_size == digits.size()){
			iter1--;
			value = *iter1 + carry;
			carry = value / 10;		// 是否产生进位
			sum.digits.push_front(value % 10);
		}
		else if (big_size == other_very_long.digits.size()){
			iter2--;
			value = *iter2 + carry;
			carry = value / 10;		// 是否产生进位
			sum.digits.push_front(value % 10);
		}
	}
	if (carry == 1)		// 是否产生新位
		sum.digits.push_front(carry);
//	reverse(sum.digits.begin(), sum.digits.end());	// 反转sum.digits中各元素的顺序
	return sum;
}
实现文件中修改 factorial()方法如下:(使用递归)

very_long_int very_long_int::factorial(int n) const
{
	very_long_int temp = *this,
		sum = *this;
	if (n == 0){
		sum.digits.erase(sum.digits.begin(), sum.digits.end());	// 释放sum占用的所有内存
		sum.digits.push_back('0'-'0');	// 分配一个字节存储 0
	}
	if (n == 1)
		return *this;
	else{
		return  *this * factorial(n-1);	// 递归求阶乘
	}
}

运行结果:




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值