2021年hznu寒假集訓第一天
技術標籤:c++
2021年hznu寒假集訓第一天
對於常用語言c++的認識
絕大部分情況下用C++(效率高、code速度快),少數情況用Java(有大數)、Python(相容度不高)
輸入cin >>a
輸出cout<<a
cout<<a<<endl = cout<<a<<"\n"
下面舉一個比較常見的輸出例子
cout<<i<<": "<<s1[i]<<endl
萬能標頭檔案 #include<bits/stdc++.h>
陣列儘量開大
時間(空間)複雜度
時間複雜度:又稱時間複雜性,用來描述程式執行時間與輸入資料規模的函式關係
演算法中基本操作重複執行的次數是問題規模n的某個函式,用T(n)表示,若有某個輔助函式f(n),使得當n趨近於無窮大時,T(n)/f (n)的極限值為不等於零的常數,則稱f(n)是T(n)的同數量級函式。記作T(n)=O(f(n)),稱O(f(n)) 為演算法的漸進時間複雜度,簡稱時間複雜度。
常見演算法的複雜度O(n) O(n^2)
O(nlogn) O(2^n)
類比於高等數學的極限學習就是高階與低階同時存在,我們只需要看高階的
STL
STL:C++標準模板庫(Standard Template Library)
函式:sort reverse next_permutation
String
string即動態長度字串。
在c語言之中,我們所用的字串是一種字元陣列,而在c語言當中,我們所用的才是真正意義上的字串。
建構函式
string s1="123";//"123"
string s2("123456");//"123456"
string s3(5,'a');//"aaaaa"
string s4("123456" ,3);//"123"
string s5("123456",2,4);//"3456"
迭代器
本質就是指標
string::iterator it;
// string是stl裡面的容器名稱,指標的名稱叫做it
string::iterator it=s2.begin();
it++;//即指向下一個
cout<<(*it)<<endl;
還有一種就是s2.end();
begin是首位置,end是末位置
不同的是 s2是指向末位置之後的那個位置,因為在工程裡面,大部分寫區間都是左閉右開。
因為string::iterator比較長,我們可以直接寫auto,auto即自動,自動去識別右邊型別,讓左邊的型別等於它。
常用函式
s2.clear();
//清空s2
s2.length();
//s2的長度
s2.append("123");
//在s2後面加上字串"123" 等同於+="123"
//c++的字串之間可以直接比較,這一點也區分與c語言
s2.push_back('1');
//與append不同,push_back只能加字元
//其實在更多時候,我們直接用+=就好
int p=s2.find("12");
//尋找s2中字串"12"的位置,如果找到,輸出位置,否則輸出-1
s2.erase(s2.begin());
//把s2的首字元刪除
s2.erase(s2.begin(),s2.begin()+3);
//s2的首位置到+3的位置刪除
vector
動態陣列,記憶體連續
因為動態陣列,無需設定大小,可以解決陣列不夠大的問題。
寫法:
vector<int>v1;
vector<int>v2(2);
//v2數組裡面全是2;
vector<int>v3({1,2,3,4,5});
//v3數組裡面存放的就是1,2,3,4,5
vector<int>v4(v3);
//v4拷貝陣列v3;
內部原理:
比如一開始放入一個1;
此時容量是1,大小也是1;
如果要再放一個2,肯定是放不下的,就要重新擴充套件一個空間,容量是2,大小也是2;
如果要再放一個3,又放不下,要重新擴充套件一個空間,容量是4,大小是3的
每次開闢都是翻一倍
常用函式
a=v3.size();
//v3裡有幾個元素,v3.size就是幾
v3.push_back(7);
//在陣列末尾新增一個數7
v3.pop_back();
//將尾部元素刪除
v3.empty();
//如果v3為空,返回true,否則返回false
a=v3.front();
//a=v3(0);
a=v3.back();
//a=v3(v3.size()-1);
v3.insert(v3.begin(),4);
//在第一個位置之前插入4這個元素
v3.erase(v3.begin());
//把v3的首個元素刪除
v3.erase(v3.begin(),v3.begin()+3);
//s2的首位置到+3的位置的元素刪除刪除
queue
佇列,先進先出(FIFO) 不支援下標訪問
印表機,排隊隊伍都是佇列模型
寫法:
queue<int>qu;
//與前面的vector相同
常用函式:
qu.push(1);
//拉來一個1元素
qu.pop();
//走了1個元素
qu.front();
//佇列中的第一個元素
qu.back();
//佇列中的最後一個元素
qu.size();
//佇列裡共有幾個元素
qu.empty();
//如果qu為空,返回true,否則返回false
也可以用陣列來模擬
stack
堆疊,先進後出(FILO)
類似於人依次卡在井中,後卡住的人可以先出來
寫法:
stack<int>st;
常用函式:
st.push(1);
st.push(2);
st.push(3);
//依次掉進來元素1,2,3
st.pop();
//那麼3先出去
st.top();
//相當於front的東西,因為是掉進井裡,所以用top
st.size();
st.empty();
set
集合,元素有序排列,不重複
寫法:
set<int>se;
常用函式:
se.insert(1);
//集合se中插入一個元素1,不管插入幾次1,集合中只會存在一個1
se.erase(1);
//把集合se中的1給刪除掉
se.erase(se.begin());
//也可以使用迭代器,把se的第一個元素刪掉
se.clear();
se.size();
//同上
se.count(1);
//返回集合中1的個數,因為集合中至多存在一個,所以常拿來判斷是否存在該元素
se.find(1);
//如果存在,則返回迭代器位置;否則,se.find(1)=se.end()
lower_bound(x);
//大於等於x的第一個元素位置,不存在返回end()
upper_bound(x);
//大於x的第一個元素位置,不存在返回end()
erase在刪除這個數之後,會把他之後的迭代器給返回。
如果erase刪除的元素不存在,那其實還會正常執行,不過不影響罷了。
先舉一個錯誤案例
int main(){
set<int>se;
for(int i=1;i<=10;i++){
se.insert(i);
}
for(auto it=se.begin();it!=se.end();it++){
if((*it)%2==1){
se.erase(it);
}
}
for(auto x:se){
cout<<x<<endl;
}
}
因為it的迭代器還指在這個位置,你就給他刪了,接下來他就不知道跑哪裡去了。
正確做法
int main(){
set<int>se;
for(int i=1;i<=10;i++){
se.insert(i);
}
for(auto it=se.begin();it!=se.end();){
if((*it)%2==1){
it=se.erase(it);
}
else{
it++;
}
}
for(auto x:se){
cout<<x<<endl;
}
}
查詢、插入、刪除O(logn)
map
字典,key-value鍵值對,按key有序排列
寫法:
map<int,int>mp;
例子:
map<int,int>mp;
mp[6]=2;
mp[4]=123;
for(auto it=mp.begin();it!=mp.end();it++){
cout<<(it->first)<<" "<<(it->second)<<endl;
}
輸出
6 2
4 123
常用函式:
mp.find();
mp.erase(6);
//可以直接用key來刪除
mp.erase(mp.find(6));
//也可以通過找key的迭代器位置來刪除;
mp.size();
//字典大小
lower_bound(x);
upper_bound(y);
//同集合,不過是對key來說
mp.count();
//同集合
在查詢時直接輸出很容易冗餘,所以我們常用
if(mp.count(100))cout<<mp[100];
也可以像陣列一樣通過[]訪問
插入刪除O(logn)
list
雙向連結串列,內容不連續
寫法:
list<int>li;
例子:
li.push_back(5);
li.push_front(6);
for(int x:li)cout<<x<<endl;
輸出
5
6
常用函式:
li.push_back(5);
//連結串列在尾部新增5;
li.push_front(6);
//連結串列在頭部新增6;
li.insert(it,10);
//(使用前要先設定迭代器)在it位置前插入10
li.erase(it);
//把it位置上的數刪掉
li.pop_back();
//刪除最後一個元素
li.pop_front();
//刪除第一個元素
不支援隨機訪問,插入、刪除O(1),與vector相反
list在acm比賽用到的不多,基本是用不到的
常見的三個函式
sort
寫法:
sort(x+1,x+1+n);
//x+1首位置,x+1+n末尾位置,排完之後從小到大
sort(x+1,x+1+n,greater<int>());
//排完之後從大到小
//此外還有一種寫法
bool cmp(int a,int b){
return a>b;
}
sort(x+1,x+1+n,cmp);
//
sort(x+1,x+1+n,[](int a,int b){
if(a%2==b%2)return a<b;
return a%2>b%2;
});
reverse
翻轉陣列,容器
寫法:
int x[1005];
reverse(x+1,x+1+n);
vector<int>ve;
reverse(ve.begin(),ve.end());
next_permutation
求全排列中字典序更大的一個序列,不存在更大時返回false
int x[105];
int n=5;
for(int i=1;i<=n;i++)x[i]=i;
do{
for(int i=1;i<=n;i++)printf("%d ",x[i]);
puts("");
}while(next_permutation(x+1,x+1+n));
pre_permutation與之相反,是一個更小的序列