算法基础模板(1)

       最近发现自己基础还是很渣,买了本算法图解让愚笨的自己能理解一些基础算法的原理。以下模板通过亲测,代码写得比较差,见谅。

一、递归

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;
}

上面都比较基础、下一节我会继续分享的。因为我代码敲得比较慢,请见谅!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值