以下都是从小到大的排序
冒泡算法
重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
冒泡排序算法的运作如下:(从后往前)
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
private static void Bsort(int[] a){
int len=a.length;
boolean flag=true;
for(int i=0;i<len-1 && flag;i++){
flag=false;
for(int j=0;j<len-1-i;j++){
if(a[j]>a[j+1]){
int temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
flag=true;
}
}
}
}
冒泡排序的时间复杂度为O(n^2) 空间复杂度O(1),对于逆序的排列需要排序次序为2n(n-1)/2
直接插入
①确定数据“8”在原有序列中应该占有的位置序号。数据“8”所处的位置应满足小于或等于该位置右边所有的数据,大于其左边位置上所有的数据。
②将这个位置空出来,将数据“8”插进去。
直接插入排序(straight insertion sort)的做法是:
每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
第一趟比较前两个数,然后把第二个数按大小插入到有序表中; 第二趟把第三个数据与前两个数从后向前扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
直接插入排序是由两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
插入排序的基本方法是:每步将一个待排序的记录按其关键字的大小插到前面已经排序的序列中的适当位置,直到全部记录插入完毕为止。
private static void Insert(int[] a){
int len=a.length;
for(int i=0;i<len;i++){
int key=a[i];
int j=i-1;
while(j>=0 && a[j]>key){
a[j+1]=a[j];
j=j-1;
}
a[j+1]=key;
}
}
快速排序
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
private static void qs(int[] a,int left,int righ ){
if(left<righ){
int pos=partion(a,left,righ);
qs(a,left,pos-1);
qs(a,pos+1,righ);
}
}
private static int partion(int[] a,int left,int righ){
int low=left;
int high=righ;
int key=a[left];
if(low<high){
while(low<high && a[high]>key) {high--;}
if(low<high){a[low]=a[high];low++;}
while(low<high && a[low]<=key){low++;}
if(low<high){a[high]=a[low];high--;}
}
a[low]=key;
return low;
}
堆排序
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶
private static void HeapSort(int[] a){
int len=a.length;
for(int i=len/2;i>=0;i--){
shif(a,i,len-1);
}
for(int i=len-1;i>=1;i--){
int b=a[0];
a[0]=a[i];
a[i]=b;
shif(a,0,i-1);
}
}
private static void shif(int[] a, int k, int m) {
int x=a[k];
int i=k;
int j=2*i;
boolean fin=false;
while(j<m && !fin){
if(j<m && a[j]<a[j+1]) j++;
if(x>=a[j]) fin=true;
else{
a[i]=a[j];
i=j;
j=2*i;
}
}
a[i]=x;
}
shell排序
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<;…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法。
private static void shell(int[] a){
int h=1;
while(h<=a.length/3){
h=h*3+1;
}
hsort(a,h);
}
public static void hsort(int[] a,int h){
int i=0,j=0,key=0;
boolean b=true;
int len=a.length;
while(h>0){
for(i=1+h;i<len;i++){
key=a[i];
j=i-h;
while(j>=0 && a[j]>key){
a[j+h]=a[j];
j=j-h;
}
a[j+h]=key;
}
h=(h-1)/3;
}
}
归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。
public static int[] sort(int[] nums, int low, int high) {
int mid=(low+high)/2;
if(low<high){
sort(nums,low,mid);
sort(nums,mid+1,high);
merge(nums,low,mid,high);
}
return nums;
}
public static void merge(int[] nums, int low, int mid, int high) {
int[] temp=new int[nums.length];
int left=low;
int right=mid+1;
int k=low;
while(left<=mid && right<=high){
if(nums[left]>nums[right]){
temp[k++]=nums[right++];
}else{
temp[k++]=nums[left++];
}
}
while(left<=mid){
temp[k++]=nums[left++];
}
while(right<=high){
temp[k++]=nums[right++];
}
while(low<=high)
{
nums[low]=temp[low++];
}
}