HT-H_On 模板【ps:希望有朝一日能出一個HTL(H_On 標準模板庫)呢 嘿嘿
起源
要說起猹開發這些模板的原因呢~一個是大家也知道,猹這個寒假更新了STL的介紹,兩篇!可以說是人生第一次經歷了大量練習獲得了很多知識
要說直接原因,就是昨天打 CF 的時候 sages7 給我推薦了一個好用的 cf 小工具,可以自動爬取比賽題對外的測試數據,還可以用命令測試提交代碼。然後它支持在生成的題目文件夾裏生成一個編程代碼模板,這個是自己給定的。正好我早就想優化一下我的那些亂七八糟的代碼了,於是趁此機會,整活一天終於獲得了一些收穫,現在迫不及待的開始寫分享博客了owo
其實我想優化代碼的想法很久了,不知道大家有沒有遇到這種情況,有時候會經常時不時的就需要寫一些比較結構體,用來讓 set 按降序排列,可是有時候是排 int 元素有時候是 long long 還有時候甚至是 string ,那麼就算把比較結構體的大框架留下來,每次使用都可能需要修改一堆變量類型名,由於 STL 那些容器都可以隨意的設置元素的變量類型,所以我也想整一個全類型通用比較結構體。
實際上以前什麼兩數交換啊,求兩個數的最小公倍數這兩個函數,猹也都是憨憨每次都自己手寫,也經常因爲變量類型不通用而煩惱。於是這次我找了好多網頁,甚至查閱了源代碼,最終初窺門徑了!
先說說比較好用但其實沒啥用的交換函數
這個函數是真的,很簡單,但是每次對於不同的變量都要重寫真的好麻煩(要改三個地方的變量類型呢),於是我先研究的這個。
template <class H_On> void EX(H_On &a, H_On &b) {
H_On t = a;
a = b;
b = t;
}
H_On
的地方就是每次要交換的變量類型不一樣的地方要改的,尤其是經歷了昨晚我在最後一分鐘交了一道題,還沒判過比賽就結束了,但最後是 AC 之後,我真心感覺能節約幾秒都是好的,可是總是改真的很煩啊,經歷過就知道辣 > m <
總而言之呢,這樣子一來,我再無論怎麼用 EX() 這個函數,不管丟進去什麼類型的變量都可以互換辣,開心。
ps:其實 <algorithm>
庫裏有一個函數叫 swap()
,底層就是用這種模板類型的方式實現的,甚至對整型變量還有特異優化。這個函數也是我在 跟 sages7 討論我的想法的時候跟我說的 消磨猹探索積極性的 sages7 是屑,還好他沒成功
然後是也沒啥用的求最大公約數函數
這個函數的話也是時不時就會用到的,但是會遇到有時候用 int 有時候用 long long 所以其實也是有這個需求的。
template <class H_On> H_On GCD(H_On a, H_On b) {
if (!b) return a;
if (!a) return b;
while (b) {
H_On t = a % b;
a = b;
b = t;
}
return a;
}
跟上面那個類似只不過 還多了一個返回值,然後爲什麼說沒用呢,因爲其實 <algorithm>
庫裏還有一個函數 __gcd()
也是可以求最大公約數的
比較重要的 - 自定義比較結構體和一些常數的定義
STL 常備自定義比較結構體
我們在使用 set/multiset 容器的時候經常會遇到需要將默認升序排序變成降序排序的情況,而同樣的,就算是我們只保留簡單的換順序的排序規則,也時常遇到變量類型要換的情況,所以這裏給出了這個,同樣是用模板類實現的
template <class H_On_compT> struct hon_cmp {
bool operator () (const H_On_compT &a, const H_On_compT &b) {
return a > b;
}
};
這時候直接寫 set<T, hon_cmp<T>>
即可,注意,要寫兩個變量類型而且要一樣
例如:set<int, hon_cmp<int>> s;
這樣子再往集合容器 s 中插入元素時就會默認是升序排列啦。
常用常數的多類型定義
同樣是 int 和 long long 的問題,但是這裏要注意,因爲不是函數而是直接獲取一個變量,或者說我需要直接獲取一個數,一個固定值,所以這裏我用了另一種方式,就是使用模板變量的形式然後使用類來生成一個對象,作爲我們需要的變量
template <typename H_On_infnT> class infn {
public:
H_On_infnT N;
infn(H_On_infnT honValue) {
this->N = honValue;
}
};
template <typename H_On_maxnT> class maxn {
public:
H_On_maxnT N;
maxn(H_On_maxnT honValue) {
this->N = honValue;
}
};
這裏要簡單的介紹一下使用方法,有點不太好探索
infn<int> INF(int(1e9 + 9));
maxn<string> MAX("nihao");
cout << "inf = " << INF.N << endl;
cout << "max = " << MAX.N << endl;
輸出就長這樣
inf = 1000000009
max = nihao
如你所見,支持全類型的特殊功能定義。
閒言碎語
最後還是猹的無聊自言自語,猹其實是喜歡把所有常用的東西都寫上,但是爲了明確我用到了哪那個功能,會把所有的東西都儘量寫成一行,然後用到哪行把哪行註釋掉,如下所示是猹完成的模板
#include <iostream>
using namespace std;
//#include <cmath>
//#include <set>
//#include <map> //map<int, int, greater<int>> m;
//#include <stack>
//#include <vector>
//#include <deque>
//#include <bitset>
//#include <algorithm> //__gcd(), swap()
//#include <iomanip>
//#define dfos(outStep) fixed << setprecision(outStep)
//typedef long long ll;
//template <typename H_On_infnT> class infn {public: H_On_infnT N; infn(H_On_infnT honValue) {this->N = honValue;}};
//template <typename H_On_maxnT> class maxn {public: H_On_maxnT N; maxn(H_On_maxnT honValue) {this->N = honValue;}};
//template <class H_On_compT> struct hon_cmp {bool operator () (const H_On_compT &a, const H_On_compT &b) {return a > b;}};
int main() {
ios::sync_with_stdio(0); cin.tie(0);
int t; cin >> t;
while (t--) {
}
return 0;
}
可以看到,全部都一行註釋掉,還會加一些暫時不熟練的用法或者函數的註釋,然後用到那個函數庫或者預定義就取消掉註釋,實在不喜歡有些人提交的代碼有很多沒用的東西,當然這只是個人看法。沒準有一天猹也會因爲覺得麻煩而提交一大堆沒用的代碼,誰知道呢 =w=
最主要的是希望各位如果還是比較新手的階段,不要對知識不求甚解,僅僅知道用法不知道原理,這樣是不對的。
今天一整天,爲了做這個查了好多人家的文章,還翻了幾個小時的底層實現 vector 啊什麼的容器的源代碼,總算是搞清了一點點 “模板” 的工作原理,總歸做出來了還是挺開心的
最後祝大家學習快樂,天天進步 揮揮~
請多多支持猹的個人博客 H_On 個人小站 啊啊啊~拜託惹 > ~ <
因爲猹的小站真的還挺可的,所以那邊更新的也比較勤奮,感謝關注~我會努力的(ง •_•)ง