• Java学习笔记——排序算法之进阶排序(堆排序与分治并归排序)


    春蚕到死丝方尽,蜡炬成灰泪始干

                  ——无题

    这里介绍两个比较难的算法:

    1、堆排序

    2、分治并归排序

    先说堆。

    这里请大家先自行了解完全二叉树的数据结构。

    堆是完全二叉树。大顶堆是在堆中,任意双亲值都大于(或等于)其孩子值,就称其为大顶堆。

    堆排序的步骤:

    1、把数组想象成一个堆。数组的index+1就是其对应在堆中的序号

    2、调堆中各值的顺序,得到大顶堆

    3、将堆首位值与堆末尾值交换,最大值排序完毕

    4、将堆得大小减1,重复步骤2和步骤3,直到堆中只剩下一个元素。排序完毕

    上代码:

     1 public class HeapSort {
     2 
     3     public static void heapSort(int[] arr){
     4         //建立完全二叉树,从最后一个双亲开始调整双亲值,直到根,调整完毕后大顶堆建立完成
     5         for (int i = arr.length >> 1; i > 0; i --) {
     6             heapAdjust(arr, i, arr.length);//调用堆要从1到length才符合堆的定义
     7         }
     8         //堆顶和堆低交换,获取最大值,然后调整大顶堆
     9         for (int i = arr.length - 1; i > 0; i--) {
    10             arr[i] = arr[i]^arr[0];
    11             arr[0] = arr[i]^arr[0];
    12             arr[i] = arr[i]^arr[0];
    13             heapAdjust(arr, 1, i);//因为堆计数要从1开始,所以size = endIndex + 1
    14         }
    15     }
    16     //调整大顶堆.先找左子,然后和右子比,取值大的,在和双亲自己比,自己比儿子大,break,否则交换.注意:根要从1开始才能找到左子
    17     public static void heapAdjust(int[] arr, int parents, int size){
    18         int j;//孩子们的标记是j,索引全部-1
    19         int i = parents;//双亲是i,索引全部-1
    20         while (i << 1 <= size) {
    21             j = i << 1;//左子
    22             if (j + 1 <= size) {//有右子
    23                 if (arr[j - 1] < arr[j + 1 -1])
    24                     j ++;
    25             }
    26             if (arr[i - 1] > arr[j - 1])
    27                 break;
    28             arr[i-1] = arr[i-1]^arr[j-1];
    29             arr[j-1] = arr[i-1]^arr[j-1];
    30             arr[i-1] = arr[i-1]^arr[j-1];
    31             i = j;//儿子变为父亲,这里不知道是左子还是右子,所以不能直接通过for循环的迭代步骤<<i调整i值,如果是右子的话就错了(右子<<1+1)
    32         }
    33     }
    34 }

    再说分治并归排序

    这里先要了解什么是递归

     1 public class MergingTest {
     2 
     3     public static void main(String[] args) {
     4         mSort(0, 3);
     5     }
     6     private static void mSort(int left, int right) {
     7         int m = (left + right)/2;
     8         if (left == right) {
     9             System.out.println(left);
    10             return;
    11         }
    12         mSort(left, m);
    13         mSort(m+1, right);
    14     }
    15 }

    这几行代码是并归算法的核心。运行代码将输出0123456789,虽然看上去很简单,但是如果真能明白,说明你已经完全理解递归的思想了,写出并归算法也就不在话下了。

    为什么会输出0123呢?

    代码执行的走向:1→2→4→2→5→2→1→3→6→3→7→3→1→return

    能领悟这个东西就好办了,上代码:

     1 public class MergingSort {
     2 
     3     public static void mergingSort(int[] arr) {
     4         int[] temp = new int[arr.length];
          //temp是相当于一张牌,通过left,m,right在逻辑上分成两个数组,进行分治排序,arr是原数组,对数组排序不传数组怎么行?!
    5 mSort(arr, temp, 0, arr.length-1); 6 } 7 private static void mSort(int[] arr, int[] temp, int left, int right) {
          //这里的分组逻辑没有使用到temp和arr,而是把它们作为参数传入merge方法
    8 int m = (left+right)/ 2; 9 if (left == right) { 10 return; 11 } 12 mSort(arr, temp, left, m); 13 mSort(arr, temp, m+1, right); 14 merge(arr,temp,left,m,right); 15 } 16 private static void merge(int[]arr, int[] temp, int left, int m, int right) {
          //分治排序极其简单,已知两个有序数组,要把他们合并成一个有序数组,用什么方法都不用说,大家一想就知道了。
    17 for (int c = 0;c < arr.length;c++){ 18 temp[c] = arr[c]; 19 } 20 for (int p = 0; p < temp.length; p++) { 21 System.out.println("temp["+p+"] = " + temp[p]); 22 } 23 int i = left; 24 int j = m + 1; 25 int k = left; 26 while (i<=m && j<=right) {
            //使用分支结构,把每摞牌最小的那个挑出来给arr
    27 if (temp[i] < temp[j]) { 28 arr[k++] = temp[i++]; 29 } 30 if (temp[j] < temp[i]) { 31 arr[k++] = temp[j++]; 32 } 33 }
            //使用分支结构,把剩下的那摞牌都塞给arr
    34 if (i > m) { 35 while (j <= right) { 36 arr[k++] = temp[j++]; 37 } 38 } 39 if (j > right) { 40 while (i <= m) { 41 arr[k++] = temp[i++]; 42 } 43 } 44 } 45 46 }
  • 相关阅读:
    第一次冲刺个人博客03
    第一次冲刺个人博客02
    《梦断代码》阅读笔记01
    “进度条”博客——第十一周
    “进度条”博客——第十周
    “进度条”博客——第九周
    站立会议个人博客10(2016/4/28)
    站立会议个人博客9(2016/4/27)
    站立会议个人博客8(2016/4/26)
    站立会议个人博客7(2016/4/25)
  • 原文地址:https://www.cnblogs.com/tomasman/p/6846607.html
Copyright © 2020-2023  润新知