首页 > 代码库 > 几种基本排序算法总结
几种基本排序算法总结
以下均采用从小到大排序:
1.选择排序算法
个人觉得选择排序算法是容易理解的排序算法,即从n个元素中选择最小的一个元素与第一个元素交换,再将除第一个元素之外的n-1个元素找到最小的一个放在第二个位置,以此类推。
如:1,1,2,3,0
第一次排序:[0],1,2,3,1 //0最小,与第一个元素交换位置
//由这一步可知,原数组第一个元素与第二个元素都是1,第一次排序之后两个元素的前后位置改变,可知选择排序算法是不稳定的
第二次排序:[0,1],2,3,1 //经过比较后四个数的最小的是1,位置不变
第三次排序:[0,1,1],3,2 //经过比较后三个数的最小元素是1,1与第三个位置的元素即2交换位置
第四次排序:[0,1,1,2,3] //最后比较后两个,交换
java实现:
public class XuanZe { public static void main(String[] args) { int[] a={1,5,7,6,4,8,9,3,2,0}; selectSort(a); for(int i=0;i<a.length;i++) { System.out.print(a[i]+" "); } } public static void selectSort(int[] a) { int i,j,k,temp,c; for(i=0;i<a.length-1;i++) { temp=a[i]; k=i; for(j=i+1;j<a.length;j++) { if(a[j]<temp) { temp=a[j]; //每次选择最小的与前面的交换,这样有可能改变原本的两个相等的数的位置, //所以为不稳定的排序算法。如2 4 8 9 4,第一次排序时将会改变两个4原本的前后位置 k=j; } } if(k!=i) { c=a[i]; a[i]=a[k]; a[k]=c; } } } }
选择排序算法,无论之前是否有序,都要经过n-1趟排序,所以最好时间复杂度为O(n^2),最坏也是O(n^2),空间复杂度为:O(1)。适合n较小时的排序。
2.冒泡排序算法
冒泡排序算法相对来说也很简单,很多面试官爱考冒泡排序算法,不论是我之前听一些学长考研时的面试问题,还是企业的面试考题都有冒泡排序算法的问题。冒泡排序算法大数逐渐往末尾走的算法。冒泡排序是不断的通过相邻两个元素比较大小,不断的交换位置实现的。
如:9 8 4 5 0
第一次排序 :8 4 5 0 [9] //在实现这个排序的过程中,9先和8比较,交换位置 得到8 9 4 5 0;9与4比较,交换位置得到8 4 9 5 0;9和5比较,交换位置,得到8 4 5 9 0;
//9与0比较,交换位置,得到8 4 5 0 9;相邻两个元素相等或者第i-1个元素小于第i个元素时,不交换,大于时交换位置由此也可知相等元素前后位置
//不会改变,冒泡排序算法为稳定的
第二次排序:4 5 0 [8 9]
第三次排序:4 0 [5 8 9]
第四次排序:[0 4 5 8 9]
java实现:
public class MaoPao { public static void main(String[] args) { int[] a={0,4,8,9,7,6,5,3,2,1}; bubbleSort(a); for(int i=0;i<a.length;i++) { System.out.print(a[i]+" "); } } public static void bubbleSort(int[] a) { int i,j,k,temp; int len=a.length; for(i=0;i<len-1;i++) { k=len-1; for(j=0;j<k;j++) { if(a[j]>a[j+1]) { temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } k--; //每次对数组的n个数经过冒泡排序之后最大的那个在最后面, //只需要再对前n-1个元素进行排序 } } }
冒泡排序算法最好的情况下时间复杂度为O(n)(针对改进后的代码,不对应我的代码),最坏情况的时间复杂度也为O(n^2),平均时间复杂度为O(n^2),空间复杂度O(1)。适合于n较小时的排序。
3.插入排序算法
插入排序算法,假设第一个元素为有序序列,不断的将第2,3,4......个数插入到有序序列中。
如:4 5 6 1 2
[4] 5 6 1 2 //首先将4作为有序序列;
第一次排序:[4 5] 6 1 2 //将5插入到4的有序序列,形成又一个有序队列,以此下去
第二次排序:[4 5 6] 1 2 //因为插入的时候是将后面的元素插入到其前面的元素构成的有序序列当中,若是等于某个元素,即放在该元素的后面,所以不会 //改变相等的数前后位置关系
第三次排序:[1 4 5 6] 2 //排序之前的前后位置关系,是稳定的
第四次排序:[1 2 4 5 6]
java实现:
public class Cha { public static void main(String[] args) { int[] a={1,5,8,9,3,0,2,7,4,6}; insertSort(a); for(int i=0;i<a.length;i++) { System.out.print(a[i]+" "); } } public static void insertSort(int[] a) { int i,j,k,temp; int len=a.length; for(i=1;i<len;i++) { temp=a[i]; if(i-1>=0) { while(i-1>=0&&a[i-1]>temp) { a[i]=a[i-1]; //把大的数放到后面,i-- i--; //具有稳定性 } } a[i]=temp; } } }
最好时时间复杂度为O(n),最坏时间复杂度为O(n^2),平均时间复杂度为O(n^2),空间复杂度为O(1)。适合大部分是有序时。
4.希尔排序算法
希尔排序算法是对插入排序算法的改进。希尔排序相当于根据不同的步长将序列分为多个子序列,先对各个子序列使用插入排序算法排序,之后再对整个序列进行排序。步长的最后一个步长必须是1。
如:1 4 4 6 3 7 2 5 9 0
一共有10个数,步长应该为5 2 1
第一次排序:1 2 4 6 0 7 4 5 9 3 //此时步长为5,步长为5时,形成了5个子序列,分别是:1 7;4 2;4 5;6 9;3 0,用插入法对五个子序列排序,为:1 7; 2 4;4 5 ;
//6 9;0 3;合成之后为1 2 4 6 0 7 4 5 9 3
第二次排序:0 2 1 3 4 5 4 6 9 7 //此时步长为2,形成的子序列为:1 4 0 4 9 ;2 6 7 5 3 用插入法排序之后:0 1 4 4 9; 2 3 5 6 7即 0 2 1 3 4 5 4 6 9 7
第三次排序:0 1 2 3 4 4 5 6 7 9 //步长为1的插入排序算法;
//在第一次排序时,2与后面的那个4交换位置,改变了两个4的前后顺序,所以可知为不稳定排序算法
java实现:
public class XiEr { public static void main(String[] args) { int[] a={1,5,2,7,8,4,9,6,3,0}; shellSort(a); for(int i=0;i<a.length;i++) { System.out.print(a[i]+" "); } } public static void shellSort(int[] a) { int len=a.length; int i,h,temp; for(h=len/2;h>0;h=h/2) { //步长为h的插入排序,因为步长会将序列分为不同的子序列,会打乱相同数的前后顺序,所以为不稳定排序算法 for(i=h;i<len;i++) { temp=a[i]; if(i-h>=0) { while(i-h>=0&&a[i-h]>temp) { a[i]=a[i-h]; i=i-h; } } a[i]=temp; } } } }
最好的时间复杂度为O(n),平均时间复杂度为O(nlogn),空间复杂度O(1).
5.快速排序算法
快速排序算法是一个递归的排序算法,首先将第一个元素i作为分界点,后面大于i的元素移动到i后面,小于i的元素移动到i前面。在将i前面的元素作为一个序列,在i后面的元素作为一个序列。在将这两个序列的第一个元素作为分界点重复这个操作。
如: 4 7 5 8 2 1 3
第一次排序: [2 1 3] 4 [7 5 8] //首先将4作为分界点,大于等于4的移动到4之后,小于4的移动到4之前,将2 1 3作为一个序列, 7 5 8作为一个序列
第二次排序: 1 2 3 4 5 7 8 //将2作为分界点,大于2的移动到2之后,小于2的移动到2之前,得到 1 2 3,同理得到5 7 8
java实现:
public class Kuai { public static void main(String[] args) { int[] a={0,5,7,8,4,6,9,3,2,1}; int len=a.length; quickSort(a); for(int i=0;i<len;i++) { System.out.print(a[i]+" "); } } public static void quickSort(int[] a) { quick(a,0,a.length-1); } public static void quick(int[] a,int p,int q) { int index; int i=p; int j=q; if(p>=q) { return; } index=a[i]; while(i<j) { while(i<j&&a[j]>=index) //由于从两侧开始排序,不稳定 { j--; } if(i<j) { a[i++]=a[j]; } while(i<j&&a[i]<index) { i++; } if(i<j) { a[j--]=a[i]; } } a[i]=index; quick(a,p,i-1); quick(a,i+1,q); } }
最好时间复杂度为O(nlogn),最坏时间复杂度为O(n^2),平均时间复杂度O(nlogn),空间复杂度为O(nlogn),适合n较大的情况
6.归并排序算法
归并排序算法即先将数据序列划分为越来越小的半子表,再对半子表排序,最后再用递归的方法将半子表合并成越来越大的有序序列
如:7 8 4 5 2 1 3
先成为[7 8 4 5]和[2 1 3]两个序列,再次划分成为[7 8] ,[4 5],[2 1],[3]四个序列,再次划分为 [7] ,[8],[4],[5],[2],[1],[3],归并时进行排序
第一次归并为[7 8],[4 5],[1 2],[3]
第二次归并为[4 5 7 8],[1 2 3]
第三次归并为[1 2 3 4 5 6 7 8] //归并排序时并不会改变相同数的前后顺序,稳定的排序算法
java实现:
public class GuiBing { public static void main(String[] args) { int[] a={0,5,7,8,4,6,9,3,2,1}; int len=a.length; guiSort(a,0,len-1); for(int i=0;i<len;i++) { System.out.print(a[i]+" "); } } public static void guiSort(int[] a,int p,int q) //归并因为是为了拆开然后排序,并不会改变相同数的位置,稳定排序 { int r; if(p<q) { r=(p+q)/2; guiSort(a,p,r); guiSort(a,r+1,q); gui(a,p,r,q); } } public static void gui(int[] a,int p,int r,int q) { int i,j,k,n1,n2; int[] L; int[] R; n1=r-p+1; n2=q-r; L=new int[n1]; R=new int[n2]; for(i=0,k=p;i<n1;i++,k++) { L[i]=a[k]; } for(i=0,k=r+1;i<n2;i++,k++) { R[i]=a[k]; } for(i=0,j=0,k=p;i<n1&&j<n2;k++) { if(L[i]<R[j]) { a[k]=L[i++]; } else { a[k]=R[j++]; } } if(i<n1) { for(j=i;j<n1;j++) { a[k++]=L[j]; } } if(j<n2) { for(i=j;i<n2;i++) { a[k++]=R[i]; } } } }
最好的时间复杂度为O(nlogn),最坏的时间复杂度为O(nlogn),平均时间复杂度为O(nlogn),空间复杂度O(n),n大时比较好。
7.堆排序算法
堆是一种特殊的树形数据结构。堆排序利用的是一树形选择结构。堆分为大顶堆和小顶堆,大顶堆即每一个节点都比左子树和右子树大,小顶堆即每一个节点都比左子树和右子树大。
所以在使用堆排序算法时,首先是先构造堆,然后交换堆顶元素和最后一个元素的位置。
堆排序算法因为过于复杂,我不太会弄,就不详解,参照http://blog.csdn.net/xiaoxiaoxuewen/article/details/7570621,博主讲的很清晰。
java实现:
public class Dui { public static void main(String[] args) { int[] a={0,7,8,6,5,4,3,2,9,10,1}; int len=a.length; MaxHeap(a); for(int i=0;i<len;i++) { System.out.print(a[i]+" "); } } public static void MaxHeap(int[] a) { int len=a.length; int i,temp; for(i=len/2-1;i>=0;i--) { adjustMaxHeap(a,i,len-1); } for(i=len-1;i>=0;i--) { temp=a[0]; a[0]=a[i]; a[i]=temp; adjustMaxHeap(a,0,i-1); } } public static void adjustMaxHeap(int[] a,int pos,int len) { int child,temp; for(temp=a[pos];2*pos+1<=len;pos=child) { child=2*pos+1; if(child<len&&a[child]<a[child+1]) //由于child可以等于len,此处child<len即child+1<=len; { child++; //不稳定 } if(a[child]>temp) { a[pos]=a[child]; } else { break; } } a[pos]=temp; } }
最好的时间复杂度为O(nlogn),最坏的时间复杂度为O(nlogn),平均时间复杂度为O(nlogn),空间复杂度为O(1),适合n较大的情况。
几种基本排序算法总结