排序
1. 冒泡排序
时间复杂度:最好O(n),平均和最坏情况O(n2)
空间复杂度:O(1)
稳定排序
原理:从第一个元素开始,依次比较相邻两个元素,如果前者比后者大,那么就交换者两个元素,然后处理下一组,依次类推,直到排序完成。
实现:
publicvoid 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)
不是稳定排序
原理:从第一个元素开始,每次逐一扫描选择未排序部分的最小值,排在已排序部分后面,然后从下一个位置开始,继续进行相同的操作,直到排序完成。
实现:
/*** 选择排序*/publicstaticvoid 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)
不是稳定排序
原理:每次选择一个数,将数组按照这个数分成左右两个部分,右边的比它大,左边的比他小然后对左右两部分分别进行同样的操作,直到数组排序完成
实现:
publicstaticvoid sort(int[] arr){sortCore(arr,0, arr.length -1);}/*** @param arr 排序的数组* @param start 开始位置* @param end 结束位置*/privatestaticvoid sortCore(int[] arr,int start,intend){int poiv = partion(arr, start,end);if(poiv > start){sortCore(arr, start, poiv -1);}if(poiv >= start && poiv <end){sortCore(arr, poiv +1,end);}}privatestaticint partion(int[] arr,int start,intend){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)
稳定排序
原理:首选将要排序的数组对半分,对各自部分进行排序。每部分继续进行相同的操作,直至最底层。然后合并两个相邻的部分,直到所有元素都排序完成
实现:
publicstaticvoid sort(int[] arr){//创建数组,辅助排序int[] copy =newint[arr.length];sortCore(arr, copy,0, arr.length -1);}/*** 归并排序核心实现* @param arr 排序的数组* @param copy 辅助空间* @param start 开始位置* @param end 结束位置* @param offset 索引相对于原数组的偏移*/privatestaticvoid sortCore(int[] arr,int[] copy,int start,intend){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;intlast=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)
稳定排序
原理:从数组第一个元素开始,依次比较前面已经排序的部分,插入合适的位置,前面排序部分比当前值大的部分向后移动一个。
实现:
publicstaticvoid 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,即使用直接插入排序,使最终数组成为有序。
实现:
publicstaticvoid 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,其左右子节点为2n+1和2n+2大根堆为根结点的值大于等于左右子结点的值),然后依次将堆顶值与为排序的最后一个值交换,然后调整前面的值为大顶堆,每次将最大的值排好序。
实现:
/*** 堆排序*/publicstaticvoid 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 堆顶的最后一个结点的索引*/privatestaticvoid adjustHeap(int[] arr,int i,intlast){//建立以i结点为根的堆,判断子结点是否大于该节点,并将较大地值拷贝,然后继续判断int tmp = arr[i];for(int j = i *2; j <=last; j *=2){//获得左右子树中较大的一个数的下标if(j <last&& arr[j]< arr[j+1]) j++;//存在右子结点且右子结点较大if(tmp >= arr[j])break;//根结点比较大,则完成//将较大的值作为根arr[i]= arr[j];i = j;//继续往下判断,j的位置的值是最初的根结点}arr[i]= tmp;//最后确定的位置,没有子结点或者比子结点的值大;}

浙公网安备 33010602011771号