区别 | 联系 | |
---|---|---|
彻底 | 任意两个顶点之间都会有一条边 | |
连通 | 任意两个顶点之间都存在一条路径 | 彻底的必定连通 |
补充知识:偏序:有向图中两个顶点之间不存在环路,至于连通与否,是无所谓的。全序:就是在偏序的基础之上,有向无环图中的任意一对顶点还须要有明确的关系(反映在图中,就是单向连通的关系,注意不能双向连通,那就成环了)。html
问题3:广度优先遍历的代码理解。java
public Iterator<T> iteratorBFS(int startIndex) { Integer x; QueueADT<Integer> traversalQueue = new LinkedQueue<Integer>(); UnorderedListADT<T> resultList = new ArrayUnorderedList<T>(); if (!indexIsValid(startIndex)) return resultList.iterator(); boolean[] visited = new boolean[numVertices]; for (int i = 0; i < numVertices; i++) visited[i] = false; traversalQueue.enqueue(new Integer(startIndex)); visited[startIndex] = true; while (!traversalQueue.isEmpty()) { x = traversalQueue.dequeue(); resultList.addToRear(vertices[x.intValue()]); for (int i = 0; i < numVertices; i++) { if (adjMatrix[x.intValue()][i] && !visited[i]) { traversalQueue.enqueue(new Integer(i)); visited[i] = true; } } } return new GraphIterator(resultList.iterator()); }
//先把全部的顶点都标记成未访问的。 for (int i = 0; i < numVertices; i++) visited[i] = false;
//把其实顶点入队,标记为已访问。 traversalQueue.enqueue(new Integer(startIndex)); visited[startIndex] = true;
//当队不为空的时候,x等于队首元素 while (!traversalQueue.isEmpty()) { x = traversalQueue.dequeue(); //intValue()以 int 类型返回该 Integer 的值。把顶点对应的值放入无序列表中。 resultList.addToRear(vertices[x.intValue()]); //小于顶点数作一个循环,邻接矩阵的出的那个元素 for (int i = 0; i < numVertices; i++) { //若是顶点到i存在边而且i没有被标记,则i入队,i被标记。 if (adjMatrix[x.intValue()][i] && !visited[i]) { traversalQueue.enqueue(new Integer(i)); visited[i] = true; } } } return new GraphIterator(resultList.iterator());
resultGraph.adjMatrix[i][j]=Double.POSITIVE_INFINITY
是什么意思?问题1:git
问题1解决方案:改为下图就好,由于进行的是顶点的元素进行比较,而不是结点进行比较。算法
//增长顶点 public void addVertex(T vertex) { //越界扩容 if ((numVertices + 1) == adjMatrix.length) expandCapacity(); //把新加顶点到剩下全部顶点的路径定义为正无穷(邻接矩阵) vertices[numVertices] = vertex; for (int i = 0; i <= numVertices; i++) { adjMatrix[numVertices][i] = Double.POSITIVE_INFINITY; adjMatrix[i][numVertices] = Double.POSITIVE_INFINITY; } numVertices++; modCount++; }
//删除顶点 public void removeVertex(T vertex) { removeVertex(getIndex(vertex)); } //根据索引去找到该顶点 public void removeVertex(int index) { //当索引值存在时 if (indexIsValid(index)) { //从该顶点开始,顶点集中的每一个数的位置须要向前移一位 for (int j = index; j < numVertices - 1; j++) { vertices[j] = vertices[j + 1]; } //数组中的最后一个位置定义为空 vertices[numVertices - 1] = null; //从该顶点开始,边的起点从该顶点变为下一个顶点,由于顶点集的位置向前移了一位。 for (int i = index; i < numVertices - 1; i++) { for (int x = 0; x < numVertices; x++) adjMatrix[i][x] = adjMatrix[i + 1][x]; } //由于无向图,因此从该顶点开始,边的终点从该顶点变为下一个顶点依次类推 for (int i = index; i < numVertices; i++) { for (int x = 0; x < numVertices; x++) adjMatrix[x][i] = adjMatrix[x][i + 1]; } //数组中最后一个位置为空,到各个顶点的边为空 for (int i = 0; i < numVertices; i++) { adjMatrix[numVertices][i] = Double.POSITIVE_INFINITY; adjMatrix[i][numVertices] = Double.POSITIVE_INFINITY; } //个数-1,操做次数+1 numVertices--; modCount++; } }
//输入顶点添加边 public void addEdge(T vertex1, T vertex2, double weight) { //根据顶点的索引值添加边 addEdge(getIndex(vertex1), getIndex(vertex2), weight); } public void addEdge(int index1, int index2, double weight) { //当起点终点的索引值都存在的时候,由于是无向图,因此权重都相同,邻接矩阵相应的位置放入权重。操做次数+1 if (indexIsValid(index1) && indexIsValid(index2)) { adjMatrix[index1][index2] = weight; adjMatrix[index2][index1] = weight; modCount++; } }
//删除边 public void removeEdge(T vertex1, T vertex2) { //根据顶点的索引值删除边 removeEdge(getIndex(vertex1), getIndex(vertex2)); } public void removeEdge(int index1, int index2) { //当起点终点的索引值都存在的时候 if (indexIsValid(index1) && indexIsValid(index2)) { //把边上的权重都变为正无穷大 adjMatrix[index1][index2] = Double.POSITIVE_INFINITY; adjMatrix[index2][index1] = Double.POSITIVE_INFINITY; modCount++; } }
//找到两个顶点间的最短路径 public int shortestPathLength(T startVertex, T targetVertex) { //根据索引值找到最短路径长度 return shortestPathLength(getIndex(startVertex), getIndex(targetVertex)); } private int shortestPathLength(int startIndex, int targetIndex) { int result = 0; //若是起始索引值或者终止索引值不存在时,返回0 if (!indexIsValid(startIndex) || !indexIsValid(targetIndex)) return 0; int index1; //找到起点到终点最小路径的顶点的索引值 Iterator<Integer> it = iteratorShortestPathIndices(startIndex, targetIndex); //若是没有下一个则为0,没路径 if (it.hasNext()) index1 = ((Integer) it.next()).intValue(); else return 0; //有下一个则+1,做为长度 while (it.hasNext()) { result++; it.next(); } return result; }
//输出最小路径中的顶点 public Iterator iteratorShortestPath(T startVertex, T targetVertex) { return iteratorShortestPath(getIndex(startVertex), getIndex(targetVertex)); } public Iterator iteratorShortestPath(int startIndex, int targetIndex) { List<T> resultList = new ArrayList<T>(); if (!indexIsValid(startIndex) || !indexIsValid(targetIndex)) return resultList.iterator(); //获得最小路径中的顶点索引值 Iterator<Integer> it = iteratorShortestPathIndices(startIndex, targetIndex); //把对应的顶点添加到列表里 while (it.hasNext()) resultList.add(vertices[((Integer) it.next()).intValue()]); return new GraphIterator(resultList.iterator()); }
protected Iterator<Integer> iteratorShortestPathIndices(int startIndex, int targetIndex) { int index = startIndex; int[] pathLength = new int[numVertices];/*存路径的长度*/ int[] predecessor = new int[numVertices];/*前驱顶点*/ QueueADT<Integer> traversalQueue = new LinkedQueue<Integer>();/*索引值*/ UnorderedListADT<Integer> resultList = new ArrayUnorderedList<Integer>();/*顶点元素*/ /*若是索引值不存在或者起始终止索引值相等,返回无序列表中的顶点元素*/ if (!indexIsValid(startIndex) || !indexIsValid(targetIndex) || (startIndex == targetIndex)) return resultList.iterator(); /*作标记,先把标记数组所有变为false*/ boolean[] visited = new boolean[numVertices]; for (int i = 0; i < numVertices; i++) visited[i] = false; /*把起始索引值加入列表*/ traversalQueue.enqueue(Integer.valueOf(startIndex)); /*对该索引值进行标记*/ visited[startIndex] = true; /*该长度数组中该索引值的位置定位为0,前驱结点定义为-1*/ pathLength[startIndex] = 0; predecessor[startIndex] = -1; /*当索引值列表不为空而且起始和终止顶点元素不一样时*/ while (!traversalQueue.isEmpty() && (index != targetIndex)) { //index = 出队列的元素(也就是以前存入的索引值) index = (traversalQueue.dequeue()).intValue(); //找出该索引值到每一个顶点的边 for (int i = 0; i < numVertices; i++) { //若是边存在,而且终点未标记(也就是这个边没有找到过) if (adjMatrix[index][i] < Double.POSITIVE_INFINITY && !visited[i]) { /*把边的终点的索引值对应的长度数组+1*/ pathLength[i] = pathLength[index] + 1; /*前驱结点终点的索引值对应的位置存入index*/ predecessor[i] = index; /*把新的索引值加入队列*/ traversalQueue.enqueue(Integer.valueOf(i)); /*标记该顶点*/ visited[i] = true; } } } if (index != targetIndex) // no path must have been found return resultList.iterator(); StackADT<Integer> stack = new LinkedStack<Integer>(); index = targetIndex; //找到最小路径中的顶点索引值,进行入栈 stack.push(Integer.valueOf(index)); do { index = predecessor[index]; stack.push(Integer.valueOf(index)); } while (index != startIndex); //依次弹栈获得正确的顺序 while (!stack.isEmpty()) resultList.addToRear((stack.pop())); return new NetworkIndexIterator(resultList.iterator()); }
//找到最便宜的路 public double shortestPathWeight(T vertex1, T vertex2) { return shortestPathWeight(getIndex(vertex1), getIndex(vertex2)); } public double shortestPathWeight(int start, int end) { Double[] dist = new Double[numVertices];//存放该顶点对全部有边顶点的权重 boolean[] flag = new boolean[numVertices];//标记结点 for (int i = 0; i < numVertices; i++) { flag[i] = false;/*让全部都变成未标记*/ dist[i] = adjMatrix[start][i];/*初始等于该顶点到全部顶点的权重(包括不存在边的为正无穷)*/ } flag[start] = true;/*把开始顶点标记*/ int k = 0; for (int i = 0; i < numVertices; i++) { Double min = Double.POSITIVE_INFINITY; for (int j = 0; j < numVertices; j++) { //若是为标记,而且该索引值下存在权重(也就是存在边) if (flag[j] == false && dist[j] < min && dist[j] != -1 && dist[j] != 0) { min = dist[j];/*最小值就为该权重*/ k = j;/*让k等于该索引值*/ } } flag[k] = true;/*标记该索引值的顶点*/ /*找k索引值的剩下权重是否存在,若是有找到最小的添加到min里,若是没有一直+0*/ for (int j = 0; j < numVertices; j++) { if (adjMatrix[k][j] != -1&&dist[j]!= -1) { double temp = (adjMatrix[k][j] == Double.POSITIVE_INFINITY ? Double.POSITIVE_INFINITY : (min + adjMatrix[k][j])); //若是j未标记而且temp小于权重组中原有值,则让权重组j为索引的位置为temp if (flag[j] == false && (temp < dist[j])) { dist[j] = temp; } } } } return dist[end]; }
24540数组
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 0/0 | 1/1 | 2/2 | |
第二周 | 1010/1010 | 1/2 | 10/12 | |
第三周 | 651/1661 | 1/3 | 13/25 | |
第四周 | 2205/3866 | 1/4 | 15/40 | |
第五周 | 967/4833 | 2/6 | 22/62 | |
第六周 | 1680/6513 | 1/7 | 34/96 | |
第七周 | 2196/8709 | 1/8 | 35/131 | |
第八周 | 1952/10661 | 2/9 | 49/180 | |
第九周 | 2100/24540 | 1/10 | 40/131 |
计划学习时间:30小时网络
实际学习时间:40小时数据结构
改进状况:图的概念很好理解,可是实现很难!学习