码迷,mamicode.com
首页 > 编程语言 > 详细

学习日志---高级排序算法

时间:2015-09-14 12:28:10      阅读:396      评论:0      收藏:0      [点我收藏+]

标签:java算法

希尔排序

    希尔排序的基本思想是:把待排序的数据元素分成若干个小组,对同一小组内的数据元素用直接插入法排序;小组的个数逐次缩小;当完成了所有数据元素都在一个组内的排序后排序过程结束。希尔排序又称作缩小增量排序。

     选择步长,对每个小的分组进行的直接插入排序。

技术分享

/**
 * 希尔排序:我们选择步长为:15,7,3,1 我们选择步长公式为:2^k-1,2^(k-1)-1,……,15,7,3,1
 * (2^4-1,2^3-1,2^2-1,2^1-1) 注意所有排序都是从小到大排。
 */
public class ShellSort {
 
    /**
     * 排序算法的实现,对数组中指定的元素进行排序
     *
     * @param array
     *            待排序的数组
     * @param from
     *            从哪里开始排序
     * @param end
     *            排到哪里
     * @param c
     *            比较器
     */
    public void sort(Integer[] array, int from, int end) {
        // 初始步长,实质为每轮的分组数
        int step = initialStep(end - from + 1);
 
        // 第一层循环是对排序轮次进行循环。(step + 1) / 2 - 1 为下一轮步长值
        for (; step >= 1; step = (step + 1) / 2 - 1) {
            // 对每轮里的每个分组进行循环
            for (int groupIndex = 0; groupIndex < step; groupIndex++) {
 
                // 对每组进行直接插入排序
                insertSort(array, groupIndex, step, end);
            }
        }
    }
 
    /**
     * 直接插入排序实现
     *
     * @param array
     *            待排序数组
     * @param groupIndex
     *            对每轮的哪一组进行排序
     * @param step
     *            步长
     * @param end
     *            整个数组要排哪个元素止
     * @param c
     *            比较器
     */
    public void insertSort(Integer[] array, int groupIndex, int step, int end) {
        int startIndex = groupIndex;// 从哪里开始排序
        int endIndex = startIndex;// 排到哪里
        /*
         * 排到哪里需要计算得到,从开始排序元素开始,以step步长,可求得下元素是否在数组范围内,
         * 如果在数组范围内,则继续循环,直到索引超现数组范围
         */
        while ((endIndex + step) <= end) {
            endIndex += step;
        }
 
        // i为每小组里的第二个元素开始
        for (int i = groupIndex + step; i <= end; i += step) {
            for (int j = groupIndex; j < i; j += step) {
                Integer insertedElem = array[i];
                // 从有序数组中最一个元素开始查找第一个大于待插入的元素
                if ((array[j].compareTo(insertedElem)) >= 0) {
                    // 找到插入点后,从插入点开始向后所有元素后移一位
                    move(array, j, i - step, step);
                    array[j] = insertedElem;
                    break;
                }
            }
        }
    }
 
    /**
     * 根据数组长度求初始步长
     *
     * 我们选择步长的公式为:2^k-1,2^(k-1)-1,...,15,7,3,1 ,其中2^k 减一即为该步长序列,k 为排序轮次
     *
     * 初始步长:step = 2^k-1 初始步长约束条件:step < len - 1 初始步长的值要小于数组长度还要减一的值(因
     * 为第一轮分组时尽量不要分为一组,除非数组本身的长度就小于等于4)
     *
     * 由上面两个关系试可以得知:2^k - 1 < len - 1 关系式,其中k为轮次,如果把 2^k 表 达式 转换成 step 表达式,则
     * 2^k-1 可使用 (step + 1)*2-1 替换(因为 step+1 相当于第k-1 轮的步长,所以在 step+1 基础上乘以 2
     * 就相当于 2^k 了),即步长与数组长度的关系不等式为 (step + 1)*2 - 1 < len -1
     *
     * @param len
     *            数组长度
     * @return
     */
    public static int initialStep(int len) {
        /*
         * 初始值设置为步长公式中的最小步长,从最小步长推导出最长初始步长值,即按照以下公式来推:
         * 1,3,7,15,...,2^(k-1)-1,2^k-1
         * 如果数组长度小于等于4时,步长为1,即长度小于等于4的数组不用分组,此时直接退化为直接插入排序
         */
        int step = 1;
 
        // 试探下一个步长是否满足条件,如果满足条件,则步长置为下一步长
        while ((step + 1) * 2 - 1 < len - 1) {
            step = (step + 1) * 2 - 1;
        }
 
        System.out.println("初始步长 : " + step);
        return step;
    }
 
    /**
     * 以指定的步长将数组元素后移,步长指定每个元素间的间隔
     *
     * @param array
     *            待排序数组
     * @param startIndex
     *            从哪里开始移
     * @param endIndex
     *            到哪个元素止
     * @param step
     *            步长
     */
    protected final void move(Integer[] array, int startIndex, int endIndex,
            int step) {
        for (int i = endIndex; i >= startIndex; i -= step) {
            array[i + step] = array[i];
        }
    }
 
    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
        Integer[] intgArr = { 65, 34, 25, 87, 12, 38, 56, 46, 14, 77, 92, 23 };
        ShellSort shellSort = new ShellSort();
        shellSort.sort(intgArr, 0, intgArr.length - 1);
        for (Integer intObj : intgArr) {
            System.out.print(intObj + " ");
        }
    }
}

快速排序

    快速排序的基本思想:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。把整个序列看做一个数组,把第零个位置看做中轴,和最后一个比,如果比它小交换,比它大不做任何处理;交换了以后再和小的那端比,比它小不交换,比他大交换。这样循环往复,一趟排序完成,左边就是比中轴小的,右边就是比中轴大的,然后再用分治法,分别对这两个独立的数组进行排序。

    是一种快速的交换排序

技术分享

自己写出的:

import java.util.Arrays;

public class Test {
   
    public static void main(String[] args) {
        int[] array = {49,38,65,97,76,13,27,33,25,78,1,10,23,34,97};
        int start = 0;
        int end = array.length-1;
        quickSort(array,start,end);
    
        System.out.println(Arrays.toString(array));
    }

    public static void quickSort(int[] array , int head ,int bottom)
    {
        if(head==bottom)
            return;
        int start = head;
        int end = bottom;
        int pivot = array[start];
        while(start<end)
        {
            if(array[start]==pivot)
            {
                for(;end>start;end--)
                {
                    if(array[end]<array[start])
                    {
                        int temp = array[end];
                        array[end] = array[start];
                        array[start] = temp;
                        break;
                    }
                }
            }else {
                for(;start<end;start++)
                {
                    if(array[end]<array[start])
                    {
                        int temp = array[end];
                        array[end] = array[start];
                        array[start] = temp;
                        break;
                    }
                }
            }
        }
        int middle = start;
        System.out.println("one lun: " + pivot + "..." + end);
        if(head<middle)
        {
            quickSort(array, head, middle-1);
        }
        if(bottom>middle)
        {
            quickSort(array, middle+1, bottom);
        }
    }
}

参考的:

import java.util.Arrays;
//快速排序算法
public class QuickSort {
    public static void quickSort(int arr[], int low, int high) 
    {
        if(low < high) 
        {
            //按照第一个数进行切分。左边放小于【0】的数,右边放大于[0]的数
           int mid = partition(arr, low, high);
            //对关键字左边的数据进行分区
           quickSort(arr, low, mid - 1);
            //对关键字右边的数据进行分区
           quickSort(arr, mid + 1, high);
        }
    }
    public static int partition(int array[], int low, int high) {
        // 设置两个变量i、j,排序开始的时候i:=0,j:=N-1;
        // 以第一个数组元素作为关键数据,赋值给pivotKey,即pivotKey:=array[0];
        int pivotKey = array[low];
        int i= low, j = high;
        if(low < high) 
        {
           while (i < j) 
           {
               // 从J开始向前搜索,即由后开始向前搜索(J:=J-1),找到第一个小于X的值,两者交换;
               while (i < j && array[j] >= pivotKey) 
               {
                   j--;
               }
               if (i < j) 
               {
                   array[i] = array[j];
                   i++;
               }
               // 从I开始向后搜索,即由前开始向后搜索(I:=I+1),找到第一个大于X的值,两者交换;
               while (i < j && array[i] <= pivotKey) 
               {
                   i++;
               }
               if (i < j) 
               {
                   array[j] = array[i];
                   j--;
               }
            }
            array[i] = pivotKey;
            //打印每次分区后的结果
            System.out.println("每次排序:" + Arrays.toString(array));
            //将这个分区结束时的坐标i返回,用于下次执行时当做前分区的尾坐标,当做后分区的头坐标
        }
        return i;
    }
     public static void main(String[] args)
    {
        int[] list={49,38,65,97,76,13,27,49};  
        System.out.println("排序前:" +Arrays.toString(list));
        quickSort(list, 0, list.length - 1);
        System.out.println("排序后:" + Arrays.toString(list));
    }
}


堆排序

      在直接选择排序中,放在数组中的n个数据元素排成一个线性序列(即线性结构),要从有n个数据元素的数组中选择出一个最小的数据元素需要比较n-1次。如果能把待排序的数据元素集合构成一个完全二叉树结构,则每次选择出一个最大(或最小)的数据元素只需比较完全二叉树的高度次,即log2n次,则排序算法的时间复杂度就是O(nlog2n)。这就是堆排序的基本思想。

      最大堆的定义如下:
      设数组a中存放了n个数据元素,数组下标从0开始,如果当数组下标2i+1<n时有:a[i]≥a[2i+1];如果当数组下标2i+2<n时有:a[i]≥a[2i+2],则这样的数据结构称为最大堆。

      图说明见附件

//堆排序算法
public class HeapSort {
    
      //带入数组,n是最大长度额下标,h是起点
      //因为初始化下已经是最大堆,头和尾交换后,只需把新的头加入到树的最小端即可,树还是保持最大堆
      public static void createHeap(int[] a, int n, int h) 
      {
        int i, j, flag;
        int temp;

        i = h; // i为要建堆的二叉树根结点下标
        j = 2 * i + 1; // j为i结点的左孩子结点的下标
        temp = a[i];
        flag = 0;

        // 沿左右孩子中值较大者重复向下筛选
        while (j < n && flag != 1) {
            // 寻找左右孩子结点中的较大者,j为其下标
            if (j < n - 1 && a[j] < a[j + 1])
            {
               j++;
            }
            // 标记结束筛选条件
            if (temp > a[j]) 
                flag = 1; 
            else { 
                // 否则把a[j]上移
                a[i] = a[j];
                i = j;
                j = 2 * i + 1;
            }
        }
        a[i] = temp; // 把最初的a[i]赋予最后的a[j]
    }

    //初始化数组,使其对应的二叉树是最大堆,初始化下二叉树是最大堆的情况
    public static void initCreateHeap(int[] a) {
        int n = a.length;
        for (int i = (n - 1) / 2; i >= 0; i--)
            createHeap(a, n, i);
    }

    public static void heapSort(int[] a) {
        int temp;
        int n = a.length;

        initCreateHeap(a); // 初始化创建最大堆

        for (int i = n - 1; i > 0; i--) { 
            // 当前最大堆个数每次递减1
            // 把堆顶a[0]元素和当前最大堆的最后一个元素交换
            temp = a[0];
            a[0] = a[i];
            a[i] = temp;
            //交换后,把交换的头在向下找最大的,换上去,形成最大堆
            createHeap(a, i, 0); // 调整根结点满足最大堆
        }
    }

    public static void main(String[] args) {
        int[] test = { 10, 50, 32, 5, 76, 9, 40, 88 };
        int n = test.length;
        heapSort(test);
        for (int i = 0; i < n; i++)
            System.out.print(test[i] + "  ");
    }
}

这是一种基于二叉树的排序。


归并排序

技术分享

//归并排序算法
public class MergeSort {
    
    //归并排序算法
    public static void merge(int[] a, int[] swap, int k) {
        int n = a.length;
        int m = 0, u1, l2, i, j, u2;
        int l1 = 0; // 第一个有序子数组下界为0
        //l1为第一组最小,u1为第一组最大,l2为第二组最小,u2为第二组最大
        while (l1 + k <= n - 1) {
            l2 = l1 + k; // 计算第二个有序子数组下界
            u1 = l2 - 1; // 计算第一个有序子数组上界
            u2 = (l2 + k - 1 <= n - 1) ? l2 + k - 1 : n - 1; // 计算第二个有序子数组上界

            //循环找最小的插入到swap中
            for (i = l1, j = l2; i <= u1 && j <= u2; m++) {
                if (a[i] <= a[j]) {
                    swap[m] = a[i];
                    i++;
                } else {
                    swap[m] = a[j];
                    j++;
                }
            }

            // 子数组2已归并完,将子数组1中剩余的元素存放到数组swap中
            while (i <= u1) {
                swap[m] = a[i];
                m++;
                i++;
            }

            // 子数组1已归并完,将子数组2中剩余的元素存放到数组swap中
            while (j <= u2) {
                swap[m] = a[j];
                m++;
                j++;
            }

            l1 = u2 + 1;
        }

        // 将原始数组中只够一组的数据元素顺序存放到数组swap中
        for (i = l1; i < n; i++, m++)
        {
            swap[m] = a[i];
        }
    }

    public static void mergeSort(int[] a) {
        int i;
        int n = a.length;
        int k = 1; // 归并长度从1开始
        int[] swap = new int[n];

        while (k < n) {
        
            //k是每组的长度
            merge(a, swap, k); // 调用函数merge()
            for (i = 0; i < n; i++)
            {
                a[i] = swap[i]; // 将元素从临时数组swap放回数组a中
            }
            
            //每次长度增为2倍
            k = 2 * k; // 归并长度加倍
        }
    }

    public static void main(String[] args) {
        int[] test = { 72, 73, 71, 23, 94, 16, 5, 68, 64 };
        int n = test.length;
        mergeSort(test);
        for (int i = 0; i < n; i++)
            System.out.print(test[i] + "  ");
    }
}


基数排序

//基数排序算法

public class RadixSort{
    
public static void radixSort(int[] a, int m, int d) throws Exception{
    //a为要排序的数据元素,d为进制的基数,m为数据元素的最大位数
    int n = a.length;
    int i, j, k, l, power = 1;
    Queue<Integer>[] myQueue = new LinkedList[d];
            
    //创建链式队列数组对象
    for(i = 0; i < d; i++){
        Queue<Integer> temp = new LinkedList<Integer>();
        myQueue[i] = temp;
    }
        
    //进行m次排序
    for(i = 0; i < m; i++){
        if(i==0) 
            power = 1;
        else 
            power = power * d;
        
        //依次将n个数据元素按第k位的大小放到相应的队列中
        for(j = 0; j < n; j++)
        {
            k = a[j] / power - (a[j] / (power * d)) * d;    //计算k值
            myQueue[k].add(new Integer(a[j]));            // a[j]入队列k
        }

        //顺序回收各队列中的数据元素到数组a中
        l = 0;
        for(j = 0; j < d; j++){
            while(!myQueue[j].isEmpty()){
                a[l] = ((Integer)myQueue[j].remove()).intValue();
                l++;
            }
        }
    }
}
    
    public static void main(String[] args){
        int[] test = {710,342,45,686,6,841,429,134,68,264};
        int n = test.length;
        int m = 3, d = 10;
        
        try{
            radixSort(test, m, d);
        }
        catch (Exception e){
            e.printStackTrace();
        }
        for(int i = 0; i < n; i++)
            System.out.print(test[i] + "  ");
    }
}


学习日志---高级排序算法

标签:java算法

原文地址:http://wukong0716.blog.51cto.com/10442773/1694440

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!