public class Sort {
//直接插入排序
//小规模数据或基本有序时十分高效
//将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
//时间复杂度:O(n^2) 空间复杂度O(1)
//最差情况:反序,需要移动n*(n-1)/2个元素 最好情况:正序,不需要移动元素
public void straightInsertionSort(int[] a) {
int temp=0;
for(int i=1;i<a.length;i++) {
temp=a[i];
for(int j=i-1;j>=0;j--) {
if(a[j]>temp) {
a[j+1]=a[j];
if(j==0) {
a[0]=temp;
}
}
else {
a[j+1]=temp;
break;
}
}
}
}
//***********************************************************************************************************************************************************************************
//希尔排序(缩小增量排序)
//基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
//操作方法:选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;按增量序列个数k,对序列进行k 趟排序;每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
//时间复杂度:平均O(n^1.3),最好为O(n),最坏为0(n ^ 2) 空间复杂度:O(1) 稳定性:不稳定
public void shellsSort(int[] a) {
int n=a.length;
for(int g=n/2;g>0;g++) {
for(int i=g;i<n;i++) {
int insert=a[i];
int j;
for(j=i-g;j>=0&&insert<a[j];j-=g) {
a[j+g]=a[j];
}
a[j+g]=insert;
}
}
}
//***********************************************************************************************************************************************************************************
//简单选择排序(Simple Selection Sort)--改进(二元选择排序)
//基本思想:在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
//最好、最差、平均时间复杂度均为:O(n^2) 空间复杂度:O(1)
public void simpleSelectionSort(int[] a) {
for(int i=0;i<a.length;i++) {
int min=a[i];
int w=i;
for(int j=i;j<a.length;j++) {
if(a[j]<min) {
min=a[j];
w=j;
}
}
a[w]=a[i];
a[i]=min;
}
}
//************************************************************************************************************************************************************************************************
//选择排序—堆排序(Heap Sort)
// 原理: 构造初始堆,从最后一个非叶节点开始调整。选出叶子节点中比自己大的一个交换,如果交换后的叶子节点不满足堆,则继续调整
// 构造好初始堆之后,将堆头元素交换到堆尾,堆尾的元素就已经是有序的了,然后一直重复,直到所有都有序
//堆 parent=(i-1)/2 leftchild=2*i+1 rightchild=2*i+2
//build_heap过程:一共调用n次build_heap函数,build_heap(i),build_heap(i)的时间复杂度是O(log i),所以整个建立大顶堆的时间复杂度是O(log1) + O(log2) + O(log3) + … O(logn) = O(n)。(注:该公式是一个定理)
//heapify过程:一共调用n次heapify,heapify()的时间复杂度是O(log n),所以,整个不断交换堆顶与堆尾元素,并进行大顶堆化的时间复杂度是O(n*log(n))。
//heap_sort过程:整个堆排序的时间复杂度:O(n) + O(n* logn) = O(n*logn)最好最坏情况一样相同。。 空间复杂度O(1)
public void heapSort(int[] a) {
buildheap(a,a.length);
for(int i=a.length-1;i>=0;i--) {
swap(a,i,0);
heapify(a,i,0);
}
}
public void swap(int[] a,int i,int j) {
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
public void heapify(int[] a,int n,int i) {//区域成堆
int lc=2*i+1;
int rc=2*i+2;
int max=i;
if(lc<n&&a[lc]>a[i]) {
swap(a,lc,max);
}
if(rc<n&&a[rc]>a[max]) {
swap(a,rc,max);
}
}
public void buildheap(int[] a,int n) {
int last=a.length-1;
int parent=(last-1)/2;
for(int i=parent;i>=0;i--) {
heapify(a,a.length,i);
}
}
//******************************************************************************************************************************************************************************************
//交换排序—冒泡排序(Bubble Sort)----改进(双向冒泡)
//基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
//最好的时间复杂度为O(n) 最坏和平均时间复杂度为:O(n2)
public void bubbleSort(int[] a) {
for(int i=0;i<a.length-1;i++) {
for(int j=0;j<a.length-i-1;j++) {
int temp=a[j];
if(temp>a[j+1]) {
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
//*******************************************************************************************************************************************************************************************
//交换排序—快速排序(Quick Sort)
//基本思想:1)选择一个基准元素,通常选择第一个元素或者最后一个元素,(2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大。(3)此时基准元素在其排好序后的正确位置
// (4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。
//快速排序是通常被认为在同数量级(O(nlog2n))的排序方法中平均性能最好的
//最好情况(待排序列接近无序)时间复杂度为O(nlog2n),最坏情况(待排序列接近有序)时间复杂度为O(n2),平均时间复杂度为O(nlog2n) 空间复杂度O(nlog2n)
public void quickSort(int[] a,int l,int r) {
if(l<r) {
int i=l;
int j=r;
int temp=a[l];//设置准基
while(i<j) {
while(i<j&&a[j]>=temp) {
j--;
}
a[i]=a[j];
while(i<j&&a[i]<=temp) {
i++;
}
a[j]=a[i];
}
a[i]=temp;
int index=i;
quickSort(a,l,index-1);
quickSort(a,index+1,r);
}
else {
return;
}
}
//*****************************************************************************************************************************************************************************************************
// 归并排序(Merge Sort)
//基本思想:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
//最好,最坏,平均时间复杂度:O(nlogn) 空间复杂度:O(N)
//归并排序需要一个与原数组相同长度的数组做辅助来排序
//稳定性:归并排序是稳定的排序算法
public void mergeSort(int[] a) {
int[] temp=new int[a.length];
mergeSort(a,0,a.length-1,temp);
}
public void mergeSort(int[] a,int l,int r,int[] temp) {
if(l<r) {
int mid=(l+r)/2;
mergeSort(a,l,mid,temp);//左边归并排序,使得左子序列有序
mergeSort(a,mid+1,r,temp);
merge(a,l,mid,r,temp);//将两个有序子数组合并操作
}
else {
return;
}
}
public void merge(int[] a,int l,int mid,int r,int[] temp) {
int i=l,j=mid+1,t=0;
while(i<=mid&&j<=r) {
if(a[i]<a[j]) {
temp[t++]=a[i++];
}
else {
temp[t++]=a[j++];
}
}
while(i<=mid) {//将左边剩余元素填充进temp中
temp[t++]=a[i++];
}
while(j<=r) {//将右序列剩余元素填充进temp中
temp[t++]=a[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while(l<= r){
a[l++] = temp[t++];
}
}
//*********************************************************************************************************************************************************************************************************************************
//桶排序/基数排序(Radix Sort)
//基本思想:是将阵列分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序)。
//桶排序是鸽巢排序的一种归纳结果。当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。但桶排序并不是 比较排序,他不受到 O(n log n) 下限的影响。
// 简单来说,就是把数据分组,放在一个个的桶中,然后对每个桶里面的在进行排序
public static void main(String[] args) {
// TODO 自动生成的方法存根
int[] a= {4,9,8,1,5};
Sort s=new Sort();
//s.simpleSelectionSort(a);
//s.heapSort(a);
//s.bubbleSort(a);
//s.quickSort(a, 0, a.length-1);
s.mergeSort(a);
for(int i=0;i<a.length;i++) {
System.out.print(a[i]);
}
}
}