冒泡排序是一种简单的排序算法。它重复的访问要排序的数列,一次进行两个元素的比较操作,如果他们的顺序与预期想法不同则进行元素之间的交换过程。重复进行元素之间的比较操作直到元素不再需要交换,继而该排序过程已经完成。
public static void bubbleSort(int[] array){ if(array==null||array.length==0){ return; } for(int i =0;i<array.length-1;i++){ for(int j =0;j<array.length-1-i;j++){ if(array[j]>array[j+1]){ int tmp=array[j]; array[j]=array[j+1]; array[j+1]=tmp; } } } }
上述代码存在重复比较的情况,尤其是若后序排列均为正常排列时,还是会重复比较,所以为了减少这一情况对上述代码进行优化。
public static void optimizedBubbleSort(int[] array){ if(array==null||array.length==0){ return; } //设置标记,如果后续排列均为正常正常排列,则无需继续进行冒泡 boolean nextSort=true; for(int i=0;i<array.length-1&&nextSort;i++){ nextSort=false; for (int j =0;j<array.length-1-i;j++){ if(array[j]>array[j+1]){ int tmp=array[j]; array[j]=array[j+1]; array[j+1]=tmp; nextSort=true; } } } }
选择排序的特点:选择排序是不稳定的排序算法,因为无论对什么数据进行排序都是 O(n^2)的时间复杂度,因为选择排序的时间复杂度比较大,所以当使用选择排序的时候,数据规模越小越好。
public static void selectSort(int []array){ if(array==null||array.length==0){ return; } for(int i=0;i<array.length;i++){ int minIndex=i; for(int j=i+1;j<array.length;j++){ if(array[j]<array[minIndex]){ minIndex=j; } } //minIndex是元素最小的下标 if(minIndex!=i){ int tmp=array[i]; array[i]=array[minIndex]; array[minIndex]=tmp; } } }
优化:在每一次寻找元素的过程中,直接寻找两个元素,即待排序序列中的最大元素和最小元素。
public static void optimizedSelectSort(int[]array){ if(array==null||array.length==0){ return; } for(int i=0;i<array.length/2;i++){ int minIndex=i; int maxIndex=i; for(int j=i+1;j<array.length-1-i;j++){ if(array[j]<array[minIndex]){ minIndex=j; continue; } if(array[j]>array[maxIndex]){ maxIndex=j; } } int tmp=array[i]; array[i]=array[minIndex]; array[minIndex]=tmp; //判断maxIndex的值是否就是i if(maxIndex==i){ maxIndex=minIndex; } tmp=array[maxIndex]; array[maxIndex]=array[array.length-1-i]; array[array.length-1-i]=tmp; } }
插入排序的算法是通过构建有序序列,对于未排序的数据,在已排序的序列中从后向前进行查找操作,找到满足条件的元 素之后进行位置插入操作。
public static void insertSort(int []array){ if(array==null||array.length==0){ return; } for(int i=0;i<array.length;i++){ int tmp=array[i];//拿到的元素 int j=i; while(j>0&&tmp<array[j-1]){ array[j]=array[j-1]; j--; } array[j]=tmp; } }
堆是一棵顺序存储的完全二叉树。完全二叉树中所有非终端节点的值均不大于(或不小于)其左、右孩子节点的值。其中 每个节点的值小于等于其左、右孩子的值,这样的堆称为小根堆;其中每个节点的值大于等于其左、右孩子的值,这样的堆称 为大根堆;
堆排序是指利用堆这种数据结构进行设计的一种排序算法。堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小) 这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
用大根堆排序的基本思想:
private static <T>void swap(T[] arr,int index1,int index2){ T temp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = temp; } private static <T extends Comparable<T>>void adjust(T[] arr,int start,int end){ T temp=arr[start]; for(int i=2*start+1;i<=end;i=2*i+1){ if(i+1<=end && arr[i].compareTo(arr[i+1]) < 0){ i++;//i 保存左右孩子较大值的下标 } if(temp.compareTo(arr[i]) < 0){ arr[start]=arr[i]; start=i; } else{ break; } } arr[start]=temp; } public static <T extends Comparable<T>>void heapSort(T[] arr){ int i=0; for(i=(arr.length-1-1)/2;i>=0;i--){//i 代表要调整根节点的下标 adjust(arr, i, arr.length-1);//最大堆建立好了 } for(i=0;i<arr.length;i++){ //0 下标 根保存最大值 // arr[0]和堆中相对的"最后"元素进行交换 swap(arr,0,arr.length-1-i); adjust(arr, 0, arr.length-1-i-1); } }
希尔排序也是一种插入排序,它是简单插入排序的一种算法改进方式。也成为见效增量排序,希尔排序的时间复杂度相比 直接插入排序的时间复杂度要小。他与直接插入排序的不同在于它会优先比较距离较远的元素。希尔排序是按照一定的增量进 行分组排序,对每一组进行直接插入排序,随着分组个数的减少,每组中的元素就会越来越多,当增量减少为 1 时,排序结束。
选择增量 gap=length/2;缩小增量继续以 gap=gap/2 的方式进行分组。{n/2,(n/2)/2,(n/2)/4,…,1}增量序列。
public static <T extends Comparable<T>>void shellSort(T[] arr,int gap){ int i=0,j=0; for(i=gap;i<arr.length;i++){ T temp = arr[i]; for(j=i-gap;j>=0;j-=gap){ if(temp.compareTo(arr[j]) < 0){ arr[j+gap]=arr[j]; } else{ break; } } arr[j+gap]=temp; } } public static <T extends Comparable<T>>void shell(T[] arr){ int[] partition={5,3,1}; for(int i=0;i<partition.length;i++){ shellSort(arr,partition[i]); } }
归并排序建立在归并的有效操作上进行排序,主要采用分治法将已有序的子序列合并,得到完全有序的序列。即先让每一 小段有序,再让小段之间变得有序。若将两个有序合成一个有序段,这又称为二路归并。
public static <T extends Comparable<T>>void merge(T[] arr,int len,int gap){ int low1=0;//第一个归并段的起始下标 int high1=low1+gap-1;//第一个归并段的结束下标 int low2=high1+1;//第二个归并段起始下标 int high2=low2+gap-1 > len-1?len-1:low2+gap-1; T[] brr=(T[])new Comparable[arr.length]; int i=0; while(low2 < len){//保证有两个归并段 while(low1<=high1 && low2<=high2){//两个归并段都有数据时继续判断 if(arr[low1].compareTo(arr[low2]) <= 0){ brr[i++]=arr[low1++]; } else{ brr[i++]=arr[low2++]; } } while(low1<=high1){//第一个归并段还有数据 brr[i++]=arr[low1++]; } while(low2<=high2){ brr[i++]=arr[low2++]; } low1=high2+1; high1=low1+gap-1; low2=high1+1; high2 = low2+gap-1 > len-1?len-1:low2+gap-1; } //没有两个归并段:单的直接拷贝下来 while(low1<=len-1){ brr[i++]=arr[low1++]; } for(i=0;i<arr.length;i++){ arr[i]=brr[i]; } brr=null; } public static <T extends Comparable<T>>void mergeSort(T[] arr){ for(int i=1;i<arr.length;i*=2){//2 个 2 个有序,4 个 4 个有序... merge(arr,arr.length,i); } }
快排主要是通过选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一 般是无序的)。依此递归,达到总体待排序序列都有序。
三位数取中
//随机 //中位数三位取中 public static int RandParition(int []arr,int left,int right){ Random random=new Random(); int index=random.nextInt((right-left)+1)+left; int tmp=arr[left]; arr[left]=arr[index]; arr[index]=tmp; return Parition(arr,left,right); } public static void QuickSort(int []arr){ QuickPass(arr,0,arr.length-1); } public static int Parition(int []arr,int left,int right){ int i=left,j=right; int tmp=arr[i]; while (i<j){ while (i<j&&arr[j]>tmp)--j; if(i<j)arr[i]=arr[j]; while (i<j&&arr[i]<=tmp)++i; if(i<j)arr[j]=arr[i]; } arr[i]=tmp; return i; }
非递归
public static void QuickPass(int []arr,int left,int right) { Queue<Integer> queue = new LinkedList<>(); if (left >= right) return; queue.offer(left); queue.offer(right); while (!queue.isEmpty()) { left = queue.poll(); right = queue.poll(); int pos = OWParition2(arr, left, right); if (left < pos - 1) { queue.offer(left); queue.offer((pos - 1)); } if (pos + 1 < right) { queue.offer(pos + 1); queue.offer(right); } } } public static int OWParition2(int []arr,int left,int right){ int i=left,j=left+1; int tmp=arr[i]; while (j<=right){ if(arr[j]<=tmp){ i+=1; Swap(arr,i,j); } j++; } Swap(arr,left,i); return i; } public static void Swap(int[]arr,int i,int j){ int tmp=arr[i]; arr[i]=arr[j]; arr[j]=tmp; }
递归
public static void QuickSort(int []arr){ QuickPass(arr,0,arr.length-1); } // 利用递归 public static void QuickPass(int []arr,int left,int right){ if(left<right){ int pos=Parition(arr,left,right); QuickPass(arr,left,pos-1); QuickPass(arr,pos+1,right); } } public static int Parition(int []arr,int left,int right){ int i=left,j=right; int tmp=arr[i]; while (i<j){ while (i<j&&arr[j]>tmp)--j; if(i<j)arr[i]=arr[j]; while (i<j&&arr[i]<=tmp)++i; if(i<j)arr[j]=arr[i]; } arr[i]=tmp; return i; }