摘要:上篇笔记记述了四个排序:插入排序、快速排序、冒泡排序、选择排序、本篇主要记录两个:shell排序——对插入排序的改进、归并排序。同样是从思想、算法实现和java代码的实现来研究、顺道补充了点递归的东西。
Shell排序(希尔排序)是对插入排序的一种改进、也称“缩小增量排序”。他是按照一个选取的缩小增量值n将要排序的数组中元素下标相差n和n的倍数的所有元素分成n组、分别对n组元素进行插入排序、完成后按上述规则再细分n1组、n1<n、再排序、直到nx = 1、直接对这一组进行插入排序、实现Shell排序、从上边的步骤也可以看出Shell排序是对插入排序的一种改进。
a) 取数组长度的一半step=a.length/2 作为缩小增量、
b) 将数组分成 step组、
c)分别对每组进行插入排序。
d) 将step组中每组再以缩小增量step = step/2分组、重复步骤c。
e) 重复步骤c、d直到step=1、对这一组元素进行插入排序。over!
package com.chy.arithmetic; import java.util.Arrays; public class ShellSort { private static int ia[] = { 1, 54, 6, 3, 78, 34, 12, 45, 56, 3 }; private static int[] shellSort(int[] a) { //the increment; int step = a.length / 2; // The result has mostly sorted at the previous step of step=1; //Just change the condition step> = 1 to step > 1 if you want to observe it ; while (step >= 1) { for (int i = step; i < a.length; i++) { int temp = a[i]; int j; // use insert sort to sort the part of a; for (j = i - step; j >= 0 && a[j] > temp; j -= step) { a[j + step] = a[j]; } a[j + step] = temp; } //narrow the increment. step = step / 2; } return a; } public static void main(String[] args) { System.out.println(Arrays.toString(shellSort(ia))); } }
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列(一般分解到原子级),再把有序的子序列合并为整体有序序列。
a) 申请两个空间、分别存放原来序列的一半(不是严格意义上的一半、如果元素个数是奇数、则有一方会多一个元素)。
b) 使用中间变量 center= a.length/2划分序列
c) 分别填充第一步申请的两个空间
d) 递归的形式细分填充上一步划分的两个空间、直到所有空间只放一个元素。
e) 进行归并操作
f) 重复上述步骤、直到所有空间合并成一个有序序列。
a)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
b)设定两个指针,最初位置分别为两个已经排序序列的起始位置
c)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指
d)针到下一位置
e)重复步骤3直到某一指针达到序列尾
f)将另一序列剩下的所有元素直接复制到合并序列尾
package com.chy.arithmetic; import java.util.Arrays; public class MergeSort { public static void main(String[] args) { int[] array = { 3, 2, 1, 8, 5, 7, 9, 4, 6 }; System.out.println(Arrays.toString(mergeSort(array))); } private static int[] mergeSort(int[] a) { if (a.length == 1) { return a; } int[] aL = new int[a.length / 2]; int[] aR = new int[a.length - a.length / 2]; int center = a.length / 2; for (int i = 0; i < center; i++) { aL[i] = a[i]; } for (int i = center, j = 0; i < a.length; i++, j++) { aR[j] = a[i]; } int[] sortedAL = mergeSort(aL); int[] sortedAR = mergeSort(aR); int[] as = mergeTwoArray(sortedAL, sortedAR); return as; } private static int[] mergeTwoArray(int[] aL, int[] aR) { int i = 0; int j = 0; int[] a = new int[aL.length + aR.length]; int foot = 0; while (i < aL.length && j < aR.length) { if (aL[i] < aR[j]) { a[foot++] = aL[i++]; } else { a[foot++] = aR[j++]; } } if (i == aL.length) { while (j < aR.length) { a[foot++] = aR[j++]; } } else { while (i < aL.length) { a[foot++] = aL[i++]; } } return a; } }
递归在开发中是非常常见的一种算法、比如罗列某个指定文件夹下所有的文件名、因为有可能有层层文件、所以我们可以使用递归来实现。
思想:对于一个复杂的问题,把原问题分解为若干个相对简单类同的子问题,继续下去直到子问题简单到能够直接求解,也就是说到了递推的出口,这样原问题就有递推得解。
最能说明递归思想的是:Febonacci数列——看代码。
递归最重要的是1、范围要越来越小。2、是要找到出口、也就是结束条件。
package com.chy.arithmetic; import java.io.File; public class RecursiveAlgorithm { public static void main(String[] args) { System.out.println(getFibonacciValue(10)); getAllFiles("D:\\upload"); } /** * to obtain the specified index of a Fibonacci's value */ private static long getFibonacciValue(int index) { if (index == 1 || index == 2) { return 1; } else { return getFibonacciValue(index - 1) + getFibonacciValue(index - 2); } } /** * to obtain all files in a specified directory */ private static void getAllFiles(String filePath){ File file = new File(filePath); if(!file.isDirectory()){ System.out.println(file.getAbsolutePath()); }else{ File[] fileList = file.listFiles(); for(File fileDetail : fileList){ if(!fileDetail.isDirectory()){ System.out.println(fileDetail.getAbsolutePath()); }else{ getAllFiles(fileDetail.getAbsolutePath()); } } } } }