五大排序

2017-11-06  本文已影响37人  乘瓠散人

1.选择排序
首先找到序列中最小的元素并将它与序列中第一个元素交换,最小元素归位。然后从第二个元素开始扫描,找到剩下n-1个元素中最小的元素与第二个元素交换,将第二小元素归位。以此类推,扫描n-1遍后排序完成。

    private static void selectionSort(int[] a){
        for(int i=0;i<a.length-1;i++){
            int min=i;
            for(int j=i+1;j<a.length;j++){
                if(a[j]<a[min]){
                    min = j;
                }
            }
            swap(a, i, min);
        }
    }

2.冒泡排序
依次比较相邻的两个数,将小数放前,大数放后。即:

第i遍需要扫描的元素下标范围为[0, n-1-i)

 private static void bubbleSort(int[] a){
         for(int i=0;i<a.length-1;i++){
             bool flag=false;
             for(int j=0;j<a.length-1-i;j++){
                 if(a[j]>a[j+1])
                  {
                     swap(a, j, j+1);
                     flag=true;
                  }
             }
             if(flag == false) return; //本趟遍历没有发生交换,说明已经有序
         }
     }

3.插入排序

    private static void insertSort(int[] a){
        for(int i=1;i<a.length;i++){
            int cur = a[i];
            int j = i;
            while(j>0 && cur<a[j-1]){
                a[j] = a[j-1];
                j--;
            }
            a[j]=cur;
        }
    }

4.归并排序
归并排序算法在接近数组中间的位置划分数组,然后使用递归运算对两个一半元素构成的数组进行排序,最后将两个有序子数组进行合并,形成一个新的已排好序的数组。

    private static void mergeSort(int[] a, int left, int right){
        int[] b = new int[a.length];
        mSort(a, b, left, right);
    }
    /*
     * 当left==right时,只有一个元素,之后开始合并,在合并过程中排序;否则递归下去
     */
    private static void mSort(int[] a, int[] b, int left, int right){
        if(left < right){
            int i = (left + right)/2;
            mSort(a, b, left, i);
            mSort(a, b, i+1, right);
            merge(a, b, left, i, right);//合并到数组b
            copy(a, b, left, right);//复制回数组a
        }
    }
    
    //合并a[l:m]和a[m+1:r]到b[l:r]
    private static void merge(int[] a, int[] b, int l, int m, int r){
        int i=l, j=m+1, k=l;
        while(i<=m && j<=r){
            if(a[i]<=a[j]){
                b[k++]=a[i++];
            }else{
                b[k++]=a[j++];
            }
        }
        if(i>m){
            while(j<=r){
                b[k++]=a[j++];
            }
        }else{
            while(i<=m){
                b[k++]=a[i++];
            }
        }

    }
    
    //拷贝数组b中元素到数组a
    private static void copy(int[] a, int[] b, int left, int right){
        for(int i = left; i <= right; i++)
            a[i] = b[i];
    }

5.快速排序
快速排序与合并排序有着很多相似性。将要排序的数组分成两个子数组,通过两次递归调用分别对两个数组进行排序,再将已经排好序的两个数组合并成一个独立的有序数组。但是,将数组一分为二的做法比合并排序中使用的方法复杂。它需要将所有小于或者等于基准元素的元素放置到基准元素前面的位置,将大于基准的元素放置到基准后面的位置。快速排序按照元素值大小拆分,得到两个分区(Partition),拆分处称为分裂点(Split position).

    private static void quickSort(int[] a, int left, int right){
        if(left < right){
            int q = partition(a, left, right);  //q为分裂点,partition为分区函数
            quickSort(a, left, q-1);
            quickSort(a, q+1, right);
        }
    }
    private static int partition(int[] a, int left, int right){
        int p=a[left];
        int i=left+1, j=right;
        while(true){
            while(i<=right && a[i]<p)  //必须把i放在前面,因为i可能超出index
                i=i+1;
            while(j>=left && a[j]>p)
                j=j-1;
            if(i>=j) break;  
            swap(a, i, j);
        }
        swap(a, left, j);
        return j; //返回分裂点下标
    }

    private static void swap(int[] list, int k, int i){
        int temp=list[k];
        list[k]=list[i];
        list[i]=temp;
    }

快速排序扩展:找出n个元素中第k小的元素

//在a[l..r]中寻找第k小的元素
int randomizedSelect(int l,int r,int k)
{
    if(l==r) return a[l];
    int i=randomizedPartition(l,r);
    int j=i-l+1; //计算前面的元素个数
    if(k<=j) return randomizedSelect(l,i,k);
    else return randomizedSelect(i+1,r,k-j);
}
上一篇 下一篇

猜你喜欢

热点阅读