Java内排序算法二

6.归并排序

  • 思想:运用分治法思想先使每个子序列有序,再将两个已经排序的序列合并成一个序列的操作。若将两个有序表合并成一个有序表,称为二路归并。
  • 时间复杂度:平均、最佳、最差时间复杂度均为O(nlgn)
  • 代码如下:一般用递归求解:
package xianggen.sortsummary;
/**
 * 
 * MergeSort.java
 * @author xianggen
 * @date 2016年7月25日 下午3:31:00
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] arr={3,5,7,1,4,2,8,9,0,6};
        recursiveMergeSort(arr,0,arr.length-1);

        for(int i=0;i<arr.length;i++)
            System.out.print(arr[i]+" ");
        System.out.println();
    }

     public static int[] recursiveMergeSort(int[] arr, int low, int high) {  
            int mid = (low + high) / 2;  
            if (low < high) {  
                // 左边  
                recursiveMergeSort(arr, low, mid);  
                // 右边  
                recursiveMergeSort(arr, mid + 1, high);  
                // 左右归并  
                merge(arr, low, mid, high);  
            }  
            return arr;  
        }  

        public static void merge(int[] arr, int low, int mid, int high) {  
            int[] temp = new int[high - low + 1];  
            int i = low;// 左指针  
            int j = mid + 1;// 右指针  
            int k = 0;  

            // 把较小的数先移到新数组中  
            while (i <= mid && j <= high) {  
                if (arr[i] < arr[j]) {  
                    temp[k++] = arr[i++];  
                } else {  
                    temp[k++] = arr[j++];  
                }  
            }  

            // 把左边剩余的数移入数组  
            while (i <= mid) {  
                temp[k++] = arr[i++];  
            }  

            // 把右边边剩余的数移入数组  
            while (j <= high) {  
                temp[k++] = arr[j++];  
            }  

            // 把新数组中的数覆盖arr数组  
            for (int k2 = 0; k2 < temp.length; k2++) {  
                arr[k2 + low] = temp[k2];  
            }  
        }  
}

7.堆排序

二叉堆:二叉堆是完全二叉树或者是近似完全二叉树。

父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

每个结点的左子树和右子树都是一个二叉堆。

其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。堆排序是原址排序,同快排,空间开销小!

  • 思想:初始时把要排序的n个数的序列看作是一棵顺序存储的完全二叉树(一维数组存储二叉树),调整它们的存储序,使之成为一个堆,将堆顶元素输出,得到n 个元素中最小(或最大)的元素,这时堆的根节点的数最小(或者最大)。然后对前面(n-1)个元素重新调整使之成为堆,输出堆顶元素,得到n 个元素中次小(或次大)的元素。依此类推,直到只有两个节点的堆,并对它们作交换,最后得到有n个节点的有序序列。称这个过程为堆排序。
  • 时间复杂度:平均、最佳、最差时间复杂度均为O(nlogn )
  • **代码如下:实现堆排序需解决两个问题:1. 如何将n 个待排序的数建成堆;2. 输出堆顶元素后,怎样调整剩余n-1 个元素,使其成为一个新堆。

先上图解:
这里写图片描述

package xianggen.sortsummary;
/**
 * 堆排序!
 * 两个过程:建堆,堆顶与堆的最后一个元素交换位置
 * HeapSort.java
 * @author xianggen
 * @date 2016年8月16日 上午10:18:14
 */
public class HeapSort {
    public static void main(String[] args) {
        int[] arr={3,5,7,1,4,2,8,9,0,6};
        heapSort(arr,arr.length);
        printHeap(arr);

    }
    public static void heapSort(int[] arr,int length){
        buildHeap(arr,length);
        for(int i=arr.length-1;i>0;i--){
            swap(arr,0,i);
            heapAdjust(arr,0,i);
        }
    }

    /**
     * 堆初始数组建最大堆! 
     * arr[0..length-1]建成堆 ,其中arr[0]为最大值,将其与arr[length-1]交换
     * @param arr,length
     */
    public static void buildHeap(int[] arr,int length){
        //!!! 从最后一个有孩子的节点的位置开始堆调整: i= (length -1) / 2  
        for(int i=(length-1)/2;i>=0;i--){
              heapAdjust(arr,i,length);         
        }
    }

    /**
     * 这是堆排序的关键操作!!功能将一个节点拖拽至子树的合适位置!
     * @param arr
     * @param index
     * @param length
     */
    public static void heapAdjust(int[]arr, int index,int length){
        int tmp=arr[index],child=2*index+1;  //左孩子结点的位置
        while(child<length){
            if(child+1<length&&arr[child]<arr[child+1]){
                child++;    //如果位于index的节点有右孩子且其值比左孩子大,则得到右孩子的索引值
            }
            if(arr[index]<arr[child]){   // 若父节点小于孩子(较大的),则把父节点拖拽下来
                arr[index]=arr[child];
                index=child;
                child=2*index+1;    //注意这个更新,千万不要忘记。(保持刚开始时child指向的是左孩子)
            }else{
                break;   //!!! 如果当前待调整结点大于它的左右孩子,则不需要调整,直接退出 
            }
            arr[index]=tmp;   // 当前待调整的结点放到比其大的孩子结点位置上  
        }
    }

    public static void swap(int[] arr,int i,int j){
        int tmp=arr[i];
        arr[i]=arr[j];
        arr[j]=tmp;
    }

    public static void printHeap(int[] arr){
        for(int i=0;i<arr.length;i++)
            System.out.print(arr[i]+" ");
        System.out.println();
    }

}

8.计数排序

http://www.cnblogs.com/eaglet/archive/2010/09/16/1828016.html

计数排序是一个类似于桶排序的排序算法,其优势是对已知数量范围的数组进行排序。它创建一个长度为这个数据范围的数组C,C中每个元素记录要排序数组中对应记录的出现个数。这个算法于1954年由 Harold H. Seward 提出。

依靠一个辅助数组来实现,不基于比较,算法复杂度为 O(n) ,但由于要一个辅助数组C,所以空间复杂度要大一些,由于计算机的内存有限,这种算法不适合范围很大的数的排序。

最坏情况运行时间:O(n+k);最好情况运行时间:O(n+k),k为待排数组中的最大值。

看一个例子:
这里写图片描述

/**
 * 
 * CountingSort.java
 * @author xianggen
 * @date 2016年8月16日 下午2:51:08
 */
public class CountingSort {
    public static void main(String[] args) {
        int[] arr={3,3,7,1,4,2,8,19,0,6};
        int[] res=countSort(arr);
        printHeap(res);

    }

    public static int[] countSort(int[] arr){
        int max=arr[0];
        for(int i=1;i<arr.length;i++)
            if(arr[i]>max)
                max=arr[i];
        int[] tmpArr=new int[max+1];
        int[] res=new int[arr.length];

        for(int i=0;i<arr.length;i++)
            tmpArr[arr[i]]++;   //此时res[i]表示等于i的元素个数  

        for(int i=1;i<=max;i++)
            tmpArr[i]+=tmpArr[i-1]; //此时res[i]表示小于或者等于i的元素个数 
        // 把输入数组中的元素放在输出数组中对应的位置
        for(int i=arr.length-1;i>=0;i--){
            res[tmpArr[arr[i]]-1]=arr[i]; // 用tmpArr数组来确定arr[i]的下标!
            tmpArr[arr[i]]--; // 该操作使得下一个值为arr[i]的元素直接进入输出数组中arr[i]的前一个位置  
        }
        return res;
    }

8.基数排序

http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html

这里写图片描述

根据从低位还是从高位开始排序,基数排序分为两种:LSD(Least significant digital)或MSD(Most significant digital)
这里写图片描述

待排数组:73 22 93 43 55 14 28 65 39 81
使用LSD排序:先根据个位数的数值,在遍历数据时将它们各自分配到编号0至9的桶(个位数值与桶号一一对应)中;接着根据十位数值再进行一次分配。
这里写图片描述

每位基于计数排序

package xianggen.sortsummary;
/**
 * 基数排序,假定每位的排序是计数排序
 * RadixSort.java
 * @author xianggen
 * @date 2016年8月16日 下午5:34:48
 */
public class RadixSort {
    public static void main(String[] args) {
        int[] arr={3,3,7,1,4,2,8,11,0,6};
        radixSort(arr);
    }

    public static void radixSort(int[] arr){
        int d=getOffset(arr);
        int radix=10;
        int[] count=new int[radix];
        int[] bucket=new int[arr.length];

        // 按照从低位到高位的顺序执行排序过程
        for(int i=0;i<d;i++){

            // 置空各个桶的数据统计,这个操作一定不能忘记!
            for (int j=0; j<radix; j++) {
                count[j] = 0;
            }
            // 统计各个桶将要装入的数据个数
            for(int j=0;j<arr.length;j++){
                count[getDigit(arr[j],i)]++;
            }

            for(int j=1;j<radix;j++)
                count[j]=count[j]+count[j-1];
            // 将数据依次装入桶中,从右向左扫描,保证排序稳定性
            for(int j=arr.length-1;j>=0;j--){
                int index=getDigit(arr[j],i);
                bucket[count[index]-1]=arr[j];
                count[index]--;
            }
            // 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表
            for(int j=0;j<bucket.length;j++)
                arr[j]=bucket[j];
        }
        for(int j=0;j<bucket.length;j++)
            System.out.print(arr[j]+" ");
        System.out.println();
    }

    /**
     * 获取数组中元素中最大的位数!
     * @param arr
     * @return
     */
    public static int getOffset(int[] arr){
        int result=1;
        for(int i=0;i<arr.length;i++){
            int tmp=1,k=10;
            while(arr[i]>=k){
                k*=10;
                tmp++;
            }
            if(tmp>result)
                result=tmp;
        }
        return result;
    }
    /**
     * // 获取number这个数的(d+1)位数上的数字,从右往左开始(个位计起)
     * @param number
     * @param d
     * @return
     */
    public static int getDigit(int number,int d){
        int a[]={1,10,100};
        return ((number/a[d])%10);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值