国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C++進階之路】適配器、反向迭代器、仿函數(shù)

這篇具有很好參考價值的文章主要介紹了【C++進階之路】適配器、反向迭代器、仿函數(shù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

我們先來籠統(tǒng)的介紹一下今天的三個內(nèi)容。

  • 適配器——簡單的理解就是復(fù)用,用已經(jīng)實現(xiàn)的輪子,來繼續(xù)實現(xiàn)某種功能。

  • 反向迭代器——原理很簡單,就是對稱+復(fù)用(已經(jīng)造好的正向迭代器)

  • 仿函數(shù)——與函數(shù)用法相同的類,用于排序,比如大堆,小堆,升序,降序。

一、適配器

適配器的功能,在我們模擬實現(xiàn)棧和對列時十分方便!
先用這兩個例子感受一下。

①模擬實現(xiàn)棧

	template<class T,class Con = deque<T>>
	class stack
	{
	public:
	
		void push(const T& val)
		{
			st.push_back(val);
		}
		void pop()
		{
			st.pop_back();
		}
		T& top()
		{
			return st[st.size() - 1];
		}
		size_t size()
		{
			return st.size();
		}
		bool empty()
		{
			return st.empty();
		}
	private:
		Con st;
	};

②模擬實現(xiàn)對列

	template<class T, class Con = deque<T>>
	class queue
	{
	public:
		void push(const T& val)
		{
			qu.push_back(val);
		}
		void pop()
		{
			qu.pop_front();
		}
		T& front()
		{
			return qu[0];
		}
		size_t size()
		{
			return qu.size();
		}
		bool empty()
		{
			return qu.empty();
		}
	private:
		Con qu;
	};

這里的模板參數(shù):

template<class T, class Con = deque<T>>
				//這就是適配器
				

看完這兩個例子,你可能會明白,并且可能會驚訝于適配器的方便之處。

并且這里也給了模板一個用法——缺省參數(shù)

且如果是全缺省的話,我們示例化還是要給參數(shù)列表的。

如下:

stack<> st;

再來談?wù)刣eque,你可能會好奇,這里在棧的第二個缺省參數(shù)為啥不給vector<T>, 對列的第二個缺省參數(shù)為啥不給list<T>

要弄清楚原因我們先得了解deque的基本結(jié)構(gòu):

【C++進階之路】適配器、反向迭代器、仿函數(shù),C++進階之路,c++,筆記

我們知道這個中控數(shù)組一旦滿了,就要考慮擴容的問題,那該如何擴呢?

只需要將中控數(shù)組進行擴容,然后將指針拷貝過去即可。

因此相較于vector無需動數(shù)據(jù)即可完成擴容!—— 提高了擴容的效率。

相較于vector,這種結(jié)構(gòu)也支持隨機訪問,不過得通過計算,這樣高頻率的隨機訪問效率會降低,緩沖命中率也有一定的下降。

相較于list,由于list是單個申請單個釋放,因此deque的緩沖命中率較高。

但是相較于list,如果deque要在中間插入數(shù)據(jù),那效率就會降低,這一點不如list。

這樣:

  1. stack結(jié)構(gòu),實現(xiàn)尾插尾刪功能,如果要考慮擴容的效率,deque的優(yōu)勢更大。
  2. queue結(jié)構(gòu),實現(xiàn)尾插頭刪功能,如果要考慮到緩沖命中率,deque的優(yōu)勢更大。

因此庫里采用了deque來實現(xiàn)棧和對列!

二、反向迭代器

我們先來看庫里的實現(xiàn)方式:

  • vector
    【C++進階之路】適配器、反向迭代器、仿函數(shù),C++進階之路,c++,筆記
  • list
    【C++進階之路】適配器、反向迭代器、仿函數(shù),C++進階之路,c++,筆記

可以看到,這里呈現(xiàn)對稱的方式,但是如何解引用是關(guān)鍵。

庫里是這樣實現(xiàn)的:

Reverse_iterator operator* ()
{
	Iterator tmp(_it);
	return *--tmp;
}

這里使用了正向迭代器的拷貝構(gòu)造,然后再減減訪問反向迭代器的下一個元素,這樣實現(xiàn)了錯位,也能剛好利用實現(xiàn)好的正向迭代器。

剩余的就不難實現(xiàn)了:

	template<class Iterator, class Ref, class Ptr>
	struct Reverse_iterator
	{
		typedef Reverse_iterator<Iterator, Ref, Ptr> self;
		//自定義的類型不能被當(dāng)做類名進行使用
		
	
		Reverse_iterator(const Iterator& it)
		{
			_it = it;
		}
		
		self& operator ++()
		{
			_it--;
			return *this;
		}
		self operator ++(int)
		{
			self tmp(_it);
			_it--;
			return self;
		}
		Ref operator* ()
		{
			Iterator tmp(_it);
	
			return *--tmp;
		}
		Ptr operator->()
		{
			return _it.operator->();
		}
		bool operator!=(const Reverse_iterator&it)const
		{
			return _it != it._it;
	
		}
		bool operator==(const Reverse_iterator& it)const
		{
			return _it == it._it;
		}
		Iterator _it;
	};

然后我們只需在容器里加上下面的代碼即可完成復(fù)用!

		typedef list_iterator<T,T&,T*> iterator;
		typedef list_iterator<T,const T&,const T*> const_iterator;

		typedef Reverse_iterator<iterator, T, T*> reverse_iterator;
		typedef Reverse_iterator <const_iterator, const T, const T*>\
		 const_reverse_iterator;
		 
		reverse_iterator rbegin()
		{
			return end();
			//這里會調(diào)用拷貝構(gòu)造
		}
		reverse_iterator rend()
		{
			return begin();
		}

三、仿函數(shù)

我們這里先實現(xiàn)一個優(yōu)先級對列——大堆。

	template<class T,class Container = vector<T>>
	class priority_queue
	{
		//建大堆
		void AdjustDown(int parent)
		{
			//假設(shè)左孩子較大
			size_t child = parent * 2 + 1;
			//因為是往下比較,所以child應(yīng)在范圍內(nèi)
			while (child < con.size())
			{
				//先選出來較大的孩子,當(dāng)然前提得存在。
				if (child + 1 < con.size() && con[child] < con[child + 1])
				{
					child = child + 1;
				}
				//再跟父節(jié)點進行比較,如果孩子大就換
				if (con[parent]< con[child])
				{
					swap(con[parent], con[child]);
					//因為是向下比較的,所以要看parent是不是還比下面的孩子大。
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		//建大堆
		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			while (parent >= 0)
			{
				if (con[parent] < con[child])
				{
					swap(con[parent], con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
	public:

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			InputIterator it = first;
			while (it != last)
			{
				con.push_back(*it);
				it++;
			}
			//進行調(diào)堆
			//從最后一個葉子結(jié)點的父節(jié)點開始。

			//時間復(fù)雜度O(N)
			for (int i = ((con.size() - 1) - 1) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}
		void pop()
		{
			swap(con[0], con[con.size() - 1]);
			con.pop_back();
			AdjustDown(0);
		}
		void push(const T& val)
		{
			con.push_back(val);
			AdjustUp(con.size() - 1);
		}
		size_t size()
		{
			return con.size();
		}
		bool empty()
		{
			return con.empty();
		}
		T top()const
		{
			return con[0];
		}
		
		priority_queue()
		{}
	private:
		Container con;
	};

這里的大堆算是實現(xiàn)了,借助這二叉樹的一點點知識。

  • 那如果我們還要實現(xiàn)小堆呢?

用不用cv一份,再改呢?其實不用,只需要寫一個仿函數(shù)即可。

	template<class T>
	struct Less
	{
		bool operator()(const T &x1 ,const T& x2)
		{
			return x1 < x2;
		}
	};
	template<class T>
	struct Greater
	{
		bool operator()(const T& x1, const T& x2)
		{
			return x1 > x2;
		}
	};

如何使用呢?用類模板+重載函數(shù)的掉用。

template<class T,class Container = vector<T>,class Compare = Less<T>>
class priority_queue
{
	//建大堆
	void AdjustDown(int parent)
	{
		//假設(shè)左孩子較大
		size_t child = parent * 2 + 1;
		//因為是往下比較,所以child應(yīng)在范圍內(nèi)
		while (child < con.size())
		{
			//先選出來較大的孩子,當(dāng)然前提得存在。
			if (child + 1 < con.size() && com(con[child] , con[child + 1]))
			{
				child = child + 1;
			}
			//再跟父節(jié)點進行比較,如果孩子大就換
			if (com(con[parent], con[child]))
			{
				swap(con[parent], con[child]);
				//因為是向下比較的,所以要看parent是不是還比下面的孩子大。
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
	//建大堆
	void AdjustUp(int child)
	{
		int parent = (child - 1) / 2;
		while (parent >= 0)
		{
			if (com(con[parent] , con[child]))
			{
				std::swap(con[parent], con[child]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
public:

	template<class InputIterator>
	priority_queue(InputIterator first, InputIterator last)
	{
		InputIterator it = first;
		while (it != last)
		{
			con.push_back(*it);
			it++;
		}
		//進行調(diào)堆
		//從最后一個葉子結(jié)點的父節(jié)點開始。

		//時間復(fù)雜度O(N)
		for (int i = ((con.size() - 1) - 1) / 2; i >= 0; i--)
		{
			AdjustDown(i);
		}
	}
	void pop()
	{
		swap(con[0], con[con.size() - 1]);
		con.pop_back();
		AdjustDown(0);
	}
	void push(const T& val)
	{
		con.push_back(val);
		AdjustUp(con.size() - 1);
	}
	size_t size()
	{
		return con.size();
	}
	bool empty()
	{
		return con.empty();
	}
	T top()const
	{
		return con[0];
	}
	priority_queue()
	{}
private:
	Container con;
	Compare com;
};

這樣既可以當(dāng)做大堆使用,也可以當(dāng)做小堆使用。

總結(jié)

?今天的分享就到這里了,如果覺得文章不錯,點個贊鼓勵一下吧!我們下篇文章再見!文章來源地址http://www.zghlxwxcb.cn/news/detail-600738.html

到了這里,關(guān)于【C++進階之路】適配器、反向迭代器、仿函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包