zoukankan      html  css  js  c++  java
  • 排序---初级排序算法(选择排序、插入排序和希尔排序)

    写在前面的话:

    一枚自学Java和算法的工科妹子。

    • 算法学习书目:算法(第四版) Robert Sedgewick
    • 算法视频教程:Coursera  Algorithms Part1&2

    本文是根据《算法(第四版)》的个人总结,如有错误,请批评指正。

    一、排序算法介绍

    1.排序算法的目的:将所有元素的主键(如学生类,主键可以是姓名、学号、年龄等)按照某种方式排列(通常按照大小或字母排序)。

    2.排序算法类模板:sort()排序方法;less()元素比较;exch()元素交换位置;show()打印字符数组内容;isSorted()判断元素是否有序。

     1 public class Example {
     2 
     3     private Example () { }
     4 
     5     public static void sort(Comparable[] a) {
     6       // 选择排序、插入排序、希尔排序、归并排序、快速排序,实现Comparable接口
     7     }
     8     public static void sort(Object[] a, Comparator comparator) {
     9       //  数据类型中定义内部类实现Comparator
    10     }
    11 
    12     // 判断元素大小
    13     private static boolean less(Comparable v, Comparable w) {
    14         return v.compareTo(w) < 0;
    15     }
    16     private static boolean less(Comparator comparator, Object v, Object w) {
    17         return comparator.compare(v, w) < 0;
    18     }
    19 
    20     // 交换元素位置
    21     private static void exch(Object[] a, int i, int j) {
    22         Object swap = a[i];
    23         a[i] = a[j];
    24         a[j] = swap;
    25     }
    26 
    27     // 判断元素是否已排序
    28     private static boolean isSorted(Comparable[] a, int lo, int hi) {
    29         for (int i = lo + 1; i <= hi; i++)
    30             if (less(a[i], a[i-1])) return false;
    31         return true;
    32     }
    33 
    34     private static boolean isSorted(Object[] a, Comparator comparator, int lo, int hi) {
    35         for (int i = lo + 1; i <= hi; i++)
    36             if (less(comparator, a[i], a[i-1])) return false;
    37         return true;
    38     }
    39 
    40     // 打印字符数组内容
    41     private static void show(Comparable[] a) {
    42         for (int i = 0; i < a.length; i++) {
    43             StdOut.println(a[i]);
    44         }
    45     }
    46 }

    3.排序算法需要注意的问题

    • 验证:在测试代码中添加一条语句 assert isSorted(a) 来确认排序后数组元素都是有序的。
    • 运行时间:在研究排序算法时,我们需要计算比较和交换的数量。对于不交换元素的算法,我们会计算访问数组的次数。
    • 额外的内存使用:(1)原地排序算法:除了函数调用所需的栈和固定数目的实例变量之外无需额外内存;(2)其他排序算法:需要额外内存空间来存储另一份数组副本。
    • 数据类型:上述排序算法模板使用与实现了Comparable接口或者在类中定义了内部类实现Comparator接口的数据类型。Java中Integer、Double、String、File、URL等数据类型都实现了Comparable接口。当然也可以自己设计数据类型实现Comparable接口,实现compareTo()方法来自定义目标类型对象的自然次序。可参考Comparable和Comparator区别(实现和使用)

    二、初级排序算法

    1. 选择排序介绍

    1.1 选择排序算法流程

    Step1:从待排序序列中,找到关键字最小的元素;

    Step2:如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;

    Step3:从余下的 N - 1 个元素中,找出关键字最小的元素,重复Step1和Step2,直到排序结束。

    图1 选择排序的轨迹

    1.2 选择排序算法代码实现

     1 import java.util.Comparator;
     2 
     3 public class Selection {
     4 
     5     private Selection() { }
     6 
     7     public static void sort(Comparable[] a) {
     8         int n = a.length;
     9         for (int i = 0; i < n; i++) {
    10             int min = i;
    11             for (int j = i+1; j < n; j++) {
    12                 if (less(a[j], a[min])) min = j;
    13             }
    14             exch(a, i, min);
    15             assert isSorted(a, 0, i);
    16         }
    17         assert isSorted(a);
    18     }
    19 
    20     public static void sort(Object[] a, Comparator comparator) {
    21         int n = a.length;
    22         for (int i = 0; i < n; i++) {
    23             int min = i;
    24             for (int j = i+1; j < n; j++) {
    25                 if (less(comparator, a[j], a[min])) min = j;
    26             }
    27             exch(a, i, min);
    28             assert isSorted(a, comparator, 0, i);
    29         }
    30         assert isSorted(a, comparator);
    31     }
    32 
    33     // is v < w ?
    34     private static boolean less(Comparable v, Comparable w) {
    35         return v.compareTo(w) < 0;
    36     }
    37 
    38     // is v < w ?
    39     private static boolean less(Comparator comparator, Object v, Object w) {
    40         return comparator.compare(v, w) < 0;
    41     }
    42          
    43     // exchange a[i] and a[j]
    44     private static void exch(Object[] a, int i, int j) {
    45         Object swap = a[i];
    46         a[i] = a[j];
    47         a[j] = swap;
    48     }
    49 
    50     // is the array a[] sorted?
    51     private static boolean isSorted(Comparable[] a) {
    52         return isSorted(a, 0, a.length - 1);
    53     }
    54         
    55     // is the array sorted from a[lo] to a[hi]
    56     private static boolean isSorted(Comparable[] a, int lo, int hi) {
    57         for (int i = lo + 1; i <= hi; i++)
    58             if (less(a[i], a[i-1])) return false;
    59         return true;
    60     }
    61 
    62     // is the array a[] sorted?
    63     private static boolean isSorted(Object[] a, Comparator comparator) {
    64         return isSorted(a, comparator, 0, a.length - 1);
    65     }
    66 
    67     // is the array sorted from a[lo] to a[hi]
    68     private static boolean isSorted(Object[] a, Comparator comparator, int lo, int hi) {
    69         for (int i = lo + 1; i <= hi; i++)
    70             if (less(comparator, a[i], a[i-1])) return false;
    71         return true;
    72     }
    73 
    74     // print array to standard output
    75     private static void show(Comparable[] a) {
    76         for (int i = 0; i < a.length; i++) {
    77             StdOut.println(a[i]);
    78         }
    79     }
    80 }

     1.3 选择排序算法性能分析

    • 对于长度为N的数组,选择排序需要大约(N-1)+(N-2)+...+2+1=N(N-1)/2~N2/2次比较和N次交换;
    • 运行时间和输入无关;
    • 数据移动是最少的;
    • 算法不稳定。

    2. 插入排序介绍

    2.1 插入排序算法流程

    Step1:从第一个元素开始,该元素可以认为已经被排序;
    Step2:取出下一个元素,在已经排序的元素序列中从后向前扫描;
    Step3:如果该元素(已排序)大于新元素,将该元素移到下一位置;
    Step4:重复Step3,直到找到已排序的元素小于或者等于新元素的位置;
    Step5:将新元素插入到该位置后;
    Step6:重复步骤Step2~Step5.

    图2 插入排序的轨迹

     2.2 插入排序算法代码实现

      1 import java.util.Comparator;
      2 
      3 public class Insertion {
      4 
      5     // This class should not be instantiated.
      6     private Insertion() { }
      7 
      8     public static void sort(Comparable[] a) {
      9         int n = a.length;
     10         for (int i = 0; i < n; i++) {
     11             for (int j = i; j > 0 && less(a[j], a[j-1]); j--) {
     12                 exch(a, j, j-1);
     13             }
     14             assert isSorted(a, 0, i);
     15         }
     16         assert isSorted(a);
     17     }
     18 
     19     public static void sort(Comparable[] a, int lo, int hi) {
     20         for (int i = lo; i <= hi; i++) {
     21             for (int j = i; j > lo && less(a[j], a[j-1]); j--) {
     22                 exch(a, j, j-1);
     23             }
     24         }
     25         assert isSorted(a, lo, hi);
     26     }
     27 
     28    
     29     public static void sort(Object[] a, Comparator comparator) {
     30         int n = a.length;
     31         for (int i = 0; i < n; i++) {
     32             for (int j = i; j > 0 && less(a[j], a[j-1], comparator); j--) {
     33                 exch(a, j, j-1);
     34             }
     35             assert isSorted(a, 0, i, comparator);
     36         }
     37         assert isSorted(a, comparator);
     38     }
     39 
     40     public static void sort(Object[] a, int lo, int hi, Comparator comparator) {
     41         for (int i = lo; i <= hi; i++) {
     42             for (int j = i; j > lo && less(a[j], a[j-1], comparator); j--) {
     43                 exch(a, j, j-1);
     44             }
     45         }
     46         assert isSorted(a, lo, hi, comparator);
     47     }
     48 
     49 
     50     public static int[] indexSort(Comparable[] a) {
     51         int n = a.length;
     52         int[] index = new int[n];
     53         for (int i = 0; i < n; i++)
     54             index[i] = i;
     55 
     56         for (int i = 0; i < n; i++)
     57             for (int j = i; j > 0 && less(a[index[j]], a[index[j-1]]); j--)
     58                 exch(index, j, j-1);
     59 
     60         return index;
     61     }
     62 
     63     // is v < w ?
     64     private static boolean less(Comparable v, Comparable w) {
     65         return v.compareTo(w) < 0;
     66     }
     67 
     68     // is v < w ?
     69     private static boolean less(Object v, Object w, Comparator comparator) {
     70         return comparator.compare(v, w) < 0;
     71     }
     72         
     73     // exchange a[i] and a[j]
     74     private static void exch(Object[] a, int i, int j) {
     75         Object swap = a[i];
     76         a[i] = a[j];
     77         a[j] = swap;
     78     }
     79 
     80     // exchange a[i] and a[j]  (for indirect sort)
     81     private static void exch(int[] a, int i, int j) {
     82         int swap = a[i];
     83         a[i] = a[j];
     84         a[j] = swap;
     85     }
     86 
     87     private static boolean isSorted(Comparable[] a) {
     88         return isSorted(a, 0, a.length - 1);
     89     }
     90 
     91     // is the array sorted from a[lo] to a[hi]
     92     private static boolean isSorted(Comparable[] a, int lo, int hi) {
     93         for (int i = lo+1; i <= hi; i++)
     94             if (less(a[i], a[i-1])) return false;
     95         return true;
     96     }
     97 
     98     private static boolean isSorted(Object[] a, Comparator comparator) {
     99         return isSorted(a, 0, a.length - 1, comparator);
    100     }
    101 
    102     // is the array sorted from a[lo] to a[hi]
    103     private static boolean isSorted(Object[] a, int lo, int hi, Comparator comparator) {
    104         for (int i = lo + 1; i <= hi; i++)
    105             if (less(a[i], a[i-1], comparator)) return false;
    106         return true;
    107     }
    108 
    109    // print array to standard output
    110     private static void show(Comparable[] a) {
    111         for (int i = 0; i < a.length; i++) {
    112             StdOut.println(a[i]);
    113         }
    114     }
    115 }

    2.3 插入排序算法性能分析

    • 对于长度为N且主键不重复的数组,平均情况下需要~N2/4次比较和~N2/4次交换,最坏情况下(逆序数组)需要~N2/2次比较和~N2/2次交换,最好情况下(数组已经有序)需要~N-1次比较和0次交换;
    • 比较的总次数总是在交换的总次数上加一个额外项,该项为N减去被插入的元素正好是已知排序中的最小元素的次数;
    • 插入排序算法适用于部分有序的数组:1)数组中每个元素的距离离它的终点位置都不远;2)一个有序的大数组接一个小数组;3)数组中只有几个元素的位置不确定;
    • 算法稳定。

    3. 希尔排序介绍

    希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。

    3.1 希尔排序算法流程

    把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。
    随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。

    图3 希尔排序的轨迹

     3.2 希尔排序算法代码实现

     1 public class Shell {
     2 
     3     // This class should not be instantiated.
     4     private Shell() { }
     5 
     6     public static void sort(Comparable[] a) {
     7         int n = a.length;
     8 
     9         // 3x+1 increment sequence:  1, 4, 13, 40, 121, 364, 1093, ... 
    10         int h = 1;
    11         while (h < n/3) h = 3*h + 1; 
    12 
    13         while (h >= 1) {
    14             // h-sort the array
    15             for (int i = h; i < n; i++) {
    16                 for (int j = i; j >= h && less(a[j], a[j-h]); j -= h) {
    17                     exch(a, j, j-h);
    18                 }
    19             }
    20             assert isHsorted(a, h); 
    21             h /= 3;
    22         }
    23         assert isSorted(a);
    24     }
    25     
    26     // is v < w ?
    27     private static boolean less(Comparable v, Comparable w) {
    28         return v.compareTo(w) < 0;
    29     }
    30         
    31     // exchange a[i] and a[j]
    32     private static void exch(Object[] a, int i, int j) {
    33         Object swap = a[i];
    34         a[i] = a[j];
    35         a[j] = swap;
    36     }
    37 
    38     private static boolean isSorted(Comparable[] a) {
    39         for (int i = 1; i < a.length; i++)
    40             if (less(a[i], a[i-1])) return false;
    41         return true;
    42     }
    43 
    44     // is the array h-sorted?
    45     private static boolean isHsorted(Comparable[] a, int h) {
    46         for (int i = h; i < a.length; i++)
    47             if (less(a[i], a[i-h])) return false;
    48         return true;
    49     }
    50 
    51     // print array to standard output
    52     private static void show(Comparable[] a) {
    53         for (int i = 0; i < a.length; i++) {
    54             StdOut.println(a[i]);
    55         }
    56     }
    57 }

    3.3 希尔排序算法性能分析

    • 对于长度为N且主键不重复的数组,平均情况下需要~NlgN次比较,最坏情况需要~N1.5次比较;
    • 目前最好的排序序列是1,5,19,41,109...,由Sedgewick提出;
    • 希尔排序算法属于插入排序,但是不稳定。

    三、一种洗牌方法的实现(直接上代码)

    public class StdRandom
    {// 这是一个随机数静态方法库,包含各种随机数生成方法和随机数操作方法
    ...
       public static void shuffle(int[] a) {
            // 参数可以改成其他数据类型double
            if (a == null) throw new IllegalArgumentException("argument array is null");
            int n = a.length;
            for (int i = 0; i < n; i++) {
                int r = i + StdRandom.uniform(n-i);       
                //StdRandom.uniform(n-i) 方法随机产生1到n-i之间的整数
                int temp = a[i];
                a[i] = a[r];
                a[r] = temp;
            }
        }
    }

    作者: 邹珍珍(Pearl_zhen)

    出处: http://www.cnblogs.com/zouzz/

    声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接 如有问题, 可邮件(zouzhenzhen@seu.edu.cn)咨询.

  • 相关阅读:
    KAL1 LINUX 官方文档之kali nethunter文档 ---MANA Evil Access Point
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter MAC改变器
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter Kali服务
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter HID键盘攻击
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter DuckHunter攻击
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter自定义命令
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter Application Terminal
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter BadUSB攻击
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter USB-Arsenal
    KAL1 LINUX 官方文档之kali nethunter文档 ---NetHunter KeX 管理器
  • 原文地址:https://www.cnblogs.com/zouzz/p/6095345.html
Copyright © 2011-2022 走看看