一. 排序

1. 桶排序

import java.util.Scanner;
//桶排序
public class BucketSort {static int[] book; // 标记数字被访问的次数static int n; // 要输入的数字的总数// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();book = new int[100001]; // 需要保证输入的数小于100001,此时book数组已经自动被初始化为0了int t; // 暂时存储要输入的数字for (int i = 1; i <= n; i++) {t = input.nextInt();book[t]++; // 标记该数字被输入了几次}input.close();}// 堆排序核心static void bucketSort() {int flag = 0;// 从小到大排序for (int i = 0; i <= 100000; i++) {for (int j = 1; j <= book[i]; j++) {if (flag == 0) { // 使输出的第一个数前面没有空格System.out.print(i);flag = 1;} else {System.out.print(" " + i);}}}}// 程序入口public static void main(String[] args) {bucketSort();}
}

可以输入以下数据验证:

10
8 100 50 22 15 6 1 1000 999 0

运行结果是:

0 1 6 8 15 22 50 100 999 1000

2. 冒泡排序

import java.util.Scanner;
//冒泡排序
public class BubbleSort {static int n; // 存储数的多少static int[] a; // 数组存储输入的数// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();a = new int[n + 1];for (int i = 1; i <= n; i++) {a[i] = input.nextInt();}input.close();}// 冒泡排序核心static void bubbleSort() {int temp;for (int i = 1; i <= n - 1; i++) {for (int j = 1; j <= n - i; j++) {// 从小到大排序if (a[j] > a[j + 1]) {temp = a[j];a[j] = a[j + 1];a[j + 1] = temp;}}}}public static void main(String[] args) {bubbleSort(); // 调用函数int flag = 0;for (int i = 1; i <= n; i++) {if (flag == 0) {System.out.print(a[i]);flag = 1;} else {System.out.print(" " + a[i]);}}}
}

可以输入以下数据验证:

10
8 100 50 22 15 6 1 1000 999 0

运行结果是:

0 1 6 8 15 22 50 100 999 1000

3. 快速排序

import java.util.Scanner;
//快速排序算法
public class QuickSort {static int n; // 数组的大小static int[] a; // 数组存储数// 初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();a = new int[n + 1];for (int i = 1; i <= n; i++) {a[i] = input.nextInt();}input.close();}// 快速排序核心static void quickSort(int left, int right) {int i, j, temp, t;// 递归退出条件if (left > right)return;temp = a[left];i = left;j = right;while (i != j) {// 从右往左找while (a[j] >= temp && i < j)j--;// 从左往右找while (a[i] <= temp && i < j)i++;if (i < j) {t = a[i];a[i] = a[j];a[j] = t;}}a[left] = a[i];a[i] = temp;quickSort(left, i - 1);quickSort(i + 1, right);return;}public static void main(String[] args) {quickSort(1, n); //调用函数int flag = 0;for (int i = 1; i <= n; i++) {if (flag == 0) {System.out.print(a[i]);flag = 1;} else {System.out.print(" " + a[i]);}}}
}

可以输入以下数据进行验证:

10
6 1 2 7 9 3 4 5 10 8

输出结果:

1 2 3 4 5 6 7 8 9 10

二. 栈、队列、链表

1. 队列

题目:解密QQ号:给一个加密过的QQ号,首先将第一个数删除,紧接着将第2个数放到这串数的末尾,再将第3个数删除并将第4个数放到这串数的末尾,再将第5个数删除……直到剩下最后一个数,将最后一个数也删除。按照刚才删除的顺序,把这些删除的数连在一起就是QQ号,并把该QQ号输出

import java.util.Scanner;
public class Queue {static int n; // 数的个数static int[] q;static int head, tail;// 初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();q = new int[102];for (int i = 1; i <= n; i++) {q[i] = input.nextInt();}head = 1;tail = n + 1;input.close();}// 核心函数static void keyQueue() {while (head < tail) {System.out.print(q[head] + " ");head++; // 出队q[tail] = q[head]; // 将队首的放在队尾tail++;// 再将队首出队head++;}}public static void main(String[] args) {keyQueue();//调用函数}
}

可以输入以下数据进行验证:

9
6 3 1 7 5 8 9 2 4

输出结果:

6 1 5 9 4 7 2 8 3

2. 栈

题目:使用栈判断一个字符串是否为回文

import java.util.Scanner;
public class Stack {static String string;static char[] a, s;static int next, top, mid, len;// 初始化static {Scanner input = new Scanner(System.in);string = input.nextLine();s = new char[string.length()];a = new char[string.length()];a = string.toCharArray(); // 将字符串转化为字符数组len = string.length(); // 字符串的长度mid = len / 2 - 1; // 字符串的中点top = 0; // 栈的初始化input.close();}public static void main(String[] args) {// 将mid前的字符依次入栈for (int i = 0; i <= mid; i++) {s[++top] = a[i];}// 判断字符串的长度是奇数还是偶数if (len % 2 == 0)next = mid + 1;elsenext = mid + 2;// 开始匹配for (int i = next; i <= len - 1; i++) {if (a[i] != s[top])break;top--;}// 如果top的值为0,则说明栈内所有的字符都被一一匹配了if (top == 0)System.out.print("YES");elseSystem.out.print("NO");}
}

可以输入以下数据进行验证:

ahaha

运行结果是:

YES

三.万能的搜索

1. 深度优先搜索

题目:输入一个数n, 输出1~n的全排列

import java.util.Scanner;
//排数的深度优先搜索
public class DFS {static int n;static int[] a;static int[] book; // 标记数组// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();input.close();a = new int[n + 1];book = new int[n + 1];}static void dfs(int step) {if (step == n + 1) {for (int temp = 1; temp <= n; temp++)System.out.print(a[temp]);System.out.println();return;}for (int i = 1; i <= n; i++) {if (book[i] == 0) {a[step] = i;book[i] = 1;dfs(step + 1);book[i] = 0;}}return;}public static void main(String[] args) {dfs(1);}
}

可以输入以下数据进行验证:

3

运行结果是:

123
132
213
231
312
321

题目:走迷宫,指定起始点和终止点,迷宫上有些地方障碍物,找到并输出从起始点到终止点的最短距离

import java.util.Scanner;
//走迷宫
public class DFS2 {static int[][] a;// 存储迷宫的0和1static int[][] next = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };// 存上下左右的尝试,顺序为右下左上static int startx, starty, endx, endy;// 输入的开始和结束点static int n, m;// 迷宫行和列static int[][] book; // 标记迷宫是否走过static int min = 9999999; // 计算最小的步数// 初始化static {Scanner input = new Scanner(System.in);// 输入迷宫的行和列n = input.nextInt();m = input.nextInt();// 输入迷宫的开始坐标和结束坐标startx = input.nextInt();starty = input.nextInt();endx = input.nextInt();endy = input.nextInt();a = new int[n + 1][m + 1];for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)a[i][j] = input.nextInt();book = new int[n + 1][m + 1];input.close();}// 深度优先搜索(dfs)static void dfs(int x, int y, int step) {// 结束条件if (x == endx && y == endy) {if (step <= min) {min = step;}return;}// 开始尝试for (int k = 0; k <= 3; k++) {int tx, ty;tx = x + next[k][0];ty = y + next[k][1];// 判断是否越界if (tx < 1 || tx > n || ty < 1 || ty > m)continue;if (a[tx][ty] == 0 && book[tx][ty] == 0) {book[tx][ty] = 1;dfs(tx, ty, step + 1);book[tx][ty] = 0;}}return;}public static void main(String[] args) {dfs(startx, starty, 0); // 调用函数System.out.println(min);}
}

可以输入以下数据进行验证:

5 4
1 1 4 3
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1

运行结果是:

7

2. 广度优先搜索

题目:走迷宫,指定起始点和终止点,迷宫上有些地方障碍物,找到并输出从起始点到终止点的最短距离

import java.util.Scanner;
//走迷宫
public class BFS2 {static int[][] a; // 存储迷宫static int[][] book; // 标记点是否走过static int[][] next = { { 1, 0 }, { 0, -1 }, { 0, 1 }, { -1, 0 } };// 下一步的路线static int n, m; // 迷宫的行和列static int startx, starty, endx, endy;// 迷宫的起点和终点// 队列数据结构存储迷宫的点static class BfsQueue {public int x;// 存储横坐标public int y;// 存储纵坐标public int s;// 存储步数public int f;// 存储上一个节点}static BfsQueue[] bfsQueues; // 队列数组static int head, tail; // 队列的头指针和尾指针// 所有变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();// 输入迷宫行数m = input.nextInt();// 输入迷宫列数startx = input.nextInt();// 输入开始横坐标starty = input.nextInt();// 输入开始列坐标endx = input.nextInt();// 输入结束横坐标endy = input.nextInt();// 输入结束列坐标a = new int[n + 1][m + 1];book = new int[n + 1][m + 1];bfsQueues = new BfsQueue[n * m + 1];for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)a[i][j] = input.nextInt();// 队列数据初始化head = tail = 1;bfsQueues[tail] = new BfsQueue();bfsQueues[tail].x = startx;bfsQueues[tail].y = starty;bfsQueues[tail].s = 0;bfsQueues[tail].f = 0;tail++;book[startx][starty] = 1;input.close();}public static void main(String[] args) {int tx, ty;int flag = 0;while (head < tail) {for (int i = 0; i <= 3; i++) {tx = bfsQueues[head].x + next[i][0];ty = bfsQueues[head].y + next[i][1];// 判断是否越界if (tx < 1 || tx > n || ty < 1 || ty > m)continue;// 正常情况下,尾指针加一if (a[tx][ty] == 0 && book[tx][ty] == 0) {bfsQueues[tail] = new BfsQueue();book[tx][ty] = 1;bfsQueues[tail].x = tx;bfsQueues[tail].y = ty;bfsQueues[tail].f = head;bfsQueues[tail].s = bfsQueues[head].s + 1;tail++;}// 判断是否到达终点,如果是直接退出循环if (tx == endx && ty == endy) {flag = 1;break;}}if (flag == 1)break;head++;}System.out.println(bfsQueues[tail - 1].s);}
}

可以输入以下数据进行验证:

5 4
1 1 4 3
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1

运行结果是:

7

四. 图

1. 图的遍历

深度优先搜索遍历图

import java.util.Scanner;
//深度优先搜索遍历图
public class GraphDFS {static int[][] e; // 邻接矩阵存储图static int[] book; // 标记数组static int n, m; // 图的点static int sum; // 判断是否已经遍历完了所有点// 初始化变量static {Scanner input = new Scanner(System.in);n = input.nextInt(); // 输入顶点数m = input.nextInt(); // 输入边数sum = 0;book = new int[n + 1];e = new int[n + 1][n + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999;}}int a, b; // 展示存储输入两个相连的点for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();e[a][b] = 1;e[b][a] = 1;}input.close();}// 深度优先搜索图static void dfs(int cur) {System.out.print(cur + " ");if (sum == n)return;sum++;// 每访问一个点sum加一for (int i = 1; i <= n; i++) {if (e[cur][i] == 1 && book[i] == 0) {book[i] = 1;dfs(i);}}return;}public static void main(String[] args) {book[1] = 1;dfs(1);}
}

可以输入以下数据进行验证:

5 5
1 2
1 3
1 5
2 4
3 5

运行结果是:

1 2 4 3 5

广度优先搜索遍历图

//广度优先搜索遍历图
public class GraphBFS {static int[][] e; // 邻接矩阵存储图static int[] book; // 标记矩阵static int n, m; // 顶点数目与边的数目static int head, tail;// 队列的头尾指针static int[] bfsqueues; // 队列数组// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt(); // 输入顶点数m = input.nextInt(); // 输入边数e = new int[n + 1][n + 1];book = new int[n + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999;}}int a, b; // 展示存储输入两个相连的点for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();e[a][b] = 1;e[b][a] = 1;}bfsqueues = new int[n + 1];head = tail = 1;bfsqueues[tail] = 1;book[tail] = 1;tail++;input.close();}// 广度优先搜索static void bfs() {while (head < tail && tail <= n) {for (int i = 1; i <= n; i++) {if (e[bfsqueues[head]][i] == 1 && book[i] == 0) {book[i] = 1;bfsqueues[tail] = i;tail++;}}if (tail > n) {break;}head++;}}public static void main(String[] args) {bfs();for (int i = 1; i <= tail - 1; i++)System.out.print(bfsqueues[i] + " ");}
}

可以输入以下数据进行验证:

5 5
1 2
1 3
1 5
2 4
3 5

运行结果是:

1 2 3 5 4

2. 图的深度优先遍历

用深度优先搜索求最短路径

import java.util.Scanner;
//最短路径的深度优先搜索
public class ShortestDFS {static int[][] e;// 存储图static int[] book; // 标记数组static int peak; // 图的顶点的个数static int side; // 图的边的数目static int min = 99999; // 两个点不能到达的距离static int s = 0;static int start, end; // 图中开始的点和结束的点// 变量初始化static {Scanner input = new Scanner(System.in);peak = input.nextInt(); // 输入图的顶点数目side = input.nextInt(); // 输入图的边的数目e = new int[peak + 1][peak + 1];book = new int[peak + 1];start = input.nextInt();// 输入图的开始点end = input.nextInt();// 输入图的结束点for (int i = 1; i <= peak; i++) {for (int j = 1; j <= peak; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999;}}int a, b, c; // 相应顶点和相应的边的长度for (int i = 1; i <= side; i++) {a = input.nextInt();b = input.nextInt();c = input.nextInt();e[a][b] = c;}input.close();}// 深度优先搜索static void dfs(int cur, int s) {if (s > min)return;if (cur == end) {if (s < min)min = s;return;}for (int i = 1; i <= peak; i++) {if (e[cur][i] < 99999 && book[i] == 0) {book[i] = 1;dfs(i, s + e[cur][i]);book[i] = 0;}}return;}public static void main(String[] args) {dfs(start, 0);System.out.println(min);}
}

可以输入以下数据进行验证:

5 8
1 5
1 2 2
1 5 10
2 3 3
2 5 7
3 1 4
3 4 4
4 5 5
5 3 3

运行结果是:

9

3. 图的广度优先遍历

求两个顶点之间最少经过几条边可以到达

import java.util.Scanner;
//图中两个点间隔的点的个数最少,最少转机数
public class GraphBFS2 {static int[][] e; // 存储图static int[] book; // 标记数组static int n; // 图的顶点数static int side; // 图的边数static int start, end; // 开始顶点和结束顶点static int head, tail; // 队列的头尾指针;static class BfsQueue {public int cur; // 图的顶点public int s; // 经过的距离public int f; // 上一个顶点的位置}static BfsQueue[] bfsQueues; // 队列数组// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();// 输入顶点数目e = new int[n + 1][n + 1];book = new int[n + 1];side = input.nextInt(); // 输入边的数目start = input.nextInt(); // 输入开始的顶点end = input.nextInt(); // 输入结束的顶点for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999;}}// 输入对应的顶点和边的长度int a, b;for (int i = 1; i <= side; i++) {a = input.nextInt();b = input.nextInt();e[a][b] = 1;e[b][a] = 1;}input.close();head = tail = 1;bfsQueues = new BfsQueue[n + 1];bfsQueues[tail] = new BfsQueue();bfsQueues[tail].cur = start;bfsQueues[tail].s = 0;bfsQueues[tail].f = 0;book[start] = 1;tail++;}// 广度优先搜索static void bfs() {int flag = 0;while (head < tail) {for (int i = 1; i <= n; i++) {if (e[bfsQueues[head].cur][i] < 99999 && book[i] == 0) {book[i] = 1;bfsQueues[tail] = new BfsQueue();bfsQueues[tail].cur = i;bfsQueues[tail].f = head;bfsQueues[tail].s = bfsQueues[head].s + 1;tail++;}if (bfsQueues[tail - 1].cur == end) {flag = 1;return;}}if (flag == 1)break;head++;}}public static void main(String[] args) {bfs();System.out.println(bfsQueues[tail - 1].s);}
}

可以输入以下数据进行验证:

5 7 1 5
1 2
1 3
2 3
2 4
3 4
3 5
4 5

运行结果是:

2

五.最短路径

1. Floyed-Warshall

import java.util.Scanner;
//最短路径算法,只有五行的算法
public class Floyd_Warshall {static int[][] a; // 用邻接矩阵存储图static int n; // n表示邻接矩阵的行号和列号static int m; // 有多少条路线// 初始化static {Scanner input = new Scanner(System.in);n = input.nextInt(); // 输入顶点数目m = input.nextInt(); // 输入边的数目a = new int[n + 1][n + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)a[i][j] = 0;elsea[i][j] = 99999;}}int b, c, d; // 展示存储输入的点和边for (int i = 1; i <= m; i++) {b = input.nextInt();c = input.nextInt();d = input.nextInt();a[b][c] = d;}input.close();}// 最短路径求解static void floyed_worshall() {for (int k = 1; k <= n; k++) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (a[i][k] < 99999 && a[k][j] < 99999 && a[i][j] > a[i][k] + a[k][j]) {a[i][j] = a[i][k] + a[k][j];}}}}}public static void main(String[] args) {floyed_worshall();for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {System.out.print(a[i][j] + " ");}System.out.println();}}
}

可以输入以下数据进行验证:

4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12

运行结果为:

0 2 5 4
9 0 3 4
6 8 0 1
5 7 10 0

2. Dijkstra

import java.util.Scanner;
//Dijkstra算法最短路径算法
public class Dijkstra {static int[][] e; // 邻接矩阵存储图static int n, m; // 图的顶点数和边的数目static int[] dis; // 已知的最短路径static int[] book; // 标记是否是已经确定的最短路径static {Scanner input = new Scanner(System.in);n = input.nextInt(); // 输入顶点数目m = input.nextInt(); // 输入边的数目e = new int[n + 1][n + 1];dis = new int[n + 1];book = new int[n + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999;}}int a, b, c;for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();c = input.nextInt();e[a][b] = c;}// 一号顶点到其余顶点的最短距离for (int i = 1; i <= n; i++) {dis[i] = e[1][i];}for (int i = 1; i <= n; i++) {book[i] = 0;}book[1] = 1;input.close();}static void dijkstra() {int min;int temp = 1;// dis数组已经确定了一个数了,因此只需要循环n-1次就行for (int i = 1; i <= n - 1; i++) {min = 999999;for (int j = 1; j <= n; j++) {if (book[j] == 0 && dis[j] < min) {min = dis[j];temp = j;}}if (temp != 1) {book[temp] = 1;for (int v = 1; v <= n; v++) {if (e[temp][v] < 99999) {if (dis[v] > dis[temp] + e[temp][v]) {dis[v] = dis[temp] + e[temp][v];}}}}}}public static void main(String[] args) {dijkstra();for (int i = 1; i <= n; i++) {System.out.print(dis[i] + " ");}}
}

可以输入以下数据进行验证:

6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4

运行结果是:

0 1 8 4 13 17

3. Bellman-Ford——解决负权边

import java.util.Scanner;
//最短路径算法,解决负权边的情况,还可以检测是否有负权回路
public class Bellman_Ford {static int n, m; // 图的顶点数和边的数目static int[] u, v, w; // 数组存储起点、终点、边的长度static int[] dis; // 存储最短的距离// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();m = input.nextInt();u = new int[m + 1];v = new int[m + 1];w = new int[m + 1];dis = new int[n + 1];for (int i = 1; i <= n; i++) {dis[i] = 99999;}dis[1] = 0;for (int i = 1; i <= m; i++) {u[i] = input.nextInt();v[i] = input.nextInt();w[i] = input.nextInt();}input.close();}// 最短路径算法关键static void bellmanFord() {int check; // 判断是否提前达到结果int flag = 0; // 判断是否有负权回路边for (int i = 1; i <= n - 1; i++) {check = 0;for (int j = 1; j <= m; j++) {if (dis[v[j]] > dis[u[j]] + w[j]) {dis[v[j]] = dis[u[j]] + w[j];check = 1;}}if (check == 0) {break;}}for (int i = 1; i <= m; i++) {if (dis[v[i]] > dis[u[i]] + w[i])flag = 1;}if (flag == 1)System.out.println("此图有负权回路");}public static void main(String[] args) {bellmanFord();for (int i = 1; i <= n; i++) {System.out.print(dis[i] + " ");}}
}

可以输入以下数据进行验证:

5 5
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3

运行结果是:

0 -3 -1 2 4

4. Bellman-Ford的队列优化

import java.util.Scanner;
//Bellman_Ford队列优化
public class Bellman_Ford_BetterQueue {static int n, m; // 图的顶点和边static int[] dis; // 存储最短距离static int[] book; // 标记点是否已经在队列中static int[] queue; // 存储对列static int head, tail; // 对列的头尾指针static int[] u, v, w; // 数组存储顶点和边的值static int[] first, next; // 邻接表存储// 初始化static {Scanner input = new Scanner(System.in);n = input.nextInt(); // 输入顶点数目m = input.nextInt(); // 输入边的数目dis = new int[n + 1];book = new int[n + 1];next = new int[m + 1];queue = new int[n * n + 1];first = new int[n + 1];u = new int[m + 1];v = new int[m + 1];w = new int[m + 1];for (int i = 1; i <= n; i++) {first[i] = -1;}for (int i = 1; i <= m; i++) {u[i] = input.nextInt();v[i] = input.nextInt();w[i] = input.nextInt();// 邻接表存储next[i] = first[u[i]];first[u[i]] = i;}for (int i = 1; i <= n; i++) {dis[i] = 99999;}dis[1] = 0;head = tail = 1;queue[tail] = 1;tail++;book[1] = 1;input.close();}// 核心算法static void bellman_FordBetterQueue() {int k;while (head < tail) {k = first[queue[head]];while (k != -1) {if (dis[v[k]] > dis[u[k]] + w[k]) {dis[v[k]] = dis[u[k]] + w[k];if (book[v[k]] == 0) {queue[tail] = v[k];book[v[k]] = 1;tail++;}}k = next[k];}book[queue[head]] = 0;head++;}}public static void main(String[] args) {bellman_FordBetterQueue();for (int i = 1; i <= n; i++) {System.out.print(dis[i] + " ");}}
}

可以输入以下数据进行验证:

5 7
1 2 2
1 5 10
2 3 3
2 5 7
3 4 4
4 5 5
5 3 6

运行结果是:

0 2 5 9 9

5.最短路径算法比较

Floyd Dijkstra Bellman-Ford 队列优化的Bellman-Ford
空间复杂度 O(N²) O(M) O(M) O(M)
时间复杂度 O(N³) O((M+N)㏒N) O(NM) 最坏也是O(NM)
适用情况 稠密图(顶点关系密切) 稠密图(顶点关系密切) 稀疏图(边关系密切) 稀疏图(边关系密切)
负权 可以解决负权 不能解决负权 可以解决负权 可以解决负权
有负权边 可以处理 不能处理 可以处理 可以处理
判断是否存在负权回路 不能 不能 可以判定 可以判定

六.神奇的树

1. 堆排序

import java.util.Scanner;
//堆排序
public class HeapSort {static int n; // 数的多少static int num; // 存储n的值static int[] h; // 用数组存储数// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();num = n;h = new int[n + 1];for (int i = 1; i <= n; i++) {h[i] = input.nextInt();}input.close();}// 交换函数static void swap(int x, int y) {int temp = h[x];h[x] = h[y];h[y] = temp;}// 向下调整,最大的值在最上面static void shiftdown(int i) {int flag = 0; // 标记是否已经排好顺序了int temp = i;while (i * 2 <= n && flag == 0) {if (h[i] < h[2 * i])temp = 2 * i;elsetemp = i;if (i * 2 + 1 <= n) {if (h[temp] < h[i * 2 + 1]) {temp = i * 2 + 1;}}if (temp != i) { // 说明temp的值改变了swap(temp, i);i = temp;} else {flag = 1;}}}// 建立堆static void creat() {for (int i = n / 2; i >= 1; i--) {shiftdown(i);}}// 堆排序static void heapSort() {while (n > 1) {swap(1, n);n--;shiftdown(1);}}public static void main(String[] args) {creat();heapSort();for (int i = 1; i <= num; i++) {System.out.print(h[i] + " ");}}
}

可以输入以下数据验证:

14
99 5 36 7 22 17 46 12 2 19 25 28 1 92

运行结果是:

1 2 5 7 12 17 19 22 25 28 36 46 92 99

2. 并查集

问题:现在有10个强盗:1与2是同伙,3与4是同伙,5与2是同伙,4与6是同伙,2与6是同伙,8与7是同伙,9与7是同伙,1与6是同伙,2与4是同伙。注意:同伙的同伙也是同伙,输出有多少独立的犯罪团伙

import java.util.Scanner;
//并查集
public class CheckAndSet {static int n; // 强盗的人数static int m; // 搜索到的线索条数static int[] h; // 数组用来保存强盗的头领// 初始化static {Scanner input = new Scanner(System.in);n = input.nextInt(); // 输入有多少人m = input.nextInt(); // 输入有多少条线索h = new int[n + 1];for (int i = 1; i <= n; i++) {h[i] = i;}int a, b;for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();merge(a, b);}input.close();}// 递归实现查找祖先结点static int getFather(int i) {if (h[i] == i) {return i;} else {h[i] = getFather(h[i]);return h[i];}}// 合并两个结点static void merge(int i, int j) {int t1, t2;t1 = getFather(i);t2 = getFather(j);if (t1 != t2) {h[t2] = t1;}}public static void main(String[] args) {int sum = 0;for (int i = 1; i <= n; i++) {if (h[i] == i) {sum++;}}System.out.println(sum);}
}

可以输入以下数据验证:

10 9
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4

运行结果是:

3

七. 更多精彩算法

1. 图的最小生成树(Kruskal算法)

import java.util.Scanner;//Kruskal 最小生成树
public class Kruskal {static int n, m; // n为顶点,m为边static class E { // 存储点和边的关系public int u;public int v;public int w;}static int[] f; // 并查集,判断是否已经相连static E[] es;// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();m = input.nextInt();es = new E[m + 1];f = new int[n + 1];for (int i = 1; i <= m; i++) {es[i] = new E();es[i].u = input.nextInt();es[i].v = input.nextInt();es[i].w = input.nextInt();}for (int i = 1; i <= n; i++) {f[i] = i;}input.close();}// 将边从小到大排序,快速排序static void quickSort(int left, int right) {int i, j, temp, t;// 递归退出条件if (left > right)return;temp = es[left].w;i = left;j = right;while (i != j) {while (es[j].w >= temp && i < j)j--;while (es[i].w <= temp && i < j)i++;if (i < j) {t = es[i].w;es[i].w = es[j].w;es[j].w = t;}}es[left].w = es[i].w;es[i].w = temp;quickSort(left, i - 1);quickSort(i + 1, right);return;}// 找到父节点static int getFather(int i) {if (i == f[i])return i;else {f[i] = getFather(f[i]);return f[i];}}// 并查集,连接顶点之间的关系static int merge(int i, int j) {int t1, t2;t1 = getFather(i);t2 = getFather(j);if (t1 != t2) {f[t2] = t1;return 1;} else {return 0;}}public static void main(String[] args) {int count = 0, sum = 0;quickSort(1, m);// Kruskal算法核心for (int i = 1; i <= m; i++) {if (merge(es[i].u, es[i].v) == 1) {count++;sum = sum + es[i].w;}if (count == n - 1)break;}System.out.println(sum);}
}

可以输入以下数据验证:

6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2

运行结果是:

19

2. 再谈最小生成树(Prim算法)

import java.util.Scanner;
//Prim 最小生成树
public class Prim {static int n, m; // n为顶点,m为边static int[][] e; // 邻接矩阵存储图static int[] book; // 标记数组是否已经是最小生成树static int[] dis;// 选择最短距离的边加入最小生成树static int sum;// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();m = input.nextInt();e = new int[n + 1][n + 1];sum = 0;book = new int[n + 1];dis = new int[n + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999;}}int a, b, c;for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();c = input.nextInt();e[a][b] = c;e[b][a] = c;}for (int i = 1; i <= n; i++)dis[i] = e[1][i];book[1] = 1;input.close();}// Prim核心算法static void prim() {int count = 0, min, temp = 0;count++;while (count < n) {min = 99999;for (int i = 1; i <= n; i++) {if (book[i] == 0 && dis[i] < min) {min = dis[i];temp = i;}}count++;book[temp] = 1;sum = sum + dis[temp];// 添加一个节点,更换dis数组的最小值for (int j = 1; j <= n; j++) {if (book[j] == 0 && e[temp][j] < dis[j]) {dis[j] = e[temp][j];}}}}public static void main(String[] args) {prim();System.out.println(sum);}
}

可以输入以下数据验证:

6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2

运行结果是:

19

3. 图的割点

import java.util.Scanner;
//图的割点问题
public class CutPoint {static int n, m; // 顶点数和边的数目static int[][] e; // 存储图的邻接矩阵static int[] num, low;static int[] flag;static int root;static int index;static {Scanner input = new Scanner(System.in);n = input.nextInt();m = input.nextInt();e = new int[n + 1][n + 1];num = new int[n + 1];low = new int[n + 1];flag = new int[n + 1];int a, b;for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)e[i][j] = 0;for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();e[a][b] = 1;e[b][a] = 1;}root = 1;index = 0;input.close();}static int min(int a, int b) {return a < b ? a : b;}// 深度优先搜索static void dfs(int cur, int father) {int child = 0;index++;num[cur] = index;low[cur] = index;for (int i = 1; i <= n; i++) {if (e[cur][i] == 1) {if (num[i] == 0) {child++;dfs(i, cur);low[cur] = min(low[cur], low[i]);if (cur != root && low[i] >= num[cur]) {flag[cur] = 1;}if (cur == root && child == 2) {flag[cur] = 1;}} else if (i != father) {// 如果顶点i曾经被访问过,并且这个顶点不是当前顶点cur的父亲,// 则说明此时的i为cur的祖先,因此需要更新当前结点cur能访问到最早顶点的时间戳low[cur] = min(low[cur], num[i]);}}}return;}public static void main(String[] args) {dfs(1, root);for (int i = 1; i <= n; i++) {if (flag[i] == 1) {System.out.print(i + " ");}}}
}

可以运行以下数据进行验证:

6 7
1 4
1 3
4 2
3 2
2 5
2 6
5 6

运行结果是:

2

4. 图的割边

import java.util.Scanner;
//割边,与割点类似
public class CutEdge {static int n, m;static int[][] e;static int[] num, low;static int index;static int root;// 变量初始化static {Scanner input = new Scanner(System.in);n = input.nextInt();m = input.nextInt();e = new int[n + 1][n + 1];int a, b;for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();e[a][b] = 1;e[b][a] = 1;}num = new int[n + 1];low = new int[n + 1];root = 1;index = 0;input.close();}// dfsstatic void dfs(int cur, int father) {index++;num[cur] = index;low[cur] = index;for (int i = 1; i <= n; i++) {if (e[cur][i] == 1) {if (num[i] == 0) {dfs(i, cur);low[cur] = Math.min(low[cur], low[i]);if (low[i] > num[cur]) {System.out.println(cur + "-" + i);}} else if (i != father) {low[cur] = Math.min(low[cur], num[i]);}}}}public static void main(String[] args) {dfs(1, root);}
}

可以输入以下数据进行验证:

6 6
1 4
1 3
4 2
3 2
2 5
5 6

运行结果是:

5-6
2-5

5. 二分图最大匹配

import java.util.Scanner;
//二分图的最大匹配
public class BipartiteGraph {static int n, m; // n为顶点,m为边static int[][] e;static int[] match; // 匹配数组static int[] book; // 标记数组static int sum;static {Scanner input = new Scanner(System.in);n = input.nextInt();m = input.nextInt();e = new int[n + 1][n + 1];match = new int[n + 1];book = new int[n + 1];int a, b;for (int i = 1; i <= m; i++) {a = input.nextInt();b = input.nextInt();e[a][b] = 1;}input.close();}static int dfs(int u) {for (int i = 1; i <= n; i++) {if (book[i] == 0 && e[u][i] == 1) {book[i] = 1; // 标记点i已被访问过// 如果点i未被配对或者找到了新的配对if (match[i] == 0 || dfs(match[i]) != 0) {// 更新配对关系match[i] = u;return 1;}}}return 0;}public static void main(String[] args) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {book[j] = 0; // 清空上次搜索时的标记if (dfs(i) == 1) {sum++; // 寻找增广路,如果找到,配对数加1}}}System.out.println(sum);}
}

可以输入以下数据进行验证:

3 5
1 1
1 2
2 2
2 3
3 1

运行结果是:

3

参考

《啊哈算法》

啊哈算法——Java实现相关推荐

  1. 推特雪花算法 java实现

    2019独角兽企业重金招聘Python工程师标准>>> package twiter.snowflake;/*** twitter的snowflake算法 -- java实现*/ p ...

  2. java dh算法_dh密钥交换算法java

    dh密钥交换算法java 迪菲-赫尔曼密钥交换(Diffie–Hellman key exchange,简称"D–H") 是一种安全协议. 它可以让双方在完全没有对方任何预先信息的 ...

  3. 数据结构和算法(Java)-张晨光-专题视频课程

    数据结构和算法(Java)-579人已学习 课程介绍         如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功. 想写出精炼.优秀的代码,不通过不断的锤炼,是很难做到的 ...

  4. floyed java_Floyd算法java实现demo

    Floyd算法java实现,如下: package a; /** * ┏┓ ┏┓+ + * ┏┛┻━━━┛┻┓ + + * ┃ ┃ * ┃ ━ ┃ ++ + + + * ████━████ ┃+ * ...

  5. 快速排序算法 java 实现

    快速排序算法 java 实现 快速排序算法Java实现 白话经典算法系列之六 快速排序 快速搞定 各种排序算法的分析及java实现 算法概念 快速排序是C.R.A.Hoare于1962年提出的一种划分 ...

  6. java 哈希一致算法_一致哈希算法Java实现

    一致哈希算法(Consistent Hashing Algorithms)是一个分布式系统中常用的算法.传统的Hash算法当槽位(Slot)增减时,面临所有数据重新部署的问题,而一致哈希算法确可以保证 ...

  7. java进程调度怎么画图,[Java教程]进程调度的两种算法JAVA实现

    [Java教程]进程调度的两种算法JAVA实现 0 2015-10-21 12:00:08 (SJF分为preemptive shortest job first(抢占式)和non-preemptiv ...

  8. LRU算法java实现

    LRU全称是Least Recently Used,即最近最久未使用的意思. LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定的空间已 ...

  9. 数据结构与算法-java笔记一 更新中

    数据结构与算法-java笔记一 更新中 数据结构与算法 什么是数据结构.算法 数据结构学了有什么用: 线性结构 数组 特点 应用 链表 存储结构 链表类型 单链表 双向链表 双向循环链表 链表与数组的 ...

  10. for循环的一个复制算法(Java)

    for循环的一个复制算法(Java) public class ForDemo0 {public static void main(String[] args) {int[] num={10,20,3 ...

最新文章

  1. Oracle Study之--ORA-12537(TNS:connection closed) 错误案例
  2. 就因为一个笔记本,运营和产品吵得不可开交......
  3. Linux(CentOs)下安装Phantomjs + Casperjs
  4. android用什么测试类,android – 使用firebase对类进行JUnit测试
  5. 信元模式mpls 避免环路_【基础】交换机堆叠模式
  6. 转行做产品经理需要学什么?
  7. CComPtr对象作为参数进行 1.值传递 2.引用传递 3.做为返回值的注意事项
  8. ubuntu下安装RabbitVCS(失败记录)
  9. oracle同步数据adg_数据库周刊31丨华为openGauss 正式开源;7月数据库排行榜发布......
  10. eBPF and IO Visor: The what, how, and what next!
  11. python做病毒传播的空间数据_利用4行Python代码监测每一行程序的运行时间和空间消耗...
  12. 彭亚雄:7月24日阿里云上海峰会企业存储大神
  13. 特殊回文数 C++解法
  14. 六轴机器人直角坐标系建立_工业机器人六种坐标系详解(图)
  15. 招银网络2018笔试分享
  16. CAD新建、保存图形文件
  17. 本野桂 出任索尼中国专业系统集团总裁
  18. maven 设置打包路径为模块_Maven项目的子模块不能打成jar包输出到lib目录
  19. 网络优化(三)——参数初始化
  20. C++ Standard Library

热门文章

  1. 将图片型pdf转成可选中文字型pdf(免费)
  2. R语言—简介、安装、包(package)的安装与加载
  3. 畅聊“云时代下的芯片设计”,Fabless IT走进嘉楠科技!
  4. OSG中读取shp数据
  5. 捷联惯导系统学习7.4(车载惯性/里程仪组合导航 )
  6. java应用程序字体太小_为什么在任何java应用程序中字体看起来都很糟糕?
  7. 影视后期好学吗?C4D精品教学合集,看完必成大神!(附链接)
  8. HBuilder与夜神模拟器
  9. oracle的采购管理模块,ORACLEERP采购管理模块操作手册
  10. Java 递归算法之斐波那契数列第 N 项