常用算法代码模板总结

以下内容只提供对应算法方便好用的模板,或者把某项功能做成函数直接传参调用。不提供详细的算法证明。大部分算法使用java语言编写,可自行转换成其他语言。篇幅过长的内容单独用一篇博客总结,博客内给出了对应的练习题目。持续更新中......

目录

快速排序

归并排序

堆排序

前缀和与差分(一维、二维)

并查集

整数二分、浮点二分

去除数组中重复的元素(双指针)

求最大公约数

求最小公倍数

求素数(欧拉筛)

高精度加法(C++)

高精度减法(C++)

高精度乘法(C++)

高精度除法(C++)

动态规划背包问题

模式匹配算法之KMP算法

最小生成树之prim算法(无向图)

最小生成树之Kruskal算法(无向图)

单源最短路之Dijkstra算法(无向图)

单源最短路之Bellman-ford算法(有向图)

多源最短路之floyd算法(有向图)

warshall算法判断图是否连通(邻接矩阵存放图)


快速排序

快速排序java代码模板

归并排序

归并排序java代码模板

堆排序

堆排序及模拟堆java代码模板

前缀和与差分(一维、二维)

前缀和与差分代码模板

并查集

并查集java代码模板

整数二分、浮点二分

整数二分、浮点二分代码模板

去除数组中重复的元素(双指针)

public static void main(String args[]) {
		int[] nums = { 1, 1, 2, 2, 2, 3, 4, 4, 5, 6, 7 };
		int j = 0;

		for (int i = 0; i < nums.length; i++) {//去除数组当中重复的元素
			if (i == 0 || nums[i] != nums[i - 1])
				nums[j++] = nums[i];
		}

		for (int i = 0; i < j; i++)
			System.out.print(nums[i] + " ");//输出:1 2 3 4 5 6 7 
	}

求最大公约数

朴素求法

public static int gcd(int a, int b) {// 最大公约数朴素写法,传入两个数,返回最大公约数。
		while (b != 0) {
			int temp = a % b;
			a = b;
			b = temp;
		}
		if (a < 0)
			return -a;
		return a;
}

 递归写法

public static int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

求最小公倍数

public static int gbs(int n, int m) {//传入两个数,得到两个数的最小公倍数

    int temp = Math.max(n, m);//求得这两个数的较大值
    for (int i = temp; ; i++) {//从较大值开始遍历
        if (i % n == 0 && i % m == 0)
            return i;
    }

}

求素数(欧拉筛)

public static int[] Prime(int n) {// 欧拉筛求素数,传入参数n表示范围的最大值
		int[] prime = new int[100010];// 能够存放的素数个数
		boolean[] bool = new boolean[100010];
		int count = 0;// 记录素数个数
		for (int i = 2; i <= n; i++) {
			if (bool[i] == false) {
				prime[count++] = i;
				bool[i] = true;
			}
			for (int j = 0; j < count; j++) {
				if (i * prime[j] > n)
					break;
				bool[i * prime[j]] = true;
				if (i % prime[j] == 0)
					break;
			}
		}
		System.out.printf("0~%d范围内的素数个数为:%d\n", n, count);// 输出个数
		return prime;
	}

高精度加法(C++)

java和python用不上高精度。java用BigInteger,python更方便。

vector<int> add(string a, string b){//传入两个数的字符串形式,返回之和。 
	 	
		if (a.length() < b.length()) return add(b, a);

        int t = 0;
		vector<int> A, B, c;
	    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
	    for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');

	    
	    for (int i = 0; i < A.size(); i ++ ){
	        t += A[i];
	        if (i < B.size()) t += B[i];
	        C.push_back(t % 10);
	        t /= 10;
	    }

	    if (t) C.push_back(t);
	    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
	    return C;
	}

高精度减法(C++)

高精度减法存在正负号的判断,稍微复杂一点。

bool cmp(vector<int> &A, vector<int> &B)//正负号判断
{
    if (A.size() != B.size()) return A.size() > B.size();

    for (int i = A.size() - 1; i >= 0; i -- )
        if (A[i] != B[i])
            return A[i] > B[i];

    return true;
}

vector<int> sub(vector<int> &A, vector<int> &B)//传入数字,返回差。
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

int main()
{
    string a, b;
    vector<int> A, B;
    cin >> a >> b;//输入两个字符串形式的数组,返回其差
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');

    vector<int> C;

    if (cmp(A, B)) C = sub(A, B);//根据正负号的不同选择不同的相减方式
    else C = sub(B, A), cout << '-';

    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
    cout << endl;

    return 0;
}

高精度乘法(C++)

高精度乘法的两个数一般只有1个数非常大。

vector<int> mul(string a, long b){//传入一个数的字符串形式和另一个数,返回其乘积。 
	
	vector<int> A, c;
    int t = 0;
    
    for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
	
    for (int i = 0; i < A.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();
	//for (int i = C.size() - 1; i >= 0; i -- ) printf("%d", C[i]);
    return C;
}

高精度除法(C++)

vector<int> div(string a, int b, int &r)//传入 
{
	vector<int> A, c;
	r = 0;//记录余数 
	
	for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
    
    for (int i = A.size() - 1; i >= 0; i -- )
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    printf("\n余数为:%d\n",r); 
    return C;
}

动态规划背包问题

动态规划背包问题总结

模式匹配算法之KMP算法

图解KMP算法原理及其代码分析

最小生成树之prim算法(无向图)

最小生成树之prim算法java代码模板

public static int prim(int n, int[][] map) {//从下标1开始记录图的数据,n个节点,返回最小生成树的边权之和

		int[] dist = new int[n + 10];// 含义:这个点到最小生成树那个集合的最短距离,点到集合的距离
		boolean[] st = new boolean[n + 10];// st数组表示这个点有没有被加入最小生成树集合,如果被加入了,st[i]=true
		Arrays.fill(dist, INF);// 初始化距离

		int result = 0;// 记录最小生成树所有边权之和

		for (int i = 0; i < n; i++) {
			int t = -1;// 第一个点时情况特别判断
			for (int j = 1; j <= n; j++) {// 找到集合外距离集合最近的点
				if (st[j] == false && (t == -1 || dist[t] > dist[j]))
					t = j;
			}
			if (i != 0 && dist[t] == INF)// 如果最小的节点长度都为INF,那么不用找了,不存在最小生成树
				return INF;
			if (i != 0)// 如果这个点不是第一个点,将这个点距离加入
				result += dist[t];

			st[t] = true;// 将t这个点加入集合当中
			for (int j = 1; j <= n; j++)// 用这个点来更新其他点到这个集合的最短距离
				dist[j] = Math.min(dist[j], map[t][j]);// 这个时候t这个点已经被加入集合当中了,所以其他点到集合的距离可以用t来更新,因为t也在集合当中。

		}
		return result;
	}

最小生成树之Kruskal算法(无向图)

最小生成树之Kruskal算法java代码模板

static int[] p;

	public static int Find(int x) {// 并查集路径压缩优化
		if (p[x] != x)
			p[x] = Find(p[x]);
		return p[x];
	}
// kruskal算法略显繁琐,需要用到并查集
	public static int kruskal(int n, int[][] way) {// n个点,way记录的是边的信息
		
		p=new int[n+10];
		
		Arrays.sort(way, new Comparator<int[]>() {// 重写比较器,以边的权值作为比较依据
			public int compare(int[] o1, int[] o2) {
				return o1[2] - o2[2];
			}
		});

		for (int i = 1; i <= n; i++)// 并查集初始化每一个点,都是以自己为根节点的集合
			p[i] = i;

		int result = 0, count = 0;
		for (int i = 0; i < way.length; i++) {
			int a = way[i][0];
			int b = way[i][1];
			int c = way[i][2];
			a = Find(a);// 查询a的根节点
			b = Find(b);// 查询b的根节点
			if (a != b) {// 如果a和b不在一个集合里面
				p[a] = b;// 将a的根节点的父节点指向b
				result += c;// 加上这条边的距离
				count++;// 合并的点数加1
			}
		}

		if (count < n - 1)// 如果连通的点少于了点的总个数,说明不能构成最小生成树
			return Integer.MIN_VALUE;
		return result;

	}

单源最短路之Dijkstra算法(无向图)

单源最短路之Dijkstra算法java代码模板

public static int[] Dijkstra(int[][] map) {// 传入一个临界矩阵存放的图,从下标0开始为第一个点,返回所有点到第一个节点的最短距离数组。
		// 注意邻接矩阵存放的图初始化的数值是由你自己确认的!
		int n = map.length;
		int[] dist = new int[n];// 存放点到初始点的距离
		boolean[] st = new boolean[n];// 存放是否确定到初始点的距离最短
		Arrays.fill(dist, Integer.MAX_VALUE);// 初始化存放的所有节点到第一个节点的距离为无穷大

		dist[0] = 0;// 初始点到自己的距离为0

		for (int i = 0; i < n - 1; i++) {
			int temp = -1;
			for (int j = 0; j < n; j++) {// 如果矩阵从1开始存放节点信息,修改为for (int j = 1; j <= n; j++)

				if (st[j] == false && (temp == -1 || dist[temp] > dist[j]))// 第一次替换找到没有标记确定的第一个点,之后循环找距离初始点最近的没有标记确定的点
					temp = j;
			}

			// 如果矩阵从1开始存放节点信息,修改为for (int j = 1; j <= n; j++)
			for (int j = 0; j < n; j++) {// 通过上一步找到的点来更新这个点能够到达的其他点的距离
				// map[temp][j]表示temp到j这个点的距离,再加上dist[temp]就表示初始点以temp为中间点到j的距离
				dist[j] = Math.min(dist[j], dist[temp] + map[temp][j]);
			}
			st[temp] = true;// 更新完成之后,将该点标记为确定
		}
		return dist;// 返回结果
	}

单源最短路之Bellman-ford算法(有向图)

单源最短路之Bellman-ford算法java代码模板

public static int[] Bellman_Ford(int n, int[][] way) {// n个点,way表示边的信息,way[i][j]=a表示从i到j距离为a,节点的下标从1开始记录,返回从第一个点到所有点最近的距离

		int[] dist = new int[510];// 存放到某点的距离
		int[] temp = new int[3];// 存放单条边
		Arrays.fill(dist, Integer.MAX_VALUE / 20);// 初始化
		dist[1] = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				temp = way[j];
				dist[temp[1]] = Math.min(dist[temp[1]], dist[temp[0]] + temp[2]);
			}
		}
		return dist;
	}

多源最短路之floyd算法(有向图)

多源最短路之floyd算法java代码模板

public static int[][] floyd(int n, int[][] map) {// 三重循环,n个点传入邻接矩阵存放的图map,返回多个点之间的最短路径数组
		// 刚开始传入的是邻接矩阵图,返回的是距离map[i][j]=a表示从i到j最短距离为a
		// 刚开始邻接矩阵的初始化自行处理。
		for (int k = 1; k <= n; k++) {
			for (int i = 1; i <= n; i++) {
				for (int j = 1; j <= n; j++)
					map[i][j] = Math.min(map[i][j], map[i][k] + map[k][j]);
			}
		}
		return map;
	}

warshall算法判断图是否连通(邻接矩阵存放图)

public static boolean Warshall(int[][] tmp, int n) {// 传入这个图的邻接矩阵和节点个数。判断图是否连通,连通返回true

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (tmp[i][j] == 1) {
					for (int k = 0; k < n; k++) {
						if (tmp[k][i] == 1)
							tmp[k][j] = tmp[j][k] = 1;
					}
				}
			}
		}
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				if (tmp[i][j] != 1)
					return false;
		return true;
	}

猜你喜欢

转载自blog.csdn.net/weixin_41746479/article/details/121291233