排序算法
介绍
排序是将一组程序,依指定的顺序进行排列的过程。
分类
![图片说明](https://uploadfiles.nowcoder.com/images/20200603/319217495_1591191208624_072774B6B658B3603E1AA7198722775C "图片标题")
分别实现
冒泡排序
冒泡排序(Bubble Sorting)的基本思想是:通过对需要排序的序列从前往后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移到后部。
优化:
因为排序的过程,各元素不断接近自己的位置,如果一轮比较下来没有进行过交换,就说明序列有序,因此在排序过程设置一个标志flag判断元素是否进行过交换。
代码实现:
import java.util.Arrays; public class BubbleSort { public static void main(String[] args) { // TODO Auto-generated method stub int arr[]= {3,9,-1,20,10}; //实例 int tmp; boolean flag=false; for(int i=0;i<arr.length-1;i++) { for(int j=0;j<arr.length-i-1;j++) { if(arr[j]>arr[j+1]) { flag=true; tmp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=tmp; } } if(flag==false) { break; }else{ flag=false; } } System.out.println(Arrays.toString(arr)); } }
选择排序
选择排序也属于内部排序,是从欲排序的数据中,按指定的规则选出某一元素,再依照规定交换位置后达到排序的目的。
思想:选择排序(select sorting)的基本思想是:第一次从arr[0]到arr[n-1]中选最小值,与arr[0]交换,第二次从arr[1]到arr[n-1]中选取最小值,与arr[1]交换,以此类推,共进行n-1轮,得到一个按排序码从小到大的有序排列。
![图片说明](https://uploadfiles.nowcoder.com/images/20200603/319217495_1591181603895_C1E97AEBCF714B35A7814DEE4E2091EB "图片标题")
代码实现:
import java.util.Arrays; public class Test { public static void main(String[] args) { // TODO Auto-generated method stub int arr[]= {3,9,-1,20,10}; //实例 for(int i=0;i<=arr.length-1;i++) { int min=arr[i]; int minIndex=i; for(int j=i+1;j<=arr.length-1;j++) { if(arr[j]<arr[i]) { min=arr[j]; minIndex=j; } } if(min!=arr[i]) { arr[minIndex]=arr[i]; arr[i]=min; } } System.out.println(Arrays.toString(arr)); } }
插入排序
插入排序属于内部排序法。是对欲排序的元素以插入的方式找寻该元素的适当位置,以达到排序的目的。
思想:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只含有一个元素,无序表中包含有 n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。
![图片说明](https://uploadfiles.nowcoder.com/images/20200603/319217495_1591191590646_552CDF0684C8865FA988AF20D09B5DB1 &amp;amp;amp;amp;amp;quot;图片标题&amp;amp;amp;amp;amp;quot;)
代码实现:
import java.util.Arrays; public class InsertSort { public static void main(String[] args) { // TODO Auto-generated method stub int arr[]= {3,-1,9,87,21,46}; insertSort(arr); System.out.print(Arrays.toString(arr)); } public static void insertSort(int[] arr) { for(int i=1;i&amp;amp;amp;amp;amp;amp;lt;arr.length;i++) { int insertVal=arr[i]; int insertIndex=i-1; while(insertIndex&amp;amp;amp;amp;amp;amp;gt;=0&amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;insertVal&amp;amp;amp;amp;amp;amp;lt;arr[insertIndex]) { arr[insertIndex+1]=arr[insertIndex]; insertIndex--; } arr[insertIndex+1]=insertVal; } } }
希尔排序
希尔排序也是一种插入排序,它是简单插入排序经过改进后的一个更高效的版本,也称为缩小增量排序。
基本思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰好被分成一组,算法便终止。
![图片说明](https://uploadfiles.nowcoder.com/images/20200604/319217495_1591200468530_8BFA07D9C67D2EA96345ECBFA8C5AF1F &amp;amp;amp;quot;图片标题&amp;amp;amp;quot;)
代码实现
import java.util.Arrays; public class ShellSort { public static void main(String[] args) { // TODO Auto-generated method stub int[] arr= {8,9,1,7,2,3,5,4,6,0}; shellSort(arr); //shellSort2(arr); System.out.print(Arrays.toString(arr)); } public static void shellSort(int[] arr){ //采用交换法 int tmp=0; int count=0; for(int gap=arr.length/2;gap&amp;amp;amp;amp;gt;0;gap/=2) { for(int i=gap;i&amp;amp;amp;amp;lt;arr.length;i++) { //遍历各组所有的元素(共gap组,每组有个元素),步长gap for(int j=i-gap;j&amp;amp;amp;amp;gt;=0;j-=gap) { //注意循环条件 //如果当前元素大于加上步长后的元素,说明交换 if(arr[j]&amp;amp;amp;amp;gt;arr[j+gap]) { tmp=arr[j]; arr[j]=arr[j+gap]; arr[j+gap]=tmp; } } } } } //对交换的希尔排序进行优化----&amp;amp;amp;amp;gt;移位法 public static void shellSort2(int[] arr) { //增量gap,并逐步的缩小增量 for(int gap=arr.length/2;gap&amp;amp;amp;amp;gt;0;gap/=2) { //从第gap个元素,逐个对其所在的组进行直接插入排序 for(int i=gap;i&amp;amp;amp;amp;lt;arr.length;i++) { int j=i; int tmp=arr[j]; if(arr[j]&amp;amp;amp;amp;lt;arr[j-gap]) { while(j-gap&amp;amp;amp;amp;gt;=0&amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;tmp&amp;amp;amp;amp;lt;arr[j-gap]) { //移动 arr[j]=arr[j-gap]; j-=gap; } //当退出while后,就给tep找到插入的位置 arr[j]=tmp; } } } } }
快速排序
快速排序是(QuickSort)是对冒泡排序的一种改进。基本思想是:通过一趟排序将要排序的数据分割成独立的两部分。其中一部分的所有数据都比另外一部分的所有数据都小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
![图片说明](https://uploadfiles.nowcoder.com/images/20200604/319217495_1591263687006_69D156F2078C3334AF849ACDB0F162B5 &amp;amp;quot;图片标题&amp;amp;quot;)
代码实现
import java.util.Arrays; public class QuickSort { public static void main(String[] args) { // TODO Auto-generated method stub int arr[]= {-9,78,0,23,-567,70}; quickSort(arr,0,arr.length-1); System.out.println(Arrays.toString(arr)); } public static void quickSort(int[] arr,int left,int right) { int l=left; int r=right; //设置pivot 中轴值 int pivot=arr[(left+right)/2]; int temp=0; //交换时用 //while循环,使比pivot小的值放左边,比pivot值大的放右边 while(l&amp;amp;amp;lt;r) { //再pivot的左边一直找,找到大于等于pivot的值,才退出 while(arr[l]&amp;amp;amp;lt;pivot) { l+=1; } //在pivot右边找到小于pivot的值,才退出 while(arr[r]&amp;amp;amp;gt;pivot) { r-=1; } //如果l&amp;amp;amp;gt;=r说明pivot左右两边的值以全部是右边大于左边 if(l&amp;amp;amp;gt;=r) { break; } //交换 temp=arr[l]; arr[l]=arr[r]; arr[r]=temp; //如果交换完后,发现arr[l]==pivot值,相等 r--,前移 if(arr[1]==pivot) { r-=1; } //如果交换完后,发现这个arr[r]==pivot值,相等 l++,后移 if(arr[r]==pivot) { l+=1; } } //如果l==r,必须l++.r--,否则会出现栈溢出 if(l==r) { l+=1; r-=1; } //向左递归 if(left&amp;amp;amp;lt;r) { quickSort(arr,left,r); } //向右递归 if(right&amp;amp;amp;gt;l) { quickSort(arr,l,right); } } }
思路分析图
![图片说明](https://uploadfiles.nowcoder.com/images/20200604/319217495_1591266433640_DF802A013B9462E9AEDD6EA8F6D8494C &amp;amp;quot;图片标题&amp;amp;quot;)
归并排序
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分置(divide-and-conquer)策略(分治法将问题分(divide)一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各个答案“修补在一起”,即分而治之)。
![图片说明](https://uploadfiles.nowcoder.com/images/20200604/319217495_1591275552398_79024EFA86169A44AA188AB425322B59 &quot;图片标题&quot;)
![图片说明](https://uploadfiles.nowcoder.com/images/20200604/319217495_1591275564408_DA7EC1F1BEF51678FD02EB30D1EC3FC8 &quot;图片标题&quot;)
代码实现
import java.util.Arrays; public class MergeSort { public static void main(String[] args) { // TODO Auto-generated method stub int arr[]= {8,4,5,7,1,3,6,2}; int temp[]=new int[arr.length]; //归并需要的额外空间 mergeSort(arr,0,arr.length-1,temp); System.out.println(&amp;quot;归并排序后=&amp;quot;+Arrays.toString(arr)); } //分+合的方法 public static void mergeSort(int[] arr,int left,int right,int[] temp) { if(left&amp;lt;right) { int mid=(left+right)/2; //中间索引 //向左递归进行分解 mergeSort(arr,left,mid,temp); //向右递归进行分解 mergeSort(arr,mid+1,right,temp); //合并 merge(arr,left,mid,right,temp); } } //合并的方法 public static void merge(int[] arr,int left,int mid,int right,int[] temp) { int i=left;//初始化i,左边有序序列的初始索引 int j=mid+1;//初始化j,右边有序序列的初始索引 int t=0; //指向temp数组的当前序列 //(一) //先把左右两边(有序)的数据按照规则填充到temp数组 //直到左右两边的有序序列,有一边处理完为止 while(i&amp;lt;=mid&amp;amp;&amp;amp;j&amp;lt;=right) { //如果左边的有序序列的当前元素,小于右边有序序列的当前元素 //即将左边的当前元素填充到temp数组 //然后i++,temp索引t++ if(arr[i]&amp;lt;=arr[j]) { temp[t]=arr[i]; t++; i++; }else { temp[t]=arr[j]; t++; j++; } } //(二) //将有剩余数据的一边依次填充到temp while(i&amp;lt;=mid) { temp[t]=arr[i]; t++; i++; } while(j&amp;lt;=right) { temp[t]=arr[j]; t++; j++; } //(三) //将temp数组的元素拷贝到arr,注意的是不是每次都拷贝所有的元素 t=0; int tempLeft=left; //第一次合并tempLeft=0,right=1;第二次tempLeft=2,right=3//tL=0,ri=3 //最后一次 tempLeft=0 right=7 while(tempLeft&amp;lt;=right) { arr[tempLeft]=temp[t]; t++; tempLeft++; } } }
基数排序(适用于非负数排序)
1)基数排序(桶排序)属于“分配式排序”(distribution sort),又称“桶子法”(buck sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配到某些"桶"中,达到排序效果。
2)基数排序法是属于稳定性的排序,基数排序法是效率高的稳定性排序法。
3)基数排序(Radix Sort)是桶排序的发展。
4)基数排序是1887年赫尔曼.赫勒里发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。
基本思想
①将所有待比较数值统一位同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行依次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成了一个有序序列。
②图文,以数组{53,3,542,748,14,214}为例。
![图片说明](https://uploadfiles.nowcoder.com/images/20200605/319217495_1591326653692_954A11EC3E977807EC386EC1B9D32EB7 "图片标题")
![图片说明](https://uploadfiles.nowcoder.com/images/20200605/319217495_1591326668087_9EB65C0872631ABDFEE9F9C473B91D00 "图片标题")
代码实现
import java.util.Arrays; public class RadixSort { public static void main(String[] args) { // TODO Auto-generated method stub int arr[]= {53,3,542,748,14,214}; radixSort(arr); System.out.println(Arrays.toString(arr)); } //基数排序方法 public static void radixSort(int[] arr) { //1.得到数组中最大的数的位数 int max=arr[0]; //假设第一个数就是最大数 for(int i=1;i<arr.length;i++) { if(arr[i]>max) { max=arr[i]; } } //得到最大位数是多少 int maxLength=(max+"").length(); //计算某数的位数的一个方法,转为string类型,.length()。 //定义一个二维数组,表示10个桶,每个桶就是一个一维数组 //说明 //1.二维数组包含10个一维数组 //2.为防止在放入数的时候,数据溢出,将每个一位数组大小定义为arr.length,所以基数算法是以空间换时间的一种算法 int[][] bucket=new int[10][arr.length]; //定义一个一维数组记录各个桶放入的数据个数 int[] bucketElementCount=new int[10]; for(int i=0,n=1;i<maxLength;i++,n*=10) { //(针对每个元素的对应位进行排序处理),个位→十位→百位→... for(int j=0;j<arr.length;j++) { //取出对应元素的对应位的值 int digitOfElement=arr[j]/n%10; //放入到对应的桶里 bucket[digitOfElement][bucketElementCount[digitOfElement]]=arr[j]; bucketElementCount[digitOfElement]++; } //按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组) int index=0; //遍历每一个桶,并将桶中的数据放到原数组 for(int k=0;k<bucketElementCount.length;k++) { //如果桶不为空,则放入原数组 if(bucketElementCount[k]!=0) { //循环第k个桶,将数据依次放入 for(int l=0;l<bucketElementCount[k];l++) { // arr[index++]=bucket[k][l]; } } //第i+1轮处理过后,需要将每个bucketElementCounts[k]=0 bucketElementCount[k]=0; } System.out.println("第"+(i+1)+"轮,对位数的排序处理 arr="+Arrays.toString(arr));