标签:java算法
希尔排序
希尔排序的基本思想是:把待排序的数据元素分成若干个小组,对同一小组内的数据元素用直接插入法排序;小组的个数逐次缩小;当完成了所有数据元素都在一个组内的排序后排序过程结束。希尔排序又称作缩小增量排序。
选择步长,对每个小的分组进行的直接插入排序。
/** * 希尔排序:我们选择步长为:15,7,3,1 我们选择步长公式为:2^k-1,2^(k-1)-1,……,15,7,3,1 * (2^4-1,2^3-1,2^2-1,2^1-1) 注意所有排序都是从小到大排。 */ public class ShellSort { /** * 排序算法的实现,对数组中指定的元素进行排序 * * @param array * 待排序的数组 * @param from * 从哪里开始排序 * @param end * 排到哪里 * @param c * 比较器 */ public void sort(Integer[] array, int from, int end) { // 初始步长,实质为每轮的分组数 int step = initialStep(end - from + 1); // 第一层循环是对排序轮次进行循环。(step + 1) / 2 - 1 为下一轮步长值 for (; step >= 1; step = (step + 1) / 2 - 1) { // 对每轮里的每个分组进行循环 for (int groupIndex = 0; groupIndex < step; groupIndex++) { // 对每组进行直接插入排序 insertSort(array, groupIndex, step, end); } } } /** * 直接插入排序实现 * * @param array * 待排序数组 * @param groupIndex * 对每轮的哪一组进行排序 * @param step * 步长 * @param end * 整个数组要排哪个元素止 * @param c * 比较器 */ public void insertSort(Integer[] array, int groupIndex, int step, int end) { int startIndex = groupIndex;// 从哪里开始排序 int endIndex = startIndex;// 排到哪里 /* * 排到哪里需要计算得到,从开始排序元素开始,以step步长,可求得下元素是否在数组范围内, * 如果在数组范围内,则继续循环,直到索引超现数组范围 */ while ((endIndex + step) <= end) { endIndex += step; } // i为每小组里的第二个元素开始 for (int i = groupIndex + step; i <= end; i += step) { for (int j = groupIndex; j < i; j += step) { Integer insertedElem = array[i]; // 从有序数组中最一个元素开始查找第一个大于待插入的元素 if ((array[j].compareTo(insertedElem)) >= 0) { // 找到插入点后,从插入点开始向后所有元素后移一位 move(array, j, i - step, step); array[j] = insertedElem; break; } } } } /** * 根据数组长度求初始步长 * * 我们选择步长的公式为:2^k-1,2^(k-1)-1,...,15,7,3,1 ,其中2^k 减一即为该步长序列,k 为排序轮次 * * 初始步长:step = 2^k-1 初始步长约束条件:step < len - 1 初始步长的值要小于数组长度还要减一的值(因 * 为第一轮分组时尽量不要分为一组,除非数组本身的长度就小于等于4) * * 由上面两个关系试可以得知:2^k - 1 < len - 1 关系式,其中k为轮次,如果把 2^k 表 达式 转换成 step 表达式,则 * 2^k-1 可使用 (step + 1)*2-1 替换(因为 step+1 相当于第k-1 轮的步长,所以在 step+1 基础上乘以 2 * 就相当于 2^k 了),即步长与数组长度的关系不等式为 (step + 1)*2 - 1 < len -1 * * @param len * 数组长度 * @return */ public static int initialStep(int len) { /* * 初始值设置为步长公式中的最小步长,从最小步长推导出最长初始步长值,即按照以下公式来推: * 1,3,7,15,...,2^(k-1)-1,2^k-1 * 如果数组长度小于等于4时,步长为1,即长度小于等于4的数组不用分组,此时直接退化为直接插入排序 */ int step = 1; // 试探下一个步长是否满足条件,如果满足条件,则步长置为下一步长 while ((step + 1) * 2 - 1 < len - 1) { step = (step + 1) * 2 - 1; } System.out.println("初始步长 : " + step); return step; } /** * 以指定的步长将数组元素后移,步长指定每个元素间的间隔 * * @param array * 待排序数组 * @param startIndex * 从哪里开始移 * @param endIndex * 到哪个元素止 * @param step * 步长 */ protected final void move(Integer[] array, int startIndex, int endIndex, int step) { for (int i = endIndex; i >= startIndex; i -= step) { array[i + step] = array[i]; } } /** * 测试 * * @param args */ public static void main(String[] args) { Integer[] intgArr = { 65, 34, 25, 87, 12, 38, 56, 46, 14, 77, 92, 23 }; ShellSort shellSort = new ShellSort(); shellSort.sort(intgArr, 0, intgArr.length - 1); for (Integer intObj : intgArr) { System.out.print(intObj + " "); } } }
快速排序
快速排序的基本思想:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。把整个序列看做一个数组,把第零个位置看做中轴,和最后一个比,如果比它小交换,比它大不做任何处理;交换了以后再和小的那端比,比它小不交换,比他大交换。这样循环往复,一趟排序完成,左边就是比中轴小的,右边就是比中轴大的,然后再用分治法,分别对这两个独立的数组进行排序。
是一种快速的交换排序
自己写出的:
import java.util.Arrays; public class Test { public static void main(String[] args) { int[] array = {49,38,65,97,76,13,27,33,25,78,1,10,23,34,97}; int start = 0; int end = array.length-1; quickSort(array,start,end); System.out.println(Arrays.toString(array)); } public static void quickSort(int[] array , int head ,int bottom) { if(head==bottom) return; int start = head; int end = bottom; int pivot = array[start]; while(start<end) { if(array[start]==pivot) { for(;end>start;end--) { if(array[end]<array[start]) { int temp = array[end]; array[end] = array[start]; array[start] = temp; break; } } }else { for(;start<end;start++) { if(array[end]<array[start]) { int temp = array[end]; array[end] = array[start]; array[start] = temp; break; } } } } int middle = start; System.out.println("one lun: " + pivot + "..." + end); if(head<middle) { quickSort(array, head, middle-1); } if(bottom>middle) { quickSort(array, middle+1, bottom); } } }
参考的:
import java.util.Arrays; //快速排序算法 public class QuickSort { public static void quickSort(int arr[], int low, int high) { if(low < high) { //按照第一个数进行切分。左边放小于【0】的数,右边放大于[0]的数 int mid = partition(arr, low, high); //对关键字左边的数据进行分区 quickSort(arr, low, mid - 1); //对关键字右边的数据进行分区 quickSort(arr, mid + 1, high); } } public static int partition(int array[], int low, int high) { // 设置两个变量i、j,排序开始的时候i:=0,j:=N-1; // 以第一个数组元素作为关键数据,赋值给pivotKey,即pivotKey:=array[0]; int pivotKey = array[low]; int i= low, j = high; if(low < high) { while (i < j) { // 从J开始向前搜索,即由后开始向前搜索(J:=J-1),找到第一个小于X的值,两者交换; while (i < j && array[j] >= pivotKey) { j--; } if (i < j) { array[i] = array[j]; i++; } // 从I开始向后搜索,即由前开始向后搜索(I:=I+1),找到第一个大于X的值,两者交换; while (i < j && array[i] <= pivotKey) { i++; } if (i < j) { array[j] = array[i]; j--; } } array[i] = pivotKey; //打印每次分区后的结果 System.out.println("每次排序:" + Arrays.toString(array)); //将这个分区结束时的坐标i返回,用于下次执行时当做前分区的尾坐标,当做后分区的头坐标 } return i; } public static void main(String[] args) { int[] list={49,38,65,97,76,13,27,49}; System.out.println("排序前:" +Arrays.toString(list)); quickSort(list, 0, list.length - 1); System.out.println("排序后:" + Arrays.toString(list)); } }
堆排序
在直接选择排序中,放在数组中的n个数据元素排成一个线性序列(即线性结构),要从有n个数据元素的数组中选择出一个最小的数据元素需要比较n-1次。如果能把待排序的数据元素集合构成一个完全二叉树结构,则每次选择出一个最大(或最小)的数据元素只需比较完全二叉树的高度次,即log2n次,则排序算法的时间复杂度就是O(nlog2n)。这就是堆排序的基本思想。
最大堆的定义如下:
设数组a中存放了n个数据元素,数组下标从0开始,如果当数组下标2i+1<n时有:a[i]≥a[2i+1];如果当数组下标2i+2<n时有:a[i]≥a[2i+2],则这样的数据结构称为最大堆。
图说明见附件
//堆排序算法 public class HeapSort { //带入数组,n是最大长度额下标,h是起点 //因为初始化下已经是最大堆,头和尾交换后,只需把新的头加入到树的最小端即可,树还是保持最大堆 public static void createHeap(int[] a, int n, int h) { int i, j, flag; int temp; i = h; // i为要建堆的二叉树根结点下标 j = 2 * i + 1; // j为i结点的左孩子结点的下标 temp = a[i]; flag = 0; // 沿左右孩子中值较大者重复向下筛选 while (j < n && flag != 1) { // 寻找左右孩子结点中的较大者,j为其下标 if (j < n - 1 && a[j] < a[j + 1]) { j++; } // 标记结束筛选条件 if (temp > a[j]) flag = 1; else { // 否则把a[j]上移 a[i] = a[j]; i = j; j = 2 * i + 1; } } a[i] = temp; // 把最初的a[i]赋予最后的a[j] } //初始化数组,使其对应的二叉树是最大堆,初始化下二叉树是最大堆的情况 public static void initCreateHeap(int[] a) { int n = a.length; for (int i = (n - 1) / 2; i >= 0; i--) createHeap(a, n, i); } public static void heapSort(int[] a) { int temp; int n = a.length; initCreateHeap(a); // 初始化创建最大堆 for (int i = n - 1; i > 0; i--) { // 当前最大堆个数每次递减1 // 把堆顶a[0]元素和当前最大堆的最后一个元素交换 temp = a[0]; a[0] = a[i]; a[i] = temp; //交换后,把交换的头在向下找最大的,换上去,形成最大堆 createHeap(a, i, 0); // 调整根结点满足最大堆 } } public static void main(String[] args) { int[] test = { 10, 50, 32, 5, 76, 9, 40, 88 }; int n = test.length; heapSort(test); for (int i = 0; i < n; i++) System.out.print(test[i] + " "); } }
这是一种基于二叉树的排序。
归并排序
//归并排序算法 public class MergeSort { //归并排序算法 public static void merge(int[] a, int[] swap, int k) { int n = a.length; int m = 0, u1, l2, i, j, u2; int l1 = 0; // 第一个有序子数组下界为0 //l1为第一组最小,u1为第一组最大,l2为第二组最小,u2为第二组最大 while (l1 + k <= n - 1) { l2 = l1 + k; // 计算第二个有序子数组下界 u1 = l2 - 1; // 计算第一个有序子数组上界 u2 = (l2 + k - 1 <= n - 1) ? l2 + k - 1 : n - 1; // 计算第二个有序子数组上界 //循环找最小的插入到swap中 for (i = l1, j = l2; i <= u1 && j <= u2; m++) { if (a[i] <= a[j]) { swap[m] = a[i]; i++; } else { swap[m] = a[j]; j++; } } // 子数组2已归并完,将子数组1中剩余的元素存放到数组swap中 while (i <= u1) { swap[m] = a[i]; m++; i++; } // 子数组1已归并完,将子数组2中剩余的元素存放到数组swap中 while (j <= u2) { swap[m] = a[j]; m++; j++; } l1 = u2 + 1; } // 将原始数组中只够一组的数据元素顺序存放到数组swap中 for (i = l1; i < n; i++, m++) { swap[m] = a[i]; } } public static void mergeSort(int[] a) { int i; int n = a.length; int k = 1; // 归并长度从1开始 int[] swap = new int[n]; while (k < n) { //k是每组的长度 merge(a, swap, k); // 调用函数merge() for (i = 0; i < n; i++) { a[i] = swap[i]; // 将元素从临时数组swap放回数组a中 } //每次长度增为2倍 k = 2 * k; // 归并长度加倍 } } public static void main(String[] args) { int[] test = { 72, 73, 71, 23, 94, 16, 5, 68, 64 }; int n = test.length; mergeSort(test); for (int i = 0; i < n; i++) System.out.print(test[i] + " "); } }
基数排序
//基数排序算法 public class RadixSort{ public static void radixSort(int[] a, int m, int d) throws Exception{ //a为要排序的数据元素,d为进制的基数,m为数据元素的最大位数 int n = a.length; int i, j, k, l, power = 1; Queue<Integer>[] myQueue = new LinkedList[d]; //创建链式队列数组对象 for(i = 0; i < d; i++){ Queue<Integer> temp = new LinkedList<Integer>(); myQueue[i] = temp; } //进行m次排序 for(i = 0; i < m; i++){ if(i==0) power = 1; else power = power * d; //依次将n个数据元素按第k位的大小放到相应的队列中 for(j = 0; j < n; j++) { k = a[j] / power - (a[j] / (power * d)) * d; //计算k值 myQueue[k].add(new Integer(a[j])); // a[j]入队列k } //顺序回收各队列中的数据元素到数组a中 l = 0; for(j = 0; j < d; j++){ while(!myQueue[j].isEmpty()){ a[l] = ((Integer)myQueue[j].remove()).intValue(); l++; } } } } public static void main(String[] args){ int[] test = {710,342,45,686,6,841,429,134,68,264}; int n = test.length; int m = 3, d = 10; try{ radixSort(test, m, d); } catch (Exception e){ e.printStackTrace(); } for(int i = 0; i < n; i++) System.out.print(test[i] + " "); } }
标签:java算法
原文地址:http://wukong0716.blog.51cto.com/10442773/1694440