七种排序的实现
2016-07-20 21:52
239 查看
冒泡排序
选择排序
快速排序
归并排序
插入排序
希尔排序
堆排序
空间复杂度:O(1)
稳定排序
原理:从第一个元素开始,依次比较相邻两个元素,如果前者比后者大,那么就交换者两个元素,然后处理下一组,依次类推,直到排序完成。
实现:
空间复杂度:O(1)
不是稳定排序
原理:从第一个元素开始,每次逐一扫描选择未排序部分的最小值,排在已排序部分后面,然后从下一个位置开始,继续进行相同的操作,直到排序完成。
实现:
空间复杂度:平均情况O(logn),最坏情况O(n)
不是稳定排序
原理:每次选择一个数,将数组按照这个数分成左右两个部分,右边的比它大,左边的比他小然后对左右两部分分别进行同样的操作,直到数组排序完成
实现:
空间复杂度:O(n)
稳定排序
原理:首选将要排序的数组对半分,对各自部分进行排序。每部分继续进行相同的操作,直至最底层。然后合并两个相邻的部分,直到所有元素都排序完成
实现:
空间复杂度:O(1)
稳定排序
原理:从数组第一个元素开始,依次比较前面已经排序的部分,插入合适的位置,前面排序部分比当前值大的部分向后移动一个。
实现:
空间复杂度:O(1)
不是稳定排序
原理:将无序数组分割为若干个子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,对各个子序列进行插入排序;然后再选择一个更小的增量,再将数组分割为多个子序列进行排序……最后选择增量为1,即使用直接插入排序,使最终数组成为有序。
实现:
空间复杂度:O(1)
不是稳定排序
原理:建立初始堆,从最后一个非叶结点开始,往前遍历,判断以该节点的开始的堆是否是符合,不符合则调整需要建立大顶堆,每次将子节点中较大地一个数往上移动,直到叶结点(堆:结点n的父节点为(n-1)/ 2,其左右子节点为2*n+1和2*n+2大根堆为根结点的值大于等于左右子结点的值),然后依次将堆顶值与为排序的最后一个值交换,然后调整前面的值为大顶堆,每次将最大的值排好序。
实现:
选择排序
快速排序
归并排序
插入排序
希尔排序
堆排序
1. 冒泡排序
时间复杂度:最好O(n),平均和最坏情况O(n2)空间复杂度:O(1)
稳定排序
原理:从第一个元素开始,依次比较相邻两个元素,如果前者比后者大,那么就交换者两个元素,然后处理下一组,依次类推,直到排序完成。
实现:
public void bubbleSort(int[] arr){ boolean isChanged = false; for(int i = 0; i < arr.length - 1; i++){ isChanged = false; for(int j = 0; j < arr.length - 1 - i; j++){ if(arr[j] > arr[j+1]){ int tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp; isChanged = true; } } if(!isChanged) break; //本次没有发生交换,说明已经排好序了 } }
2. 选择排序
时间复杂度:最好、平均和最坏情况O(n2)空间复杂度:O(1)
不是稳定排序
原理:从第一个元素开始,每次逐一扫描选择未排序部分的最小值,排在已排序部分后面,然后从下一个位置开始,继续进行相同的操作,直到排序完成。
实现:
/** * 选择排序 */ public static void sort(int[] arr){ //判断arr是否为空 if(arr == null) return; int minIndex; for(int i = 0; i < arr.length - 1; i++){ minIndex = i; for (int j = i + 1; j < arr.length; j++){ if (arr[j] < arr[minIndex]){ minIndex = j; } } if (minIndex != i){ //最小值不是当前值,需要交换 int tmp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = tmp; } } }
3. 快速排序
时间复杂度:最好、平均情况O(nlogn),最坏情况O(n2)空间复杂度:平均情况O(logn),最坏情况O(n)
不是稳定排序
原理:每次选择一个数,将数组按照这个数分成左右两个部分,右边的比它大,左边的比他小然后对左右两部分分别进行同样的操作,直到数组排序完成
实现:
public static void sort(int[] arr){ sortCore(arr, 0, arr.length - 1); } /** * @param arr 排序的数组 * @param start 开始位置 * @param end 结束位置 */ private static void sortCore(int[] arr, int start, int end) { int poiv = partion(arr, start, end); if (poiv > start){ sortCore(arr, start, poiv - 1); } if (poiv >= start && poiv < end){ sortCore(arr, poiv + 1, end); } } private static int partion(int[] arr, int start, int end) { int tmp = arr[start]; while (start < end){ while (start < end && arr[end] >= tmp) end--; if (start < end) { arr[start] = arr[end]; } while (start < end && arr[start] < tmp) start++; if (start < end){ arr[end] = arr[start]; } } arr[start] = tmp; return start; }
4. 归并排序
时间复杂度:最好、平均和最坏情况O(nlogn)空间复杂度:O(n)
稳定排序
原理:首选将要排序的数组对半分,对各自部分进行排序。每部分继续进行相同的操作,直至最底层。然后合并两个相邻的部分,直到所有元素都排序完成
实现:
public static void sort(int[] arr){ //创建数组,辅助排序 int[] copy = new int[arr.length]; sortCore(arr, copy, 0, arr.length - 1); } /** * 归并排序核心实现 * @param arr 排序的数组 * @param copy 辅助空间 * @param start 开始位置 * @param end 结束位置 * @param offset 索引相对于原数组的偏移 */ private static void sortCore(int[] arr, int[] copy, int start, int end) { if (start == end) { copy[start] = arr[start]; return; } int mid = (end - start) / 2 + start; //分成两部分,递归 sortCore(arr, copy, start, mid); sortCore(arr, copy, mid + 1, end); //合并两个部分,将合并结果存入 int forward = mid; int behand = end; int last = end; while (forward >= start && behand > mid){ if (copy[forward] > copy[behand]){ arr[last --] = copy[forward --]; }else { arr[last --] = copy[behand --]; } } while (forward >= start){ arr[last --] = copy[forward --]; } while (behand > mid){ arr[last --] = copy[behand --]; } //拷贝到copy数组 for (int i = start; i <= end; i++){ copy[i] = arr[i]; } }
5. 插入排序
时间复杂度:最好O(n),平均和最外情况O(n2)空间复杂度:O(1)
稳定排序
原理:从数组第一个元素开始,依次比较前面已经排序的部分,插入合适的位置,前面排序部分比当前值大的部分向后移动一个。
实现:
public static void sort(int[] arr){ int tmp; //每次排序,存储当前的值 for(int i = 1; i < arr.length; i++){ tmp = arr[i]; //保存当前值 int j; for (j = i; j >= fromIndex && tmp < arr[j - 1]; j --){ //遇到比当前值大的元素,则元素后移一位 arr[j] = arr[j-1]; } arr[j] = tmp; | } }
6. 希尔排序
时间复杂度:平均情况O(n1.25)空间复杂度:O(1)
不是稳定排序
原理:将无序数组分割为若干个子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,对各个子序列进行插入排序;然后再选择一个更小的增量,再将数组分割为多个子序列进行排序……最后选择增量为1,即使用直接插入排序,使最终数组成为有序。
实现:
public static void sort(int[] arr){ //checkRange(arr.length, fromIndex, toIndex); int adder = arr.length / 2; //增量 while (adder > 0){ //从adder开始,每次排序均与前面的adder(当adder是1时就是插入排序)处的元素比较 for (int i = adder ; i < arr.length; i++){ int j; int tmp = arr[i]; for (j = i; j >= adder && tmp < arr[j - adder]; j = j - adder){ arr[j] = arr[j - adder]; } arr[j] = tmp; } adder /= 2; } }
7. 堆排序
时间复杂度:最好、平均和最坏情况均为O(nlogn)空间复杂度:O(1)
不是稳定排序
原理:建立初始堆,从最后一个非叶结点开始,往前遍历,判断以该节点的开始的堆是否是符合,不符合则调整需要建立大顶堆,每次将子节点中较大地一个数往上移动,直到叶结点(堆:结点n的父节点为(n-1)/ 2,其左右子节点为2*n+1和2*n+2大根堆为根结点的值大于等于左右子结点的值),然后依次将堆顶值与为排序的最后一个值交换,然后调整前面的值为大顶堆,每次将最大的值排好序。
实现:
/** * 堆排序 */ public static void sort(int[] arr){ //建立初始堆,从最后一个非叶结点开始,往前遍历,判断以该节点的开始的堆是否是符合,不符合则调整 //需要建立大顶堆,每次将子节点中较大地一个数往上移动,直到叶结点 //节点n的父节点为(n-1)/ 2,其左右子节点为2*n+1和2*n+2 //大根堆为根结点的值大于等于左右子结点的值 for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--){ adjustHeap(arr, i, arr.length-1); } //依次将堆顶值与为排序的最后一个值交换,然后调整前面的值为大顶堆 for (int i = arr.length - 1; i >= 1; i--){ //交换 arr[0] ^= arr[i]; arr[i] ^= arr[0]; arr[0] ^= arr[i]; //调整 adjustHeap(arr, 0, i - 1); } } /** * 调整为大顶堆 * @param arr * @param i 以i为堆的堆顶 * @param last 堆顶的最后一个结点的索引 */ private static void adjustHeap(int[] arr, int i, int last) { //建立以i结点为根的堆,判断子结点是否大于该节点,并将较大地值拷贝,然后继续判断 int tmp = arr[i]; for (int j = i * 2 + 1; j <= last; j = j * 2 + 1){ //获得左右子树中较大的一个数的下标 if (j < last && arr[j] < arr[j+1]) j++; //存在右子结点且右子结点较大 if (tmp >= arr[j]) break; //根结点比较大,则完成 //将较大的值作为根 arr[i] = arr[j]; i = j; //继续往下判断,j的位置的值是最初的根结点 } arr[i] = tmp; //最后确定的位置,没有子结点或者比子结点的值大; }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 在命令行用 sort 进行排序
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序