算法學習——STL和基本數據結構

第一次接觸算法,只是照着自己的方法學習的,總結寫的可能不是會很好,但我會努力改進。

#STL容器包括順序式容器和關聯式容器。

順序式容器:

·vector:動態數組,從末尾能快速插入與刪除,直接訪問任何元素。

·list:雙鏈表,從任何地方快速插入與刪除。

·deque:雙向隊列,從前面或後面快速插入與刪除,直接訪問任何元素。

·queue:隊列,先進先出

·priority_queue:優先隊列,最高優先級元素總是第一個出列。

·stack:棧,先進後出。

關聯式容器:

·set:集合,快速查找,不允許重複值

·multiset:快速查找,允許重複值

·map:一對多映射,基於關鍵字快速查找,不允許重複值

·multimap:一對多映射,基於關鍵字快速查找,允許重複值

1.vector

vector是STL的動態數組,在運行時能根據需要改變數組大小。

vector容器是一個模板類,能存放任何類型的對象。

·定義:

功能                                 例子                                               說明

定義int型數組                  vector<int>a;                                  默認初始化,a爲空

                                       vector<int>b(a);                              用a定義b

                                        vector<int>a(100);                         a有100個值爲0的元素

                                        vector<int>a(100,6);                      100個值爲6的元素

定義string型數組             vector<string>a(10,"null");             10個值爲null的元素

                                        vector<string>vec(10,"hello");       10個值爲hello的元素

                                        vector<string>b(a.begin(),a.end()); b是a的複製

定義結構型數組               struct point{int x,y;};                          a用來存座標

                                         vector<point>a;                                同上

用戶還可以定義多維數組,例如定義一個二維數組:

vector<int>a[MAXN];

它的第一維大小是固定的MAXN,第二位是動態的。用這個方式可以實現圖的鄰接表存儲,細節見:https://oi-wiki.org/lang/csl/sequence-container/

常用操作等等,詳見https://oi-wiki.org/lang/csl/sequence-container/

例子:hdu4841 “圓桌問題”  https://vjudge.net/contest/337673#problem

題目大意:類似約瑟夫環問題

解題思路:利用vector容器解題,刪除壞人,留下好人,對於好人輸出G,對於壞人輸出B

代碼:

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int main(){
	vector<int>table;
	int n,m;//模擬圓桌
	while(cin>>n>>m){
		table.clear();//清空圓桌
		for(int i=0;i<2*n;i++) table.push_back(i);//初始化 
		int pos=0; //記錄當前位置
		for(int i=0;i<n;i++){//趕走n個人 
			pos=(pos+m-1)%table.size();//圓桌是個環,做取餘處理 
			table.erase(table.begin()+pos);//刪除壞人,讓人數減一 
		} 
		int j=0;
		for(int i=0;i<2*n;i++){//打印預先安排座位 
			if(!(i%50)&&i)  cout<<endl; //50字母一行
			if(j<table.size()&&i==table[j]){//table留下來的都是好人 
				j++;
				cout<<"G"; 
			} 
			else
			cout<<"B";
		}
		cout<<endl<<endl;//留一個空行 
	} 
	return 0;
}

  2.棧和stack

棧:先進後出

棧的有關操作:

stack<Type>s;  //定義棧,Type爲數據類型,例如int,float,char等

s.push(item);   //把item放到棧頂

s.top();         //返回棧頂的元素,但不會刪除

s.pop();          //刪除棧頂的元素,但不會返回.在出棧時需要進行兩步操作,即先top()獲得棧頂元素,再pop()刪除棧頂元素

s.size();         //返回棧中元素的個數

s.empty();      //檢查棧是否爲空,如果爲空,返回true,否則返回false

爆棧問題:https://blog.csdn.net/weixin_34342905/article/details/93207342

更多詳見:https://oi-wiki.org/ds/stack/

例子:hdu1062”Text Reverse“   https://vjudge.net/contest/337673#problem/B

題目大意:反轉字符串

解題思路:利用棧特性,進行儲存,再輸出。

代碼:

#include<iostream>
#include<stack>
using namespace std;
int main(){
	int n;
	char ch;
	scanf("%d",&n); getchar();
	while(n--){
		stack<char>s;
		while(true){
			ch=getchar();//一次讀入一個字符 
			if(ch==' '||ch=='\n'||ch==EOF){
				while(!s.empty()){
					printf("%c",s.top()) ;//輸出棧頂 
				s.pop();//清除棧頂 
			}
			if(ch=='\n'||ch==EOF)  break;
			printf(" ");
		}
		else s.push(ch);//入棧 
	}
	printf("\n");
}
return 0; 
}

 例子:hdu1237“簡單計算器”  https://vjudge.net/contest/337673#problem/C

題目大意:如上

題目思路:利用棧的操作,中間用2個棧導了一下

代碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a[4],hash1[4],vis[4],hash2[10000];
int flag,temp,cnt;
void Show(){
    int num = hash1[0] * 1000 + hash1[1] * 100 + hash1[2] * 10 + hash1[3];
    if(hash2[num]) return;
    else{
        hash2[num] = 1;
        if(temp != hash1[0]){
            cnt = 0;
            temp = hash1[0];
            flag++;
            if(flag) printf("\n");
        }
 
        if(cnt != 0) printf(" ");
        for(int i = 0;i < 4;i++){
            printf("%d",hash1[i]);
        }
        cnt++;
    }
    return ;
}
void Dfs(int x){
    if(x == 4){
        Show();
        return ;
    }
    for(int i = 0;i < 4;i++){
        if(x == 0 && a[i] == 0)continue;
        if(!vis[i]){
            hash1[x] = a[i];
            vis[i] = 1;
            Dfs(x + 1);
            vis[i] = 0;
        }
    }
}
int main(){
    int k = 0;
    while(~scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3])){
        if(!a[0] && !a[1] && !a[2] && !a[3]) break;
        if(k)printf("\n");
        sort(a,a+4);
        memset(hash1,0,sizeof(hash1));
        memset(hash2,0,sizeof(hash2));
        memset(vis,0,sizeof(vis));
        temp = -1,flag = -1,cnt = 0;
        Dfs(0);
        printf("\n");
        k++;
    }
    return 0;
}

 

3.隊列和queue

隊列:先進先出

隊列的有關操作:

queue<Type>q;   //定義隊列,Type爲數據類型,例如int,float,char等

q.push(item);       //把item放進隊列

q.front();               //返回隊首元素,但不會刪除

q.pop();                //刪除隊首元素

q.back();               //返回隊尾元素

q.size();                //返回元素個數

q.empty();             //檢查隊列是否爲空

詳情見:https://oi-wiki.org/ds/queue/#_4

例子:hdu1702“acboy needs your help again!”    https://vjudge.net/contest/337673#problem/D

題目大意:利用站和隊列的特性,輸出東西

題目思路:定義站和隊列,利用循環結構和判斷條件,將符合要求的數據push進站和隊列,然後按要求輸出

代碼:

#include<iostream>
#include<stack>
#include<queue>
#include<string>
using namespace std;
int main(){
	int t,n,temp;
	cin>>t;
	while(t--){
		string str,str1;
		queue<int>Q;
		stack<int>S;
		cin>>n>>str;
		for(int i=0;i<n;i++){
			if(str=="FIFO"){
				cin>>str1;
				if(str=="IN"){
					cin>>temp; Q.push(temp);
				}
				if(str1=="OUT"){
					if(Q.empty()) cout<<"None"<<endl;
					else{
						cout<<Q.front()<<endl;
						Q.pop();
					}
				}
			}
			else{
				cin>>str1;
				if(str1=="IN"){
					cin>>temp; S.push(temp);
				}
				if(str1=="OUT"){
					if(S.empty()) cout<<"None"<<endl;
					else{
						cout<<S.top()<<endl;
						S.pop();
					}
				}
			}
		}
	}
	return 0;
}

  

優先隊列,顧名思義就是優先級最高的先出隊。

有關操作如下:

q.top();     //返回具有最高優先級的元素值,但不刪除該元素

q.pop();    //刪除最高優先級元素

q,push(item);    //插入新元素

可以用優先隊列對數據排序,設定數據小的優先級高,把所有數push進優先隊列後一個個top出來,就得到了從小到大的排序,其總複雜度時O(nlog以2爲底的n)

詳見:自己搜索吧,良莠不齊的

例子:hdu1873“看病要排隊”   https://vjudge.net/contest/337673#problem/E

題目大意:

解題思路:

代碼:

#include<iostream>
#include<stack>
#include<queue>
#include<string>
using namespace std;
int main(){
	int t,n,temp;
	cin>>t;
	while(t--){
		string str,str1;
		queue<int>Q;
		stack<int>S;
		cin>>n>>str;
		for(int i=0;i<n;i++){
			if(str=="FIFO"){
				cin>>str1;
				if(str=="IN"){
					cin>>temp; Q.push(temp);
				}
				if(str1=="OUT"){
					if(Q.empty()) cout<<"None"<<endl;
					else{
						cout<<Q.front()<<endl;
						Q.pop();
					}
				}
			}
			else{
				cin>>str1;
				if(str1=="IN"){
					cin>>temp; S.push(temp);
				}
				if(str1=="OUT"){
					if(S.empty()) cout<<"None"<<endl;
					else{
						cout<<S.top()<<endl;
						S.pop();
					}
				}
			}
		}
	}
	return 0;
}

  4.鏈表和list

STL的list是數據結構的雙向鏈表,它的內存空間可以是不連續的,通過指針來進行數據的訪問,它可以高效率的在任意地方刪除和插入,插入和刪除操作是常數時間的。

list和vector的優缺點正好相反,他們的應用場景不同:

(1)vector:插入和刪除操作少,隨機訪問元素頻繁。

(2)list:插入和刪除頻繁,隨機訪問較少。

詳見:https://oi-wiki.org/ds/linked-list/

list例子:hdu1276“士兵隊列訓練問題”  https://vjudge.net/contest/337673#problem/F

題目大意:輪流進行1-2,1-3報數,出列

解題思路:構建list,利用循環結構,取餘,求人

代碼:

#include <iostream>
#include <list>
using namespace std;
int main(){
	int t,n;
	cin>>t;
	while(t--){
		cin>>n;
		int k=2;
		list<int>mylist;
		list<int>::iterator it;
		for(int i=1;i<=n;i++)
		mylist.push_back(i);
		while(mylist.size()>3){
			int num=1;
			for(it=mylist.begin();it!=mylist.end();){
				if(num++%k==0)
				it=mylist.erase(it);
				else
				it++;
			}
			k==2?k=3:k=2;
		}
		for(it=mylist.begin();it!=mylist.end();it++){
			if(it!=mylist.begin())
			cout<<" ";
			cout<<*it;
		}
		cout<<endl;
	}
	return 0;
}

  5.set

set和map在競賽題中的應用很廣泛,特別是需要用二叉搜索樹處理數據的題目,如果用set和map實現,能極大地簡化代碼。

set的有關操作:

set<Type>A      //定義

 A.insert(item);   //把item放進set

A.erase(item);    //刪除元素item

A.clear();            //清空set

A.empty();          //判斷是否爲空

A.size();             //返回元素個數

A.find(k);             //返回一個迭代器,指向鍵值K

A.lower_bound(k);    //返回一個迭代器,指向鍵值不小於k的第一個元素

A.upper_bound();     //返回一個迭代器,指向鍵值大於k的第一個元素

詳見:https://oi-wiki.org/lang/csl/associative-container/

 例子:hdu2094“產生冠軍”  https://vjudge.net/contest/337673#problem/G

題目大意:判斷冠軍

題目思路:定義集合A和B,把所有人放進集合A,把所有有失敗記錄的放進集合B,如果A-B=1,則可以判斷存在冠軍,否則不能。

代碼:

#include<iostream>
#include<string>
#include<set>
using namespace std;
int main(){
	set<string>A,B;
	string s1,s2;
	int n;
	while(cin>>n&&n){  //若輸入爲0則退出,若不是0則循環
		for(int i=0;i<n;i++){
			cin>>s1>>s2;
			A.insert(s1); A.insert(s2);
			B.insert(s2);
		}
		if(A.size()-B.size()==1)
		cout<<"Yes"<<endl;
		else
		cout<<"No"<<endl;
		A.clear();  B.clear();
	}
	return 0;
}

  6.map

map是關聯容器,它實現從鍵(key)到值(value)的映射。map效率高的原因是他用平衡二叉搜索樹來存儲和訪問。

map在例子中具體操作如下:

(1)定義,map<string,int>student,存儲學生的name和id

(2)賦值:例如stduent["Tom"]=15。這裏把”Tom“當成普通數組的下標來使用。

(3)查找:在找學號時,可以直接使用student["Tom"]表示他的id,不再去搜索所有的姓名。

詳見:https://oi-wiki.org/lang/csl/associative-container/

例子:hdu2648"Shopping"   https://vjudge.net/contest/337673#problem/H

題目大意:得知商店排行

題目思路:如下

代碼:

#include<iostream>
#include<map>
#include<string>
using namespace std;
int main(){
	int n,m,p;
	map<string,int>shop;
	while(cin>>n){
		string s;
		for(int i=1;i<=n;i++) cin>>s;//輸入商店名字,實際上用不着處理
		cin>>m;
		while(m--){
			for(int i=1;i<=n;i++){
				cin>>p>>s;
				shop[s]+=p;//用map直接操作商店,加上價格 
			}
			int rank=1;
			map<string,int>::iterator it;//迭代器,,遍歷數據,判斷是否集合中有數據,
                                                                //有則取出,然後不斷執行
			for(it=shop.begin();it!=shop.end();it++)
			if(it->second>shop["memory"])
			rank++;
			cout<<rank<<endl; 
		} 
		shop.clear();
	}
	return 0;
}

  7.sort

注意:它排序的範圍是[first,last),包括first,不包括last

<1>sort()的比較函數  

sort()可以用自定義的比較函數進行排序,也可以用系統的種函數排序,即less(),greater(),less_equal(),greater_equal()。在默認情況下,程序是按從大到小的順序排序的,less()可以不寫。  例子詳見P34

sort()還可以對結構變量進行排序,例子詳見P35

<2>相關函數

stable_sort():當排序元素相等時,保留原來的順序。在對結構體排序時,當結構體中的排序元素相等時,如果需要保留原序,可以用它。

partial_sort():局部排序。例如有10個數字,求最小的5個數。如果用sort(),需要先全部排序,再輸出前5個;而用它可以直接輸出前5個。

8.next_permutation()

返回值:如果沒有下一個排列組合,返回false,否則返回true。每執行它一次,就會把新的排列放到原來的空間裏去。

它的排列範圍時[first,last),包括first,不包括last

例子:hdu1027”Ignatius and the Princess II“   https://vjudge.net/contest/337673#problem/I

題目大意:如題

題目思路:利用它生成一個一個小的序列,直到m小

代碼:

#include<iostream>
 #include<algorithm>
 using namespace std;
 int a[1001];
 int main(){
 	int n,m;
 	while(cin>>n>>m){
 		for(int i=1;i<=n;i++) a[i]=i;//生成一個字典序最小的序列
		 int b=1;
		 do{
		 	if(b==m) break;
		 	b++;
		 }while(next_permutation(a+1,a+n+1));
		 for(int i=1;i<n;i++)//注意第一個是a+1,最後一個是a+n 
		 cout<<a[i]<<" ";//輸出第m大的字典序 
		 cout<<a[n]<<endl;
	 }
	 return 0;
 }

  例子:hdu"排列2”    https://vjudge.net/contest/337673#problem/J

題目大意:如題

題目思路:

代碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int a[4],hash1[4],vis[4],hash2[10000];
int flag,temp,cnt;
void Show(){
    int num = hash1[0] * 1000 + hash1[1] * 100 + hash1[2] * 10 + hash1[3];
    if(hash2[num]) return;
    else{
        hash2[num] = 1;
        if(temp != hash1[0]){
            cnt = 0;
            temp = hash1[0];
            flag++;
            if(flag) printf("\n");
        }
 
        if(cnt != 0) printf(" ");
        for(int i = 0;i < 4;i++){
            printf("%d",hash1[i]);
        }
        cnt++;
    }
    return ;
}
void Dfs(int x){
    if(x == 4){
        Show();
        return ;
    }
    for(int i = 0;i < 4;i++){
        if(x == 0 && a[i] == 0)continue;
        if(!vis[i]){
            hash1[x] = a[i];
            vis[i] = 1;
            Dfs(x + 1);
            vis[i] = 0;
        }
    }
}
int main(){
    int k = 0;
    while(~scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3])){
        if(!a[0] && !a[1] && !a[2] && !a[3]) break;
        if(k)printf("\n");
        sort(a,a+4);
        memset(hash1,0,sizeof(hash1));
        memset(hash2,0,sizeof(hash2));
        memset(vis,0,sizeof(vis));
        temp = -1,flag = -1,cnt = 0;
        Dfs(0);
        printf("\n");
        k++;
    }
    return 0;
}

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章