常用排序(插入、堆、归并)

一、插入排序

直接插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止。

对于一个数组a[n]来说,第一次a[0]就构成了已拍好序的子序列,而a[2]~a[n-1]为待排序的序列。每次插入即将a[i]插入到已经排好序的子序列a[0]~a[i-1]中,如此进行n-1次插入即可。

代码实现:

public void insertSort(int[] a,int n){
    int j,k,temp;
    for(int i=1;i<n;i++){
        //找到a[i]元素所要插入的位置,即j+1
        for(j=i-1;j>=0;j--){
            if(a[j]<=a[i])
                break;
        }

        if(j!=i-1){//若j=i-1则说明a[i]就在i位置上
            temp = a[i];
            //将数组中j之后的元素向后移动一位
            for(k=i;k>j+1;k--){
                a[k] = a[k-1];
            }
            a[j+1] = temp;//插入元素原a[i]

        }
    }
}

二、堆排序

堆排序分为大顶堆和小顶堆。堆排序不适合元素较少情况。堆排序在最好最坏的情况下,其时间复杂度均为O(nlogn)。相对于快速排序来说,这是堆排序的最大优点。此外,堆排序仅需一个记录大小的供交换用的辅助存储空间。

1、构造初始堆:
先将无序数组构成二叉树。然后对此二叉树进行调整,从下标为i=n/2的节点开始考虑(因为此节点是下标最大的非叶子节点),判断此节点与其左右节点三者之间最大的值,将其交换到父节点的位置上,如此直至i=0(根节点)调整后就会得到一个顶部为最大值的堆,即为初始堆了。
2、进行堆排序 将堆顶元素输出并与堆最后一个元素交换,此时有序区的长度即为1,然后继续调整堆
直至有序区的长度为n-1时即元素也全部有序输出了,堆排序结束。

代码实现:

public class HeapClass {

    //sortHeap 堆排序主方法
    public  void sortHeap(int[] A,int n){
        if (A == null || A.length <= 1) {  
            return;  
        }

        buildHeap(A, n);//建初始堆
        for (int i = n-1; i >= 1; i--) {
            swap(A,i,0);//将堆顶元素与堆第i个元素交换

            //【重要】:从根节点开始调,未排序序列大小为i
            adjustHeap(A,0,i);
        }
    }

    //buildHeap 建立初始堆
    public  void buildHeap(int[] A,int n){
         if (A == null || A.length <= 1) {  
             return;  
         } 

        for (int i = n/2; i >= 0; i--) {//从最后一个非叶子节点开始调整
            adjustHeap(A, i, n);
        }
    }

    //adjustHeap 调整堆
    public  void adjustHeap(int[] A,int i,int n){
        int max = i;

        if((2*i+1<n)&&A[2*i+1]>A[max]){
            max = 2*i+1;
        }
        if((2*i+2<n)&&A[2*i+2]>A[max]){
            max = 2*i+2;
        }
        if(max!=i){
            swap(A,i,max);
            //交换后检查子堆是否满足
            adjustHeap(A,max,n);
        }
    }

    //交换元素
    public  void swap(int[] A,int i,int j){
        A[i] = A[i] + A[j];
        A[j] = A[i] - A[j];
        A[i] = A[i] - A[j];
    }


    public static void main(String args[]){

    //  int[] A = {2,6,3,1,1,9,7,4,5};
    //  int n = A.length;   
    //  sortHeap(A, n); 

    }
}

3、归并排序

归并排序基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。为了达到合并的两个序列有序,可以将A,B组各自分成二组,依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。归并排序的效率比较高.

代码实现:

public class MergeSort {

    private  int[] temp;
    //合并两个已经有序的序列,即数组a[]以mid为中点的左右两边
    public void mergeArray(int A[], int first, int mid, int last)  
    {  
        int lFirst = first, rFirst = mid + 1;  
        int m = mid,n = last,k = 0;  

        //判断是否两个序列都有剩余时
        while (lFirst <= m && rFirst <= n){  
            if (A[lFirst] <= A[rFirst]){  
                temp[k++] = A[lFirst++];  
            }else{  
                temp[k++] = A[lFirst++];  
            }
        }  
        //判断是否左/右存在剩余元素,并将剩余元素直接加在temp[]数组的后面
        while (lFirst <= m)  
            temp[k++] = A[lFirst++];  

        while (rFirst <= n)  
            temp[k++] = A[rFirst++];  
        //将temp存的合并后的序列赋给a[]相应位置
        for (int i = 0; i < k; i++){  
            A[first + i] = temp[i];
        }

    }  

    //主归并类
    public void mergeSort(int A[], int first, int last)  
    {  
        if (first < last)  
        {  
            int mid = (first + last)/2;  
            mergeSort(A, first, mid);    //得到左边有序  
            mergeSort(A, mid + 1, last); //得到右边有序

            mergeArray(A, first, mid, last); //再将二个有序数列合并  
        }  
    }

    public static void main(String args[]){

    //  int[] A = {2,6,3,1,1,9,7,4,5};
    //  int n = A.length;
    //  mergeSort(A,0,n-1);

    }
}

猜你喜欢

转载自blog.csdn.net/kiddingboy_wjj/article/details/50937381