六种常见排序算法Java实现

一、冒泡排序
冒泡排序实现简单,但运行效率较慢。算法思想是,设要排序的为数组A中的元素,遍历A.length-1次,每次找出待排序元素中最小的值放在相应位置,如:第一次遍历数组下标为A.length-1 到0的元素,将最小的值放在A[0]的位置,第二次遍历数组下标为A.length-1到1的元素,将最小值放在A[1]的位置。总共遍历 A.length-1次得到一个有序数组。这个算法的时间开销主要在比较和交换上。效率极低。

Java实现代码:

public class Bubble  {

    public static long[] BubbleSort(long[] a){
        for(int i=a.length -1;i>0;i--){
            for(int j=0;j<i ;j++){
                if(a[j]>a[j+1]){
                    long temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;
            }

        }
        }
return a;
}

二、插入排序

插入排序适合少量元素的排序,插入排序算法将元素分为两组,一组是已经有序的,一组是待参与排序的。初始时,有序的组中仅有原数组的首元素,其后,不断从待排序的元素中取出一个插入到有序数组的合适位置,直至待排序数组为空。此过程类似于玩扑克牌中起牌的过程,手中的牌是有序的,桌子上的牌是待排序的,每次从桌上起一张牌插到手中的牌。插入排序算法最坏情况下插入排序运行时间为Θ(n^2)。
具体的Java实现代码如下:
注:float[] a为待排序的数组。

    public static float[] InsertSort(float[] a)
    {    
        if (a.length <= 1) 
            return a;
//  从第二个元素起  插到前面排列好的序列中 
        for(int i=1;i<a.length;i++){    
            float key = a[i]; //key为要插入的数据
            int j = i -1;//标记要与Key比较的元素的下标0
            while(j>=0&&key<a[j]){
                a[j+1] = a[j];
                j--;
            }
        a[j+1] = key;
        }
        return a;
    }

三、 快速排序

最坏情况时间复杂度为Θ(n2)。虽然最坏情况表现很差,但是快速排序通常是实际应用中最好的选择,因为它的平均性能特别好,它的期望时间复杂度为Θ(n lg n) 而且Θ(nlg n)中隐含的常数因子非常小,此外,它还能在原址排序。
与归并排序一样,快速排序也使用了分治思想。大致思路是这样的:
1、 数组被划分成两个子数组(可能为空),这两个数组满足:左边数组中的每一个元素都不大于右边数组的任一个元素。
2、 对两个子数组重复上面操作,直至子数组长度小于等于1。
对于第一步操作,代码中用partition函数实现。主要思路如下:
对于数组A:
1、 数组的最后一个元素为哨兵;
2、 数组划分界线Div初始为-1;
3、 遍历数组中下标为0-A.length-2的元素进行以下操作:

  • 若该元素小于A[A.length-1],该元素与A[Div+1]交换;
  • Div加一;
    4、 A[Div+1]与A[A.length-1]交换。
    Java实现的代码如下:
    private static float[] QuickSort(float[] a,int p,int r) {
        // TODO Auto-generated method stub
        if(p<r){
            int q = partition(a,p,r);
            QuickSort(a,p,q-1);
            QuickSort(a,q+1,r);

        }
        return a;
    } 
//  partition函数得到数组的一个下标  这个下标使得左边的元素都大于它 右边的元素都不小于它
    private static int partition(float[] a,int p,int r){
        float x = a[r];
        int low = p - 1 ;// p-low存放比x小的  low-high存放比x大的
        for(int j=p;j<r;j++){

            if(a[j]<=x)  {
//              exchange a[low+1] with a[j]
                float temp = a[low+1];
                a[low+1] = a[j];
                a[j] = temp;
                low++;
                }
        }
//          exchange a[low+1] with a[r]
            float temp = a[r];
            a[r] = a[low+1];
            a[low+1] = temp;
            low++;
    return low;

    }

四、归并排序

简言之,归并排序将两个有序的数组合并为一个新的有序数组
以扑克牌为例 两堆牌面朝上的有序扑克牌 每次取两堆中 最上面的较小的一张 直到一堆牌为空

private  float[] MergeSort(float[] a)
{   if(a.length<=1) return a;
    for(int i = 1;i<a.length;i=2*i) 
        for(int p = 0;p<a.length;p=p+2*i )
        {   
            int r = p + 2*i -1;
            int q = p + i -1;
            if(q>a.length - 1) q = a.length - 1;
            if(r>a.length - 1) r = a.length - 1 ;   
             Merge(a,p,q,r);
        }

    return a;
}
private static float[] Merge(float[] a,int p,int q,int r) // a为待排序数组 pqr为下标 p->q有序  q+1->r有序
{
    int n1 = q - p + 1;
    int n2 = r -q;
    float[] L = new float[n1+1];
    float[] R = new float[n2+1];
    for(int i=0; i<n1;i++)
        L[i] = a[p + i];
    L[n1] =  99999;//哨兵位置
    for(int i=0; i<n2; i++)
        R[i] = a[q+i + 1];
    R[n2] = 99999;//哨兵位置
//  i和j标记R和L待比较的最小值的位置
    int i = 0;
    int j = 0;
//  k标记a中插入位置
 for(int k=p;k<=r;k++)
    if(R[i]>L[j])
        {
        a[k] = L[j];
        j++;
        }
    else
        {
        a[k] = R[i];
        i++;
        }
    return a;
}

}
 

五、 希尔排序

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插入排序的执行效率。对于插入排序而言,比较尴尬的地方在于,如果插入一个较大的数,它需要跟前面的元素进行大量的比较才能找到自己的位置,同时,在到达它的位置的过程中,也进行了大量的数据交换操作。而希尔排序通过加大插入排序中要比较的元素之间的间隔,并对这些有一定间隔的元素进行插入排序,从而可以使得元素大幅度的移动。希尔排序大约需要Θ(n*(lg n)2)时间。
算法大致实现思路:
1.与插入排序不同,比较不再仅局限于相邻元素,而是设置一个间隔h,A[i]与A[i+h]比较,A[i+h]再与A[i+2h]比较,比较的同时将小的元素交换到前面来。
2.逐步减小h至1,最终得到有序数组。
希尔排序比较尴尬的地方在于,这个间隔h怎么取值?

  public static void shellSort(int[] data) {  
        int j = 0;  
        int temp = 0;  
        for (int increment = data.length / 2; increment > 0; increment /= 2) {  
            for (int i = increment; i < data.length; i++) {  
                temp = data[i];  
                for (j = i; j >= increment; j -= increment) {  
                    if(temp > data[j - increment]){  
                        data[j] = data[j - increment];  
                    }else{  
                        break;  
                    }  
                }   
                data[j] = temp;  
            }  
        }  

六、选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。
选择排序法的第一层循环从起始元素开始选到倒数第二个元素,主要是在每次进入的第二层循环之前,将外层循环的下标赋值给临时变量,接下来的第二层循环中,如果发现有比这个最小位置处的元素更小的元素,则将那个更小的元素的下标赋给临时变量,最后,在二层循环退出后,如果临时变量改变,则说明,有比当前外层循环位置更小的元素,需要将这两个元素交换.

public static void selectSort(int[]a)
{
    int minIndex=0;
    int temp=0;
    if((a==null)||(a.length==0))
        return;
    for(int i=0;i<a.length-1;i++)
    {
        minIndex=i;//无序区的最小数据数组下标
        for(intj=i+1;j<a.length;j++)
        {
            //在无序区中找到最小数据并保存其数组下标
            if(a[j]<a[minIndex])
            {
                minIndex=j;
            }
        }
        if(minIndex!=i)
        {
            //如果不是无序区的最小值位置不是默认的第一个数据,则交换之。
            temp=a[i];
            a[i]=a[minIndex];
            a[minIndex]=temp;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值