algorithm
Sorting algorithm
There are basically eight sorting algorithms
- Bubble sorting
- Insert sort
- Heap sort
- Select sort
- Quick sort
- Merge sort
- Cardinality sort
- Shell Sort
Of course, it is not required to fully master all sorting methods. Nevertheless, it is necessary to understand the implementation principle. This provides ideas for us to encounter similar problems
When you encounter sorting problems, you can use sort () and stable in the header file algorthm_ sort() function to sort
The implementation of sort() uses quick sorting, which is not stable. Stable can be used when stable sorting is required_ sort(), which is merge sort.
The complexity of both sorts is O(nlogn), but generally fast sort is faster than merge sort, so sort() is used without stable sort
sort() usage
Two parameters sort (start address, end address + 1);
The default is ascending sort.
Code example:
#include<iostream> #include<algorithm> using namespace std; int main(){ int a[10]={2,5,1,7,3,9,0,4,8,6}; sort(a,a+10); for(int i = 0; i < 10; i++){ cout<<a[i]<<' '; } } /* Output: 0 1 2 3 4 5 6 7 8 9 */
Three parameters sort (start address, end address + 1, sorting function address);
Example code:
#include<iostream> #include<algorithm> bool cmp(int v1,int v2){ return v1>v2; } using namespace std; int main(){ int a[10]={2,5,1,7,3,9,0,4,8,6}; sort(a,a+10,cmp); for(int i = 0; i < 10; i++){ cout<<a[i]<<' '; } } /* Output: 9 8 7 6 5 4 3 2 1 0 */
Joint search set
Joint search is an uncommon algorithm, but it must be learned because it plays a great role.
effect:
It is to divide into sets to see whether two objects belong to the same set.
Principle:
- Implement with an array f[i], and initialize the array f[i] = i
- Build a relationship
- A find() function is required to find
Example code:
#include<iostream> using namespace std; //Join set array int f[10]; //Find function int find(int value){ if(value!=f[value])return f[value]=find(f[value]); return value; } int main(){ //Initialize f[i] array for(int i = 0; i < 10; i++){ f[i]=i; } //Let's build the set {0}, {1,2,3,4}, {5}, {6,7,8,9} f[find(1)]=find(2); f[find(1)]=find(3); f[find(1)]=find(4); f[find(6)]=find(7); f[find(6)]=find(8); f[find(6)]=find(9); //Print understanding for(int i = 0; i < 10; i++){ cout<<i<<" Belong to collection "<<find(i)<<endl; } } /* Output: 0 Belongs to collection 0 1 Belongs to set 4 2 Belongs to set 4 3 Belongs to set 4 4 Belongs to set 4 5 Belong to set 5 6 Belongs to set 9 7 Belongs to set 9 8 Belongs to set 9 9 Belongs to set 9 */
search
Binary search
Binary search is very suitable for linear search, that is, the problem has certain increment or decrement. For example, finding a number in 0-1000000000 will cause huge time overhead if it is checked one by one in the ordinary order. The time complexity of binary search is O(logn), which greatly reduces the time overhead
Principle:
- Take three values, left = minimum range - 1, right = maximum range + 1,middle = (left + right)/2;
- If the middle value is larger than the ideal value, make right = middle + 1, and left = middle - 1;
- Repeat step 2 until middle = = ideal value;
(Note: the above is the usage of searching integer)
Example:
Search 1 number from 0x80000000+1 to 0x7fffff-1
Example code:
#include<iostream> using namespace std; int main(){ cout<<"Please enter a "<<(int)0x80000000+1<<" reach "<<0x7fffffff-1<<" Number of"<<endl; int value; cin>>value; int l= (int)0x80000000; int r= (int)0x7fffffff; int ans=0; while(1){ ans++; int m=(l+r)/2; if(m==value){ cout<<m<<endl<<"Search times: "<<ans; break; } if(m>value){ r=m+1; }else{ l=m-1; } } } /* Output: Please enter a number from - 2147483648 to 2147483646 5 5 Number of searches: 32 */
Three point search
The trisection search is suitable for the minimization of parabola like curves
Principle:
- Take four values, left = minimum range, right = maximum range, middle1 = left + (left - right)/3, middle2 = right - (left + right)/3
- On the premise, you need to know whether the parabola like opening is up or down. If the opening is up, that is, find the minimum value. If middle1 > middle2, make left=middle1, and conversely, right=middle2
- Repeat step 2 until right - left = = certain accuracy
Depth first search
It is often called dfs(Depth first search), which searches for all possible solutions to a problem
Principle:
- Implement the recursive function dfs(), and take the parameters according to the actual situation
Example:
On the map .s.#. ..#.. .#... .#... ...e. in s It's the entrance,e It's an exit,#It's an obstacle. Only one step at a time (up, down, left and right) Find the shortest number of steps
Example code:
#include<iostream> using namespace std; //Minimum steps int minStep=0x7fffffff; //Map char map[5][5]={'.','s','.','#','.','.','.','#','.','.','.','#','.','.','.','.','#','.','.','.','.','.','.','e','.'}; //Tag array for backtracking int sign[5][5]={0}; //dfs function void dfs(int step,int x,int y){ if(map[y][x]=='e'){ minStep=min(minStep,step); } //Up, down, left and right int m[4][2]{0,1,0,-1,-1,0,1,0}; for(int i = 0; i < 4; i++){ int x1=x+m[i][0]; int y1=y+m[i][1]; if(x1>=0&&x1<5&&y1>=0&&y1<5&&map[x1][y1]!='#'&&sign[y1][x1]==0){ sign[y1][x1]=1; dfs(step+1,x+m[i][0],y+m[i][1]); //to flash back sign[y1][x1]=0; } } } int main(){ int x,y; //Find the starting point for(int i = 0; i < 5; i++){ for(int j = 0; j < 5; j++){ if(map[i][j]=='s'){ x=j; y=i; } } } //dfs dfs(0,x,y); cout<<minStep<<endl; } /* Output: 8 */
Width first search
Often called bfs(Width first search), it is generally used for the shortest path problem
principle
- Implementation with data structure queue
- Search step by step and find the shortest path
Examples
Same question as above
Example code:
#include<iostream> #include<queue> using namespace std; class node{ public: int x,y,step; }; int main(){ //Map char map[5][5]={'.','s','.','#','.','.','.','#','.','.','.','#','.','.','.','.','#','.','.','.','.','.','.','e','.'}; //Tag array int sign[5][5]={0}; queue<node> q; node p; //Find the starting point for(int i = 0; i < 5; i++){ for(int j = 0; j < 5; j++){ if(map[i][j]=='s'){ p.x=j; p.y=i; p.step=0; } } } q.push(p); sign[p.y][p.x]=1; //bfs while(!q.empty()){ //Up, down, left and right int m[4][2]{0,1,0,-1,-1,0,1,0}; node d=q.front(); q.pop(); if(map[d.y][d.x]=='e'){ cout<<d.step<<endl; break; } for(int i = 0; i < 4; i++){ int x1=d.x+m[i][0]; int y1=d.y+m[i][1]; if(x1>=0&&x1<5&&y1>=0&&y1<5&&map[x1][y1]!='#'&&sign[y1][x1]==0){ sign[y1][x1]=1; node e; e.x=x1; e.y=y1; e.step=d.step+1; q.push(e); } } } } /* Output: 8 */
dynamic programming
Dynamic programming, referred to as dp, reduces the calculation of repeated steps and greatly reduces the time complexity by maintaining a memorized dp array
Typical example:
Find the length of the longest increasing substring, such as f[8]={1, 4, 2, 3, 5, 8, 6, 7}. The answer is 6, {1, 2, 3, 5, 6, 7}
understand:
- Use dp[n] to store the maximum continuous substring length between 0 and n
- If dp[0]=1, because f [1] > F [0], dp[1]=max(dp[1],dp[0]+1)
- Continue with step 2 until you traverse the array
Example code:
#include<iostream> #include<string> using namespace std; int main(){ int f[8]={1,4,2,3,5,8,6,7}; int dp[8]; string s[8]; //Initialize dp[],s [] for(int i=0;i<8;i++){ dp[i]=1; s[i]+=to_string(f[i]); } //dp for(int i=0;i<8;i++){ for(int j=0;j<i;j++){ if(f[i]>f[j]){ if(dp[i]<dp[j]+1){ dp[i]=dp[j]+1; s[i]=s[j]+to_string(f[i]); } } } } int ma=0; for(int i=1;i<8;i++){ if(dp[ma]<dp[i]){ ma=i; } } cout<<dp[ma]<<endl; cout<<"{"; for(int i=0;i<s[ma].size();i++){ if(i!=0){ cout<<','; } cout<<s[ma][i]; } cout<<'}'; } /* Output: 6 {1,2,3,5,6,7} */