5.6 拓扑排序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5.6 拓扑排序相关的知识,希望对你有一定的参考价值。
参考技术A 拓扑排序就是将有向无环图(不存在回路的AOV网)的顶点以特定的先后次序排序,所谓特定的先后次序排序是使得所有有向边<u,v>的两个顶点在序列中都遵顼u在v前面。(注:之所以是无环,是因为,环存在的话,有些顶点无法分先后)
举个例子
这个图的拓扑排序是,ABCD或ACBD,拓扑排序的结果可能是多种的。
但如果AOV图有环,拓扑序列是不存在的。所以,拓扑排序可以用来判断AOV图是否存在环。
本质是减治法,步骤是
按这个次序输出的就是拓扑序列了。
与dfs算法本身有一定的区别,是通过dfs算法的顺序去遍历顶点,但是输出拓扑排序的时候是需要新的顺序的。
dfs的顺序,第一个顶点,第一个顶点的其中一个邻顶点,然后是不断的访问下一个邻顶点,直到没有之后,返回第一个顶点,访问其未访问过的邻顶点。
显然,这样是不符合拓扑排序的顺序的,所以,我们在使用dfs进行拓扑排序的时候,进行了修改。
此时的顺序是,dfs访问顺序,但是其访问的第一个结点是最深的结点,接着是最深结点的上一个结点,一直到第一个结点,不访问第一个结点,而是进而向第一个结点的未被访问的邻结点开始访问这一方向的最深结点。直到第一个结点的所有邻结点都被访问了,在访问第一个结点。
可递归调用dfs
注:
基本排序算法(冒泡排序 选择排序 插入排序 快速排序 归并排序 基数排序 希尔排序)
冒泡排序
public static void bubbleSort(int[] arr){ int lgn = arr.length; for (int i = 0; i < lgn - 1; i++) { for (int j = 0; j < lgn - 1 - i; j++) { if(arr[j] > arr[j + 1]){ int temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp; } } } }
选择排序
public static void SelectionSort(int[] arr){ for (int i = 0; i < arr.length; i++) { for (int j = i + 1; j < arr.length ; j++) { if(arr[j] < arr[i]){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } }
插入排序
public static void insertionSort(int [] array){ for(int i = 1; i < array.length; i++){ int temp = array[i];//被标记的值或者说是当前需要插入的值 int j = i; //如果轮循值大于被标记值则往后移 while( j > 0 && temp < array[j - 1]){ array[j] = array[j - 1]; j-- ; } //将被标记值插入最终移出的空位置 array[j] = temp; } }
快速排序
public static void quikeSort(int[] arr, int low, int high) { int start = low; int end = high; int anchor = arr[low]; while (end > start) { //比较 anchor---end while (end > start && arr[end] >= anchor) { //从末尾向前寻找小于等于anchor的值 end--; } //交换位置 if (arr[end] <= anchor) { int temp = arr[end]; arr[end] = arr[start]; arr[start] = temp; } //比较start---anchor while (end > start && arr[start] <= anchor) {//从起始位置向后寻找大于等于anchor的值 start++; } //交换位置 if (arr[start] >= anchor) { int temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; } } //anchor位置确定。左边的元素值都小于anchor值,右边的值都大于anchor值,递归排序左右两侧排序 //左边元素。low---anchor值索引-1 if (start > low) { quikeSort(arr, low, start - 1); } //右边元素。从anchor值索引+1---high if (end < high) { quikeSort(arr, end + 1, high); } }
归并排序
public static void mergeSort(int[] data) { sort(data, 0, data.length - 1); } public static void sort(int[] data, int left, int right) { if (left >= right) return; // 找出中间索引 int center = (left + right) / 2; // 对左边数组进行递归 sort(data, left, center); // 对右边数组进行递归 sort(data, center + 1, right); // 合并 merge(data, left, center, right); } /** * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序 * * @param data * 数组对象 * @param left * 左数组的第一个元素的索引 * @param center * 左数组的最后一个元素的索引,center+1是右数组第一个元素的索引 * @param right * 右数组最后一个元素的索引 */ public static void merge(int[] data, int left, int center, int right) { // 临时数组 int[] tmpArr = new int[data.length]; // 右数组第一个元素索引 int mid = center + 1; // third 记录临时数组的索引 int third = left; // 缓存左数组第一个元素的索引 int tmp = left; while (left <= center && mid <= right) { // 从两个数组中取出最小的放入临时数组 if (data[left] <= data[mid]) { tmpArr[third++] = data[left++]; } else { tmpArr[third++] = data[mid++]; } } // 剩余部分依次放入临时数组(实际上两个while只会执行其中一个) while (mid <= right) { tmpArr[third++] = data[mid++]; } while (left <= center) { tmpArr[third++] = data[left++]; } // 将临时数组中的内容拷贝回原数组中 // (原left-right范围的内容被复制回原数组) while (tmp <= right) { data[tmp] = tmpArr[tmp++]; } }
基数排序
//LSD public static void radixLSDSort(int[] arr){ //最高位数 int maxBit = getMaxBit(arr); //十个bulk 分别存放 每个位数 数字 相应的元素 如个位为3 则放入bulk[3] Queue<Integer>[] bulk = new Queue[10]; for (int i = 0; i < bulk.length; i++) { bulk[i] = new ArrayDeque(); } //分别处理不同位数 存放 处理 for (int i = 0; i < maxBit; i++) { for (int j = 0; j < arr.length; j++) { int ivalue = (int) (arr[j] % Math.pow(10, i + 1) / Math.pow(10, i)); //去相应位数上的数字作为 存入bulk index bulk[ivalue].offer(arr[j]); } //取出bulk中的元素 重新放入数组 并清除bulk中的元素。 int arrIndex = 0; for (int j = 0; j < bulk.length; j++) { while (bulk[j].size()>0){ arr[arrIndex++] = bulk[j].poll(); } } } } public static int getMaxBit(int[] arr){ int max = arr[0]; for (int i = 1; i < arr.length; i++) { if(arr[i] > max){ max = arr[i]; } } int b = 0; while (max > 0){ max /= 10; b++; } return b; } public static void radixMSDSort(int[] arr){ msdSort(arr, 0, arr.length, getMaxBit(arr)); } //MSD public static void msdSort(int[] arr, int left, int right, int maxBit){ //十个bulk 分别存放 每个位数 数字 相应的元素 如个位为3 则放入bulk[3] Queue<Integer>[] bulk = new Queue[10]; for (int i = 0; i < bulk.length; i++) { bulk[i] = new ArrayDeque(); } //依据最高位分别放入不同的bulk for (int j = left; j < right; j++) { int ivalue = (int) (arr[j] % Math.pow(10, maxBit) / Math.pow(10, maxBit - 1)); //去相应位数上的数字作为 存入bulk index bulk[ivalue].offer(arr[j]); } //取出bulk中的元素 重新放入数组 并清除bulk中的元素。记录bulk中queue大小大于1的数组索引 递归使用 List<Integer> count = new ArrayList<Integer>(); int arrIndex = left; for (int j = 0; j < bulk.length; j++) { int start = arrIndex; while (bulk[j].size()>0){ arr[arrIndex++] = bulk[j].poll(); } if(arrIndex - start > 1){ count.add(start); count.add(arrIndex); } } //递归最小位判断 int nextBit = maxBit - 1; if(nextBit > 0) { for (int i = 1; i < count.size(); i += 2) { msdSort(arr, count.get(i - 1), count.get(i), nextBit); } } }
shell排序
public static void shellSort(int[] arr){ int step = arr.length/2; while (step >= 1) { //步长为1时 包含所有数组序列 for (int i = 0; i < step; i++) { //步长为n则数组将分为n组分别排序 for (int j = step + i; j < arr.length; j += step) { //对跨步长每组元素进行插入排序 int temp = arr[j]; int preIndex = j - step; while (preIndex > -1 && temp < arr[preIndex]) { arr[preIndex + step] = arr[preIndex]; preIndex -= step; } arr[preIndex + step] = temp; System.out.println(" middle: " + Arrays.toString(arr)); } } step /= 2; //每次步长处理 } }
以上是关于5.6 拓扑排序的主要内容,如果未能解决你的问题,请参考以下文章