排序
来源:互联网 发布:泰迪罗宾地位知乎 编辑:程序博客网 时间:2024/06/07 05:46
package sort;/** * 插入排序 * 1)直接插入排序 * 2)折半插入排序 * 3)希尔排序 * * 选择排序 * 1)简单选择排序 * 2)堆排序 * * 交换排序 * 1)起泡排序 * 2)快速排序 * * 归并排序 */public class sorts { /** * 直接插入排序 稳定排序 * 空间复杂度:o(1) * 时间复杂度: * 最坏情况: o(n^2) * 最好情况: o(n) * 平均情况: o(n^2) * @param data 待排数据数组 */ public static void InsertSort(int[] data){ for(int i = 1; i < data.length; i++){//数组下标从0开始,第一个元素有序,所以从第二个开始处理 int tmp = data[i];//用来临时存放待排元素 int j = i - 1;//标记开始比较的位置 //完成了从待排元素之前的元素开始扫描,如果大于待排元素,则后移一位 while(j >= 0 && tmp < data[j]){ data[j+1] = data[j]; --j; } data[j+1] = tmp;//找到插入位置,将tmp中暂存的待排元素插入 } } /** * 折半插入排序 稳定排序 折半查找法的基本要求是序列已经基本有序 * 空间复杂度:o(1) * 时间复杂度: * 最坏情况: o(n^2) * 最好情况: o(n) * 平均情况: o(n^2) * @param data 待排数据数组 */ public static void binaryInsertSort(int[] data){ for(int i = 1; i < data.length; i++){//数组下标从0开始,第一个元素有序,所以从第二个开始处理 int tmp = data[i]; int low = 0; int high = i - 1; while(low <= high){//当low > high 折半查找结束 int mid = (low + high) / 2; if(tmp < data[mid]){ high = mid - 1; // 插入点在低半区 }else{ //关键字相同时,使low = mid + 1,到高半区,保证稳定性 low = mid + 1;// 插入点在高半区 } } //依次向后移动记录 for(int t = i-1; t > high; t--){// 记录后移 data[t+1] = data[t]; } data[high+1] = tmp; // 插入 } } /** * 冒泡(起泡)排序 稳定排序 * 空间复杂度:o(1) tmp * 时间复杂度: * 最坏情况: o(n^2) * 最好情况: o(n) * 平均情况: o(n^2) * @param data 待排数据数组 */ public static void BubbleSort(int[] data){ int n = data.length; for(int k = 0; k < n-1; k++){//进行(n-1)趟冒泡 boolean flag = false;//变量flag用来标记本趟排序是否发生交换 for(int i = 1; i < n-k; i++){ if(data[i-1] > data[i]){ int tmp = data[i]; data[i] = data[i-1]; data[i-1] = tmp; flag = true;//如果没发生交换,则flag为false,否则为true } } if(!flag){ return; } } } /** * 快速排序 对从data[l]到data[r]的元素进行排序 通常都选取第一个元素作为枢纽 * 空间复杂度:o(logn) 快速排序是递归进行的, 递归需要栈的辅助 * 时间复杂度: * 最坏情况: o(n^2) * 最好情况: o(nlogn) * 平均情况: o(nlogn) 就平均时间而言,快速排序是所有排序算法中最好的 快速排序的排序趟数和初始序列有关 * @param data 待排数据数组 * @param l 待排数据数组起始位置 * @param r 待排数据数组终止位置 */ public static void QuickSort(int[] data, int l, int r){ int i = l; int j = r; if(l < r){//l >= r 相当于递归终止条件 int tmp = data[l]; //下面这个循环完成了一趟排序,即将数组中小于等于tmp的元素放在左边,大于等于tmp的元素放在右边 while(i != j){ while(j>i&&data[j]>=tmp) --j;//从右到左扫描找到一个小于tmp的元素 if(i<j){ data[i] = data[j]; i++; } while(j>i&&data[i]<=tmp) i++; if(i<j){ data[j] = data[i]; j--; } } data[i] = tmp; QuickSort(data, l, i-1);//递归地对tmp左边元素进行排序 QuickSort(data, i+1, r);//递归地对tmp右边元素进行排序 } } /** * 简单选择排序 从头到尾顺序扫描序列,找出最小的一个记录,和第一个记录交换,接着从剩下的记录中继续这种选择和交换,最终使序列有序 * 空间复杂度:o(1) tmp * 时间复杂度:o(n^2) * @param data 待排数据数组 */ public static void SelectSort(int[] data, int n){ for(int i = 0; i < (n-1); i++){ int k = i;//k用来记录最小值的位置 for(int j = i + 1; j < n; j++){ if(data[j] < data[k]){ k = j; } } if(k != i){ int tmp = data[k]; data[k] = data[i]; data[i] = tmp; } } }}
快排划分函数非常重要:可以用来求第k大的数,前k小个数(剑指offer面试题40),数组中出现次数超过数组长度一半的数字(剑指offer面试题39)
public static void Partition(int[] data, int start, int end){int i = start;int j = end;int tmp = data[i];if (data == null || data.length <= 0 || start <0 || end >= data.length ) {return ;}while(i != j) {while (i < j && data[j] >= tmp) --j;//从右到左依次遍历找到小于tmp的元素if (i < j){data[i] = data[j];i++;} while (i < j && data[i] <= tmp) i++;//从左到右依次遍历找到大于tmp的元素if (i < j){data[j] = data[i];j--;}}data[i] = tmp;}
与直接插入排序相比,折半插入排序寻找插入位置上面所花的时间大大减少。折半插入排序在记录移动次数方面和直接插入排序是一样的,所以时间复杂度和直接插入排序还是一样的。
希尔排序:
又叫做缩小增量排序,其本质是插入排序,只不过是将待排序的序列按某种规则分成几个子序列,分别对这几个子序列进行直接插入排序。
希尔排序是不稳定的排序
空间复杂度:o(1)
平均情况下时间复杂度: o(nlogn)
注意:希尔排序的增量取法要注意,首先增量序列的最后一个值一定是1; 其次增量序列中的值没有除1之外的公因子,如8、4、2、1这样的序列就不要取(8、4、2有公共因子2)
堆排序:
堆排序是不稳定的。可以把堆看成一棵完全二叉树,这棵完全二叉树满足:任何一个非叶子结点的值都不大于(或不小于)其左右孩子结点的值。若父亲大孩子节点,则这样的堆叫做大顶堆,反之叫小顶堆。
从无序序列所确定的完全二叉树的第一个非叶子节点,开始从右到左,从下到上,对每个非叶子节点进行调整,最终得到一个大顶堆。
对结点调整方法:
1) 将当前结点(假设为a)的值与其孩子结点进行比较,如果存在大于a值的孩子结点,则从中选出最大的一个与a交换。当a来到下一层的时候重复以上过程,直到a的孩子结点值都小于a的值为止。
2) 将当前无序序列中第一个元素,反映在树中是根结点(假设为a)与无序序列中最后一个元素交换(假设为b)。a进入有序序列,到达最终位置,无序序列中的元素减少1个,有序序列中元素增加1个。此时只有结点b可能不满足堆的定义,对其调整
3) 重复2)过程,直到无序序列中的元素剩下1个时排序结束。
适用范围:
记录数很多的情况,典型的例子是从10000个记录中选出前10个最小的。
这幅图归并排序的空间复杂度为O(n)
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- C#可访问性不一致
- web.xml中load-on-startup的作用
- leetcode 116/117 Populating Next Right Pointers in Each Node 1/2
- 129_sumRoottoLeafNumbers
- JMS 之 Active MQ的安全机制
- 排序
- uboot的eMMC初始化代码流程分析
- 当类的属性被static final修饰时需要注意的问题
- 什么是 JWT -- JSON WEB TOKEN
- Java多线程
- 1180:5个数求最值
- Selector 实现原理
- OPNET网络仿真分析-1.1.1、网络仿真简介
- 【云周刊】第139期:阿里年会黑科技全揭秘:IoT手环、人脸识别验票、大屏弹幕互动等“十八般武艺”轮番上阵