数据结构之程序员常用10种算法,Alibaba技术官内部私藏MySQL笔记分享

}

System.out.println(“得到的选择结果是” + selects);//[K1,K2,K3,K5]

}

}

4.贪心算法注意事项和细节

在这里插入图片描述

六、普里姆算法


1.修路问题

在这里插入图片描述

2.最小生成树

在这里插入图片描述

3.算法介绍

在这里插入图片描述

4.实践

在这里插入图片描述

package com.atguigu.prim;

import java.util.Arrays;

public class PrimAlgorithm {

public static void main(String[] args) {

//测试看看图是否创建ok

char[] data = new char[]{‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’};

int verxs = data.length;

//邻接矩阵的关系使用二维数组表示,10000这个大数,表示两个点不联通

int [][]weight=new int[][]{

{10000,5,7,10000,10000,10000,2},

{5,10000,10000,9,10000,10000,3},

{7,10000,10000,10000,8,10000,10000},

{10000,9,10000,10000,10000,4,10000},

{10000,10000,8,10000,10000,5,4},

{10000,10000,10000,4,5,10000,6},

{2,3,10000,10000,4,6,10000},};

//创建MGraph对象

MGraph graph = new MGraph(verxs);

//创建一个MinTree对象

MinTree minTree = new MinTree();

minTree.createGraph(graph, verxs, data, weight);

//输出

minTree.showGraph(graph);

//测试普利姆算法

minTree.prim(graph, 1);//

}

}

//创建最小生成树->村庄的图

class MinTree {

//创建图的邻接矩阵

/**

  • @param graph 图对象

  • @param verxs 图对应的顶点个数

  • @param data 图的各个顶点的值

  • @param weight 图的邻接矩阵

*/

public void createGraph(MGraph graph, int verxs, char data[], int[][] weight) {

int i, j;

for(i = 0; i < verxs; i++) {//顶点

graph.data[i] = data[i];

for(j = 0; j < verxs; j++) {

graph.weight[i][j] = weight[i][j];

}

}

}

//显示图的邻接矩阵

public void showGraph(MGraph graph) {

for(int[] link: graph.weight) {

System.out.println(Arrays.toString(link));

}

}

//编写prim算法,得到最小生成树

/**

  • @param graph 图

  • @param v 表示从图的第几个顶点开始生成’A’->0 ‘B’->1…

*/

public void prim(MGraph graph, int v) {

//visited[] 标记结点(顶点)是否被访问过

int visited[] = new int[graph.verxs];

//visited[] 默认元素的值都是0, 表示没有访问过

// for(int i =0; i <graph.verxs; i++) {

// visited[i] = 0;

// }

//把当前这个结点标记为已访问

visited[v] = 1;

//h1 和 h2 记录两个顶点的下标

int h1 = -1;

int h2 = -1;

int minWeight = 10000; //将 minWeight 初始成一个大数,后面在遍历过程中,会被替换

for(int k = 1; k < graph.verxs; k++) {//因为有 graph.verxs顶点,普利姆算法结束后,有 graph.verxs-1边

//这个是确定每一次生成的子图 ,和哪个结点的距离最近

for(int i = 0; i < graph.verxs; i++) {// i结点表示被访问过的结点

for(int j = 0; j< graph.verxs;j++) {//j结点表示还没有访问过的结点

if(visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight) {

//替换minWeight(寻找已经访问过的结点和未访问过的结点间的权值最小的边)

minWeight = graph.weight[i][j];

h1 = i;

h2 = j;

}

}

}

//找到一条边是最小

System.out.println(“边<” + graph.data[h1] + “,” + graph.data[h2] + “> 权值:” + minWeight);

//将当前这个结点标记为已经访问

visited[h2] = 1;

//minWeight 重新设置为最大值 10000

minWeight = 10000;

}

}

}

class MGraph {

int verxs; //表示图的节点个数

char[] data;//存放结点数据

int[][] weight; //存放边,就是我们的邻接矩阵

public MGraph(int verxs) {

this.verxs = verxs;

data = new char[verxs];

weight = new int[verxs][verxs];

}

}

七、克鲁斯卡尔算法


1.公交站问题

在这里插入图片描述

2.算法介绍

在这里插入图片描述

3.实践

package com.atguigu.kruskal;

import java.util.Arrays;

public class KruskalCase {

private int edgeNum; //边的个数

private char[] vertexs; //顶点数组

private int[][] matrix; //邻接矩阵

//使用 INF 表示两个顶点不能连通

private static final int INF = Integer.MAX_VALUE;

public static void main(String[] args) {

char[] vertexs = {‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’};

//克鲁斯卡尔算法的邻接矩阵

int matrix[][] = {

/A//B//C//D//E//F//G/

/A/ { 0, 12, INF, INF, INF, 16, 14},

/B/ { 12, 0, 10, INF, INF, 7, INF},

/C/ { INF, 10, 0, 3, 5, 6, INF},

/D/ { INF, INF, 3, 0, 4, INF, INF},

/E/ { INF, INF, 5, 4, 0, 2, 8},

/F/ { 16, 7, 6, INF, 2, 0, 9},

/G/ { 14, INF, INF, INF, 8, 9, 0}};

//大家可以在去测试其它的邻接矩阵,结果都可以得到最小生成树.

//创建KruskalCase 对象实例

KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);

//输出构建的

kruskalCase.print();

kruskalCase.kruskal();

}

//构造器

public KruskalCase(char[] vertexs, int[][] matrix) {

//初始化顶点数和边的个数

int vlen = vertexs.length;

//初始化顶点, 复制拷贝的方式

this.vertexs = new char[vlen];

for(int i = 0; i < vertexs.length; i++) {

this.vertexs[i] = vertexs[i];

}

//初始化边, 使用的是复制拷贝的方式

this.matrix = new int[vlen][vlen];

for(int i = 0; i < vlen; i++) {

for(int j= 0; j < vlen; j++) {

this.matrix[i][j] = matrix[i][j];

}

}

//统计边的条数

for(int i =0; i < vlen; i++) {

for(int j = i+1; j < vlen; j++) {

if(this.matrix[i][j] != INF) {

edgeNum++;

}

}

}

}

public void kruskal() {

int index = 0; //表示最后结果数组的索引

int[] ends = new int[edgeNum]; //用于保存"已有最小生成树" 中的每个顶点在最小生成树中的终点

//创建结果数组, 保存最后的最小生成树

EData[] rets = new EData[edgeNum];

//获取图中 所有的边的集合 , 一共有12边

EData[] edges = getEdges();

System.out.println(“图的边的集合=” + Arrays.toString(edges) + " 共"+ edges.length); //12

//按照边的权值大小进行排序(从小到大)

sortEdges(edges);

//遍历edges 数组,将边添加到最小生成树中时,判断是准备加入的边否形成了回路,如果没有,就加入 rets, 否则不能加入

for(int i=0; i < edgeNum; i++) {

//获取到第i条边的第一个顶点(起点)

int p1 = getPosition(edges[i].start); //p1=4

//获取到第i条边的第2个顶点

int p2 = getPosition(edges[i].end); //p2 = 5

//获取p1这个顶点在已有最小生成树中的终点

int m = getEnd(ends, p1); //m = 4

//获取p2这个顶点在已有最小生成树中的终点

int n = getEnd(ends, p2); // n = 5

//是否构成回路

if(m != n) { //没有构成回路

ends[m] = n; // 设置m 在"已有最小生成树"中的终点 <E,F> [0,0,0,0,5,0,0,0,0,0,0,0]

rets[index++] = edges[i]; //有一条边加入到rets数组

}

}

//<E,F> <C,D> <D,E> <B,F> <E,G> <A,B>。

//统计并打印 “最小生成树”, 输出 rets

System.out.println(“最小生成树为”);

for(int i = 0; i < index; i++) {

System.out.println(rets[i]);

}

}

//打印邻接矩阵

public void print() {

System.out.println(“邻接矩阵为: \n”);

for(int i = 0; i < vertexs.length; i++) {

for(int j=0; j < vertexs.length; j++) {

System.out.printf(“%12d”, matrix[i][j]);

}

System.out.println();//换行

}

}

/**

  • 功能:对边进行排序处理, 冒泡排序

  • @param edges 边的集合

*/

private void sortEdges(EData[] edges) {

for(int i = 0; i < edges.length - 1; i++) {

for(int j = 0; j < edges.length - 1 - i; j++) {

if(edges[j].weight > edges[j+1].weight) {//交换

EData tmp = edges[j];

edges[j] = edges[j+1];

edges[j+1] = tmp;

}

}

}

}

/**

  • @param ch 顶点的值,比如’A’,‘B’

  • @return 返回ch顶点对应的下标,如果找不到,返回-1

*/

private int getPosition(char ch) {

for(int i = 0; i < vertexs.length; i++) {

if(vertexs[i] == ch) {//找到

return i;

}

}

//找不到,返回-1

return -1;

}

/**

  • 功能: 获取图中边,放到EData[] 数组中,后面我们需要遍历该数组

  • 是通过matrix 邻接矩阵来获取

  • EData[] 形式 [[‘A’,‘B’, 12], [‘B’,‘F’,7], …]

  • @return

*/

private EData[] getEdges() {

int index = 0;

EData[] edges = new EData[edgeNum];

for(int i = 0; i < vertexs.length; i++) {

for(int j=i+1; j <vertexs.length; j++) {

if(matrix[i][j] != INF) {

edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]);

}

}

}

return edges;

}

/**

  • 功能: 获取下标为i的顶点的终点(), 用于后面判断两个顶点的终点是否相同

  • @param ends : 数组就是记录了各个顶点对应的终点是哪个,ends 数组是在遍历过程中,逐步形成

  • @param i : 表示传入的顶点对应的下标

  • @return 返回的就是 下标为i的这个顶点对应的终点的下标, 一会回头还有来理解

*/

private int getEnd(int[] ends, int i) { // i = 4 [0,0,0,0,5,0,0,0,0,0,0,0]

while(ends[i] != 0) {

i = ends[i];

}

return i;

}

}

//创建一个类EData ,它的对象实例就表示一条边

class EData {

char start; //边的一个点

char end; //边的另外一个点

int weight; //边的权值

//构造器

public EData(char start, char end, int weight) {

this.start = start;

this.end = end;

this.weight = weight;

}

//重写toString, 便于输出边信息

@Override

public String toString() {

return “EData [<” + start + ", " + end + ">= " + weight + “]”;

}

}

八、迪杰斯特拉算法


1.最短路径问题

在这里插入图片描述

2.算法介绍

在这里插入图片描述

3.算法过程

在这里插入图片描述

4.应用

package com.atguigu.dijkstra;

import java.util.Arrays;

public class DijkstraAlgorithm {

public static void main(String[] args) {

char[] vertex = { ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’ };

//邻接矩阵

int[][] matrix = new int[vertex.length][vertex.length];

final int N = 65535;// 表示不可以连接

matrix[0]=new int[]{N,5,7,N,N,N,2};

matrix[1]=new int[]{5,N,N,9,N,N,3};

matrix[2]=new int[]{7,N,N,N,8,N,N};

matrix[3]=new int[]{N,9,N,N,N,4,N};

matrix[4]=new int[]{N,N,8,N,N,5,4};

matrix[5]=new int[]{N,N,N,4,5,N,6};

matrix[6]=new int[]{2,3,N,N,4,6,N};

//创建 Graph对象

Graph graph = new Graph(vertex, matrix);

//测试, 看看图的邻接矩阵是否ok

graph.showGraph();

//测试迪杰斯特拉算法

graph.dsj(2);//C

graph.showDijkstra();

}

}

class Graph {

private char[] vertex; // 顶点数组

private int[][] matrix; // 邻接矩阵

private VisitedVertex vv; //已经访问的顶点的集合

// 构造器

public Graph(char[] vertex, int[][] matrix) {

this.vertex = vertex;

this.matrix = matrix;

}

//显示结果

public void showDijkstra() {

vv.show();

}

// 显示图

public void showGraph() {

for (int[] link : matrix) {

System.out.println(Arrays.toString(link));

}

}

//迪杰斯特拉算法实现

/**

  • @param index 表示出发顶点对应的下标

*/

public void dsj(int index) {

vv = new VisitedVertex(vertex.length, index);

update(index);//更新index顶点到周围顶点的距离和前驱顶点

for(int j = 1; j <vertex.length; j++) {

index = vv.updateArr();// 选择并返回新的访问顶点

update(index); // 更新index顶点到周围顶点的距离和前驱顶点

}

}

//更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点,

private void update(int index) {

int len = 0;

//根据遍历我们的邻接矩阵的 matrix[index]行

for(int j = 0; j < matrix[index].length; j++) {

// len 含义是 : 出发顶点到index顶点的距离 + 从index顶点到j顶点的距离的和

len = vv.getDis(index) + matrix[index][j];

// 如果j顶点没有被访问过,并且 len 小于出发顶点到j顶点的距离,就需要更新

if(!vv.in(j) && len < vv.getDis(j)) {

vv.updatePre(j, index); //更新j顶点的前驱为index顶点

vv.updateDis(j, len); //更新出发顶点到j顶点的距离

}

}

}

}

// 已访问顶点集合

class VisitedVertex {

// 记录各个顶点是否访问过 1表示访问过,0未访问,会动态更新

public int[] already_arr;

// 每个下标对应的值为前一个顶点下标, 会动态更新

public int[] pre_visited;

// 记录出发顶点到其他所有顶点的距离,比如G为出发顶点,就会记录G到其它顶点的距离,会动态更新,求的最短距离就会存放到dis

public int[] dis;

//构造器

/**

  • @param length :表示顶点的个数

  • @param index: 出发顶点对应的下标, 比如G顶点,下标就是6

*/

public VisitedVertex(int length, int index) {

this.already_arr = new int[length];

this.pre_visited = new int[length];

this.dis = new int[length];

//初始化 dis数组

Arrays.fill(dis, 65535);

this.already_arr[index] = 1; //设置出发顶点被访问过

this.dis[index] = 0;//设置出发顶点的访问距离为0

}

/**

  • 功能: 判断index顶点是否被访问过

  • @param index

  • @return 如果访问过,就返回true, 否则访问false

*/

public boolean in(int index) {

return already_arr[index] == 1;

}

/**

  • 功能: 更新出发顶点到index顶点的距离

  • @param index

  • @param len

*/

public void updateDis(int index, int len) {

dis[index] = len;

}

/**

  • 功能: 更新pre这个顶点的前驱顶点为index顶点

  • @param pre

  • @param index

*/

public void updatePre(int pre, int index) {

pre_visited[pre] = index;

}

/**

  • 功能:返回出发顶点到index顶点的距离

  • @param index

*/

public int getDis(int index) {

return dis[index];

}

/**

  • 继续选择并返回新的访问顶点, 比如这里的G 完后,就是 A点作为新的访问顶点(注意不是出发顶点)

  • @return

*/

public int updateArr() {

int min = 65535, index = 0;

for(int i = 0; i < already_arr.length; i++) {

if(already_arr[i] == 0 && dis[i] < min ) {

min = dis[i];

index = i;

}

}

//更新 index 顶点被访问过

already_arr[index] = 1;

return index;

}

//显示最后的结果

//即将三个数组的情况输出

public void show() {

System.out.println(“==========================”);

//输出already_arr

for(int i : already_arr) {

System.out.print(i + " ");

}

System.out.println();

//输出pre_visited

for(int i : pre_visited) {

System.out.print(i + " ");

}

System.out.println();

//输出dis

for(int i : dis) {

System.out.print(i + " ");

}

System.out.println();

//为了好看最后的最短距离,我们处理

char[] vertex = { ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’ };

int count = 0;

for (int i : dis) {

if (i != 65535) {

System.out.print(vertex[count] + “(”+i+") ");

} else {

System.out.println("N ");

}

count++;

}

System.out.println();

}

}

九、弗洛伊德算法


1.算法介绍

在这里插入图片描述

2.算法分析

在这里插入图片描述

3.应用

在这里插入图片描述

package com.atguigu.floyd;

import java.util.Arrays;

public class FloydAlgorithm {

public static void main(String[] args) {

// 测试看看图是否创建成功

char[] vertex = { ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’ };

//创建邻接矩阵

int[][] matrix = new int[vertex.length][vertex.length];

final int N = 65535;

matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };

matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };

matrix[2] = new int[] { 7, N, 0, N, 8, N, N };

matrix[3] = new int[] { N, 9, N, 0, N, 4, N };

matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };

matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };

matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };

//创建 Graph 对象

Graph graph = new Graph(vertex.length, matrix, vertex);

//调用弗洛伊德算法

graph.floyd();

graph.show();

}

}

// 创建图

class Graph {

private char[] vertex; // 存放顶点的数组

private int[][] dis; // 保存,从各个顶点出发到其它顶点的距离,最后的结果,也是保留在该数组

private int[][] pre;// 保存到达目标顶点的前驱顶点

// 构造器

/**

  • @param length

  •        大小
    
  • @param matrix

  •        邻接矩阵
    
  • @param vertex

  •        顶点数组
    

*/

public Graph(int length, int[][] matrix, char[] vertex) {

this.vertex = vertex;

this.dis = matrix;

this.pre = new int[length][length];

// 对pre数组初始化, 注意存放的是前驱顶点的下标

for (int i = 0; i < length; i++) {

Arrays.fill(pre[i], i);

}

}

// 显示pre数组和dis数组

public void show() {

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

image

image

其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣,

/ 存放顶点的数组

private int[][] dis; // 保存,从各个顶点出发到其它顶点的距离,最后的结果,也是保留在该数组

private int[][] pre;// 保存到达目标顶点的前驱顶点

// 构造器

/**

  • @param length

  •        大小
    
  • @param matrix

  •        邻接矩阵
    
  • @param vertex

  •        顶点数组
    

*/

public Graph(int length, int[][] matrix, char[] vertex) {

this.vertex = vertex;

this.dis = matrix;

this.pre = new int[length][length];

// 对pre数组初始化, 注意存放的是前驱顶点的下标

for (int i = 0; i < length; i++) {

Arrays.fill(pre[i], i);

}

}

// 显示pre数组和dis数组

public void show() {

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-lmdLC7Fb-1710758852629)]
[外链图片转存中…(img-hSohbPnb-1710758852630)]
[外链图片转存中…(img-gEfNNxWz-1710758852630)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-Gu1TmdAU-1710758852631)]

最后

整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

[外链图片转存中…(img-2KuFm024-1710758852631)]

[外链图片转存中…(img-92np04br-1710758852631)]

其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣,

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值