最近发现自己基础还是很渣,买了本算法图解让愚笨的自己能理解一些基础算法的原理。以下模板通过亲测,代码写得比较差,见谅。
一、递归
1、DFS二维矩阵实现
#include <iostream>
#include <cstdio>
using namespace std;
typedef struct Vnode{
int v;
bool visited;
}vnode;
bool visited[5]={false};
int FirstAd(int v){ //v为开始搜索的点
int node[5][5]{
{0,1,0,0,0},
{1,0,1,0,0},
{0,1,0,1,1},
{0,0,1,0,0},
{0,0,1,0,0}
};
for(int i=0;i<5;i++){
if(node[v][i]==1 && visited[i]==false){
return i;
break;
}
}
return -1;
}
void Dfs(int vn){
visited[vn]=true;
printf("%d\n",vn);
int p = FirstAd(vn);
while(p!=-1){
if(visited[p]==false){ //基线条件
Dfs(p);
}
else{ //递归条件
p = FirstAd(vn);
}
}
}
2、排列与组合
#include<bits/stdc++.h>
using namespace std;
int visited[100]={0};
int num[100];
int ni[100];
int r = 0;
bool fcheck(int a[],int j){
for(int p=1;p<j;p++){
if(a[p]==a[j] && (!visited[p])){
return false;
}
}
return true;
}
void Permutation(int n,int k,int a[],int d){
if(d>k){
for(int j=1;j<=k;j++){
printf("%d ",num[j]);
}
printf("\n");
r++;
}
else{
for(int i=1;i<=n;i++){
//if(visited[i]==0 && i>ni[d-1]){ //无重复组合
//if(visited[i]==0 ){ //无重复排列
//if(visited[i]==0 && fcheck(a,i)){ //有重复的排列
if(visited[i]==0 && i>ni[d-1] && fcheck(a,i)){ //有重复组合
num[d]=a[i];
ni[d]=i;
visited[i]=1;
Permutation(n,k,a,d+1);
visited[i]=0;
}
}
}
}
int main(){
int n,k;
int a[100];
ni[0] = 0;
while(cin>>n>>k){
r = 0;
for(int i=1;i<=n;i++){
cin>>a[i];
}
a[n+1]=-1;
cout<<"This:"<<endl;
Permutation(n,k,a,1);
cout<<"总数:"<<r<<endl;
}
return 0;
}
二、分治
1、二分查找(迭代实现)
#include<bits/stdc++.h>
using namespace std;
int Binary_search(int a[],int l,int r,int k){
int mid;
while(l<r){
mid = (l+r)/2;
if(a[mid]==k)return mid; //类似于递归的基线条件
else if(a[mid]<k)l = mid+1;
else r = mid-1;
}
return -1;
}
int main()
{
int b[10]={1,3,4,6,7,9,10,23,195,1008};
int r = Binary_search(b,0,9,9);
cout<<r<<endl;
return 0;
}
2、二分查找(递归)
#include<bits/stdc++.h>
using namespace std;
int Binary_search(int a[],int l,int r,int k){
int mid;
if(l<r){ //注意是l<r哦
mid = (l+r)/2;
if(a[mid]==k)return mid; //基线条件
else if(a[mid]<k)return Binary_search(a,mid+1,r,k); //递归条件
else return Binary_search(a,l,mid-1,k); //递归条件
}
else{
return -1; //基线条件
}
}
int main()
{
int b[10]={1,3,4,6,7,9,10,23,195,1008};
int r = Binary_search(b,0,9,9);
cout<<r<<endl;
return 0;
}
3、土地分为方块问题(欧几里得算法好像好高级哦)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000;
int split(int l,int w){
if(l==w || l%w==0){ //基线条件
return w;
}
else{ //递归条件
return split(w,l%w);
}
}
int main()
{
int l,w;
printf("请输入长与宽:\n");
scanf("%d %d",&l,&w);
int ans = split(l,w);
printf("%d\n",ans);
return 0;
}
4、快速排序
4.1 Python的实现比较容易理解哦,看完书我也就只想到这种
def quicksort(array):
if len(array) < 2: #基线条件
return array
else: #递归条件
p = array[0] #基准值
l = [i for i in array[1:] if i<=p]
r = [i for i in array[1:] if i>p]
return quicksort(l)+[p]+quicksort(r)
a = []
n = int(input())
for i in range(n):
a.append(int(input()))
print(quicksort(a))
4.2 C++实现,数据结构课学过但忘了
#include <bits/stdc++.h>
using namespace std;
void QuickSort1(int a[],int l,int r){
int i=l,j=r;
int t = a[l]; //基准值
while(i<j){
while(i<j && a[j]>=t)j--;
if(i<j){
a[i] = a[j];
i++;
}
while(i<j && a[i]<t)i++;
if(i<j){
a[j] = a[i];
j--;
}
}
a[i] = t;
if(l<i)QuickSort1(a,l,i-1); //递归条件
if(i<r)QuickSort1(a,j+1,r);
//基线条件 i到达最左端,j到达最右端
}
int main()
{
int d[20];
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>d[i];
}
QuickSort1(d,0,n-1);
for(int j=0;j<n;j++){
printf("%d ",d[j]);
}
return 0;
}
4.3既然都做了,写个类方便调用吧
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QSort
{
class MQSort
{
public static void QuickSort(List<int>a,int l,int r)
{
int i = l, j = r;
int t = a[l];
while (i < j)
{
while (i < j && a[j] >= t) j--;
if (i < j)
{
a[i] = a[j];
i++;
}
while (i < j && a[i] < t) i++;
if (i < j)
{
a[j] = a[i];
j--;
}
}
a[i] = t;
if (l < i) QuickSort(a, l, i - 1);
if (i < r) QuickSort(a, j + 1, r);
}
}
}
三、图论
1、BFS二维数组实现
#include <iostream>
#include <cstdio>
using namespace std;
typedef struct Vnode{
int v;
bool visited;
}vnode;
bool visited[5]={false};
int FirstAd(int v){
int node[5][5]{
{0,1,0,0,0},
{1,0,1,0,0},
{0,1,0,1,1},
{0,0,1,0,0},
{0,0,1,0,0}
};
for(int i=0;i<5;i++){
if(node[v][i]==1 && visited[i]==false){
return i;
break;
}
}
return -1;
}
void Bfs(int vn,int n){
int c=0;
int i=0;
int flag = 0;
visited[vn]=true;
int visit[5];
printf("%d\n",vn);
visit[c]=vn;
c++;
int p;
while(c<n){
if(flag==0){
p = FirstAd(vn);
}
if(p!=-1 && visited[p]==false){
visited[p]=true;
printf("%d\n",p);
visit[c]=p;
c++;
flag = 0;
}
else if(p==-1){
p = FirstAd(visit[i]);
if(p==-1)
i++;
flag=1;
}
}
}
int main()
{
int i=0;
while(i<5){
visited[i]=false;
i++;
}
printf("\n");
Bfs(2,5);
return 0;
}
2、BFS邻接矩阵实现
#include <bits/stdc++.h>
using namespace std;
const int MAXVEX = 1000;
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef char VertexType; /* 顶点类型应由用户定义 */
typedef int EdgeType; /* 边上的权值类型应由用户定义 */
bool visited[MAXVEX] = {false}; /*记录是否被访问过;*/
typedef struct EdgeNode /* 边表结点 */
{
int adjvex; /* 邻接点域,存储该顶点对应的下标 */
EdgeType info; /* 用于存储权值,对于非网图可以不需要 */
struct EdgeNode *next; /* 链域,指向下一个邻接点 */
}EdgeNode;
typedef struct VertexNode /* 顶点表结点 */
{
VertexType data; /* 顶点域,存储顶点信息 */
EdgeNode *firstedge;/* 边表头指针 */
}VertexNode, AdjList[MAXVEX];
typedef struct
{
AdjList adjList;
int numNodes,numEdges; /* 图中当前顶点数和边数 */
}GraphAdjList;
/* 建立图的邻接表结构 */
void CreateALGraph(GraphAdjList *G)
{
int i,j,k;
EdgeNode *e;
printf("输入顶点数和边数:\n");
scanf("%d %d",&G->numNodes,&G->numEdges); /* 输入顶点数和边数 */
for(i = 0;i < G->numNodes;i++) /* 读入顶点信息,建立顶点表 */
{
printf("请输入顶点信息\n");
scanf("%s",&G->adjList[i].data); /* 输入顶点信息 */
G->adjList[i].firstedge=NULL; /* 将边表置为空表 */
}
for(k = 0;k < G->numEdges;k++)/* 建立边表 */
{
printf("输入边(vi,vj)上的顶点序号:\n");
scanf("%d %d",&i,&j); /* 输入边(vi,vj)上的顶点序号 */
e=(EdgeNode *)malloc(sizeof(EdgeNode)); /* 向内存申请空间,生成边表结点 */
e->adjvex=j; /* 邻接序号为j */
e->next=G->adjList[i].firstedge; /* 将e的指针指向当前顶点上指向的结点 */
G->adjList[i].firstedge=e; /* 将当前顶点的指针指向e */
//无向图
//e=(EdgeNode *)malloc(sizeof(EdgeNode)); /* 向内存申请空间,生成边表结点 */
//e->adjvex=i; /* 邻接序号为i */
//e->next=G->adjList[j].firstedge; /* 将e的指针指向当前顶点上指向的结点 */
//G->adjList[j].firstedge=e; /* 将当前顶点的指针指向e */
}
}
void BFS(GraphAdjList *G,int Ni){ //输入需要开始遍历的顶点下标;
int ti = Ni;
EdgeNode *p;
printf("图的广度优先遍历:\n");
queue<char>bfsque;
queue<int>numque;
printf("%c",G->adjList[ti].data);
numque.push(ti);
while(!numque.empty()){
for(p=G->adjList[numque.front()].firstedge;p!=NULL;p=p->next){
if(!visited[p->adjvex]){
bfsque.push(G->adjList[p->adjvex].data);
numque.push(p->adjvex);
visited[p->adjvex] = true;
}
}
numque.pop();
}
while(!bfsque.empty()){
printf(" %c",bfsque.front());
bfsque.pop();
}
printf("\n");
}
void DispGraphAdjList(GraphAdjList *G)
{
int i;
EdgeNode *p;
printf("图的邻接表表示如下\n");
printf("%6s%8s%12s\n","编号","顶点","相邻边编号");
for(i=0;i< G->numNodes;i++)
{
printf("%4d %8c",i,G->adjList[i].data);//
for(p=G->adjList[i].firstedge;p!=NULL;p=p->next)
printf("%4d",p->adjvex);
printf("\n");
}
}
int main()
{
GraphAdjList G;
CreateALGraph(&G);
//DispGraphAdjList(&G);
int n;
printf("请输入需要开始的头序号:\n");
scanf("%d",&n);
BFS(&G,n);
return 0;
}
3、Dijkstra最短路径(只适用于有向无环图哦)
#include <bits/stdc++.h>
using namespace std;
const int MAXVES = 1000;
const int INF = 1e9;
typedef char VertexType;
typedef int EdgeType; /*权值*/
bool visited[MAXVES]={false};
int cost[MAXVES]; /*记录从起点开始到某点的短距离*/
int parent[MAXVES]; /*记录每个节点的父节点*/
queue<int>que; /*记录要遍历的顶点序号*/
typedef struct EdgeNode{
int adjvex;
EdgeType info;
struct EdgeNode *next;
}EdgeNode;
typedef struct VertexNode{
VertexType data;
EdgeNode *firstnode;
}VertexNode,AdjList[MAXVES];
typedef struct{
AdjList adjlist;
int numNode,numEdge;
}GraphAdjList;
void CreatGraph(GraphAdjList *G){
int i,j,k,w; /*加入w为权值*/
EdgeNode *e;
printf("输入顶点数和边数:\n");
scanf("%d %d",&G->numNode,&G->numEdge);
for(i=0;i<G->numNode;i++){ //G->numNode与 *G.numNode等价
printf("输入顶点的信息\n");
scanf("%s",&G->adjlist[i].data);
G->adjlist[i].firstnode = NULL;
}
for(k=0;k<G->numEdge;k++){
printf("输入边上的顶点序号以及边的权值:\n");
scanf("%d %d %d",&i,&j,&w);
e = (EdgeNode*)malloc(sizeof(EdgeNode)); /*建立的是有向图*/
e->adjvex = j;
e->info = w; /*权值*/
e->next = G->adjlist[i].firstnode;
G->adjlist[i].firstnode = e;
}
}
int Dijkstra(GraphAdjList *g,int s,int f){
for(int k = 0;k<MAXVES;k++){
cost[k]=INF; /*先把所有赋值为无穷远*/
}
int ans = 0;
int i,spend,j;
EdgeNode *p;
que.push(s);
cost[s]=0;
while(!que.empty()){
i = que.front();
if(!visited[i]){ /*顶点是否被寻找过?*/
for(p=g->adjlist[i].firstnode;p!=NULL;p=p->next){
que.push(p->adjvex);
spend = cost[i]+p->info;
if(spend<cost[p->adjvex]){ /*和原来的距离相比如果更短,更新列表*/
cost[p->adjvex]=spend;
parent[p->adjvex]=i; /*父节点也要更新*/
}
}
visited[i]=true;
}
que.pop();
}
j = f;
stack <char>sque;
sque.push(g->adjlist[f].data);
while(parent[j]!=s){
sque.push(g->adjlist[parent[j]].data);
j = parent[j];
}
sque.push(g->adjlist[s].data);
printf("%c",sque.top());
sque.pop();
while(!sque.empty()){
printf(" %c",sque.top());
sque.pop();
}
printf("\n");
ans = cost[f];
return ans;
}
int main()
{
int s,f,r;
GraphAdjList g;
CreatGraph(&g);
printf("请输入开始序号和结束序号:\n");
scanf("%d %d",&s,&f);
r = Dijkstra(&g,s,f);
printf("%d\n",r);
return 0;
}
四、动态规划初步
1、0-1背包
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
int dp[maxn][maxn];
int v[maxn],w[maxn]; //v为价值、w为重量;
int main()
{
int n,tw; //共n件商品,tw表示背包总重量;
scanf("%d %d",&n,&tw);
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
dp[i][j]=0; //手动初始化;
}
}
for(int i=1;i<=n;i++){
scanf("%d %d",&v[i],&w[i]); //输入每件商品的价值与重量;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=tw;j++){
if(j>=w[i]){
if((dp[i-1][j-w[i]]+v[i])>dp[i-1][j]){ //主要判断条件通过网格得出
dp[i][j] = dp[i-1][j-w[i]]+v[i];
}
else{
dp[i][j]=dp[i-1][j];
}
}
else{
dp[i][j] = dp[i-1][j];
}
}
}
cout << dp[n][tw] << endl;
return 0;
}
2、LCS(包括子串和序列)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100;
char s1[maxn],s2[maxn];
int dp[maxn][maxn];
int main()
{
int i=0,j=0;
int maxsub = 0;
cin>>s1>>s2;
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
dp[i][j]=0; //手动初始化;
}
}
while(s1[i]!='\0'){
j=0;
while(s2[j]!='\0'){
if(s1[i]==s2[j]){
dp[i+1][j+1] = dp[i][j]+1;
}
else{
//dp[i+1][j+1]=0; //最长公共字串
dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]); //最长公共子序列
}
j++;
}
i++;
}
int rear;
for(int k=1;k<=i;k++){
for(int l=1;l<=j;l++){
if(maxsub<dp[k][l]){
maxsub = dp[k][l];
rear = k;
}
}
}
for(int p = rear-maxsub;p<rear;p++){
printf("%c",s1[p]);
}
printf("\n");
cout << maxsub << endl;
return 0;
}
五、其他
1、逆波兰表达式
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
char str[100];
int OptoInt(char a){ //记录每个操作的优先级
switch(a){
case '+':return 1;
break;
case '-':return 1;
break;
case '*':return 2;
break;
case '/':return 2;
break;
case '=':return 0;
break;
case '(':return 0;
}
}
int Clc(int a,int b,char op){ //每个运算符的操作
switch(op){
case '+':return a+b;
break;
case '-':return a-b;
break;
case '*':return a*b;
break;
case '/':return a/b;
break;
}
}
int main()
{
cin>>str;
int i=0;
int num = 0;
int d,e;
stack <char>sop; //操作符栈
stack <int>sv; //数据栈
char op;
int flag = 0;
while(str[i]!='\0'){ //对输入的处理
if(str[i]>='0'&&str[i]<='9'){ //输入数字的转换
num *= 10;
num += str[i]-'0';
flag = 1;
}
else{
if(flag==1){
sv.push(num); //数字压栈
num = 0;
}
if(str[i]=='(') sop.push(str[i]); //遇到左括号,左括号优先级最高
else if(str[i]==')'){ //右括号将里面操作符全出栈
while(sop.top()!='('){
op = sop.top();
sop.pop();
e = sv.top();
sv.pop();
d = sv.top();
sv.pop();
sv.push(Clc(d,e,op)); //将括号内计算结果压栈
}
sop.pop();
}
else{
if(sop.empty()){
sop.push(str[i]); //操作符栈为空即可得到结果
}
else{
while(OptoInt(sop.top())>=OptoInt(str[i])){ //当栈顶操作符优先级高时,出栈并运算
op = sop.top();
sop.pop();
e = sv.top();
sv.pop();
d = sv.top();
sv.pop();
sv.push(Clc(d,e,op));
if(sop.empty()){
break;
}
}
sop.push(str[i]); //否则进栈
}
}
flag=0;
}
i++;
}
cout << sv.top() << endl;
return 0;
}
上面都比较基础、下一节我会继续分享的。因为我代码敲得比较慢,请见谅!