排序算法的Java实现全攻略

Collections.sort()

Java的排序可以用Collections.sort() 排序函数实现。
用Collections.sort方法对list排序有两种方法:
第一种是list中的对象实现Comparable接口,如下:

/**
* 根据order对User排序
*/
public class User implements Comparable<User>{
  private String name;
  private Integer order;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Integer getOrder() {
    return order;
  }
  public void setOrder(Integer order) {
    this.order = order;
  }
  public int compareTo(User arg0) {
    return this.getOrder().compareTo(arg0.getOrder());
  }
}

测试一下:

public class Test{

  public static void main(String[] args) {
    User user1 = new User();
    user1.setName("a");
    user1.setOrder(1);
    User user2 = new User();
    user2.setName("b");
    user2.setOrder(2);
    List<User> list = new ArrayList<User>();
    //此处add user2再add user1
    list.add(user2);
    list.add(user1);
    Collections.sort(list);
    for(User u : list){
      System.out.println(u.getName());
    }
  }
}

输出结果如下

a
b

第二种方法是根据Collections.sort重载方法来实现,例如:

/**
* 根据order对User排序
*/
public class User { //此处无需实现Comparable接口
  private String name;
  private Integer order;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Integer getOrder() {
    return order;
  }
  public void setOrder(Integer order) {
    this.order = order;
  }
}

主类中这样写即可:

public class Test{
  public static void main(String[] args) {
    User user1 = new User();
    user1.setName("a");
    user1.setOrder(1);
    User user2 = new User();
    user2.setName("b");
    user2.setOrder(2);
    List<User> list = new ArrayList<User>();
    list.add(user2);
    list.add(user1);

    Collections.sort(list,new Comparator<User>(){
      public int compare(User arg0, User arg1) {
        return arg0.getOrder().compareTo(arg1.getOrder());
      }
    });
    for(User u : list){
      System.out.println(u.getName());
    }
  }
}

输出结果如下

a
b

前者代码结构简单,但是只能根据固定的属性排序,后者灵活,可以临时指定排序项,但是代码不够简洁

择优用之。

常用排序算法
下面来看几种经典排序算法的Java代码实践:

冒泡排序

 public static void bubbleSort(int A[], int n) {
    int i, j; 

    for (i = 0; i < n - 1; i ++) {
      for (j = 0; j < n - i - 1; j ++) {
        if (A[j] > A[j + 1]) {
          A[j] = A[j] ^ A[j + 1];
          A[j + 1] = A[j] ^ A[j + 1];
          A[j] = A[j] ^ A[j + 1];
        }
      }
    }
  }

直接插入排序

public static void insertSort(int A[], int n) {
    int i, j, tmp; 

    for (i = 1; i < n; i++) {
      tmp = A[i]; 

      for (j = i - 1; j >= 0; j--) {
        if (A[j] > tmp) {
          A[j + 1] = A[j];
        } else {
          break;
        }
      } 

      A[j + 1] = tmp;
    }
  }

直接选择排序

public static void selectSort(int A[], int n) {
    int i, j, loc; 

    for (i = 0; i < n; i++) {
      loc = i; 

      for (j = i + 1; j < n; j++) {
        if (A[j] < A[loc]) {
          loc = j;
        }
      } 

      if (loc != i) {
        A[i] = A[i] ^ A[loc];
        A[loc] = A[i] ^ A[loc];
        A[i] = A[i] ^ A[loc];
      }
    }
  }

堆排序

  /**
   * 堆排序(从小到大)
   *
   * @param A
   * @param n
   */
  public static void heapSort(int A[], int n) {
    int tmp; 

    // 构建大根堆
    buildMaxHeap(A, n); 

    for (int j = n - 1; j >= 1; j--) {
      tmp = A[0];
      A[0] = A[j];
      A[j] = tmp; 

      maxheapIfy(A, 0, j);
    }
  } 

  /**
   * 构建大根堆
   *
   * @param A
   * @param n
   */
  private static void buildMaxHeap(int A[], int n) {
    for (int i = (n - 2) / 2; i >= 0; i--) {
      maxheapIfy(A, i, n);
    }
  } 

  /**
   * 维护从下标i开始的最大堆
   *
   * @param A
   * @param i
   * @param n
   */
  private static void maxheapIfy(int A[], int i, int n) {
    int left, right, loc; 

    while (i < n) {
      left = 2 * i + 1;
      right = 2 * i + 2;
      loc = i; 

      if (left < n && A[left] > A[i]) {
        i = left;
      } 

      if (right < n && A[right] > A[i]) {
        i = right;
      } 

      if (loc != i) {
        A[i] = A[loc] ^ A[i];
        A[loc] = A[loc] ^ A[i];
        A[i] = A[loc] ^ A[i];
      } else {
        break;
      }
    }
  }

快速排序

  public static void quickSort(int A[], int bt, int ed) {
    if (bt < ed) {
      int pivot = pivotPartition(A, bt, ed); 

      quickSort(A, bt, pivot - 1); 

      quickSort(A, pivot + 1, ed);
    }
  } 

  private static void swapVar(int A[], int bt, int ed) {
    int mid = bt + (ed - bt) / 2; 

    if (mid != bt) {
      A[bt] = A[bt] ^ A[mid];
      A[mid] = A[bt] ^ A[mid];
      A[bt] = A[bt] ^ A[mid];
    }
  } 

  private static int pivotPartition(int A[], int bt, int ed) {
    // 取中间值作为stand,防止数组有序出现O(n^2)情况
    swapVar(A, bt, ed); 

    int stand = A[bt]; 

    while (bt < ed) {
      while (bt < ed && A[ed] >= stand) {
        ed--;
      }
      if (bt < ed) {
        A[bt++] = A[ed];
      } 

      while (bt < ed && A[bt] <= stand) {
        bt++;
      }
      if (bt < ed) {
        A[ed--] = A[bt];
      }
    } 

    A[bt] = stand; 

    return bt;
  }

归并排序

 public static void mergeSort(int A[], int bt, int ed) {
    if (bt < ed) {
      int mid = bt + (ed - bt) / 2; 

      mergeSort(A, bt, mid); 

      mergeSort(A, mid + 1, ed); 

      mergeArray(A, bt, mid, ed);
    }
  } 

  private static void mergeArray(int A[], int bt, int mid, int ed) {
    int i, j, k, len = ed - bt + 1;
    int tmp[] = new int[len]; 

    for (i = bt, j = mid + 1, k = 0; i <= mid && j <= ed; k++) {
      if (A[i] <= A[j]) {
        tmp[k] = A[i++];
      } else {
        tmp[k] = A[j++];
      }
    } 

    while (i <= mid) {
      tmp[k++] = A[i++];
    } 

    while (j <= ed) {
      tmp[k++] = A[j++];
    } 

    for (i = 0; i < k; i++) {
      A[bt + i] = tmp[i];
    }
  }

测试程序

来将以上算法归纳总结一下:

 import java.util.Scanner; 

  public class JavaSort {
    public static void main(String args[]) {
      Scanner cin = new Scanner(System.in); 

      int A[], n; 

      while (cin.hasNext()) {
        n = cin.nextInt();
        A = new int[n]; 

        for (int i = 0; i < n; i++) {
          A[i] = cin.nextInt();
        } 

        // bubbleSort(A, n); 

        // insertSort(A, n); 

        // selectSort(A, n); 

        // heapSort(A, n); 

        // quickSort(A, 0, n - 1); 

        mergeSort(A, 0, n - 1); 

        printArr(A);
      }
    } 

    /**
     * 归并排序
     *
     * @param A
     * @param bt
     * @param ed
     */
    public static void mergeSort(int A[], int bt, int ed) {
      if (bt < ed) {
        int mid = bt + (ed - bt) / 2; 

        mergeSort(A, bt, mid); 

        mergeSort(A, mid + 1, ed); 

        mergeArray(A, bt, mid, ed);
      }
    } 

    /**
     * 合并数组
     *
     * @param A
     * @param bt
     * @param mid
     * @param ed
     */
    private static void mergeArray(int A[], int bt, int mid, int ed) {
      int i, j, k, len = ed - bt + 1;
      int tmp[] = new int[len]; 

      for (i = bt, j = mid + 1, k = 0; i <= mid && j <= ed; k++) {
        if (A[i] <= A[j]) {
          tmp[k] = A[i++];
        } else {
          tmp[k] = A[j++];
        }
      } 

      while (i <= mid) {
        tmp[k++] = A[i++];
      } 

      while (j <= ed) {
        tmp[k++] = A[j++];
      } 

      for (i = 0; i < k; i++) {
        A[bt + i] = tmp[i];
      }
    } 

    /**
     * 快速排序
     *
     * @param A
     * @param bt
     * @param ed
     */
    public static void quickSort(int A[], int bt, int ed) {
      if (bt < ed) {
        int pivot = pivotPartition(A, bt, ed); 

        quickSort(A, bt, pivot - 1); 

        quickSort(A, pivot + 1, ed);
      }
    } 

    private static void swapVar(int A[], int bt, int ed) {
      int mid = bt + (ed - bt) / 2; 

      if (mid != bt) {
        A[bt] = A[bt] ^ A[mid];
        A[mid] = A[bt] ^ A[mid];
        A[bt] = A[bt] ^ A[mid];
      }
    } 

    /**
     * 快排寻找基准点位置
     *
     * @param A
     * @param bt
     * @param ed
     * @return
     */
    private static int pivotPartition(int A[], int bt, int ed) {
      // 取中间值作为stand,防止数组有序出现O(n^2)情况
      swapVar(A, bt, ed); 

      int stand = A[bt]; 

      while (bt < ed) {
        while (bt < ed && A[ed] >= stand) {
          ed--;
        }
        if (bt < ed) {
          A[bt++] = A[ed];
        } 

        while (bt < ed && A[bt] <= stand) {
          bt++;
        }
        if (bt < ed) {
          A[ed--] = A[bt];
        }
      } 

      A[bt] = stand; 

      return bt;
    } 

    /**
     * 堆排序(从小到大)
     *
     * @param A
     * @param n
     */
    public static void heapSort(int A[], int n) {
      int tmp; 

      // 构建大根堆
      buildMaxHeap(A, n); 

      for (int j = n - 1; j >= 1; j--) {
        tmp = A[0];
        A[0] = A[j];
        A[j] = tmp; 

        maxheapIfy(A, 0, j);
      }
    } 

    /**
     * 构建大根堆
     *
     * @param A
     * @param n
     */
    private static void buildMaxHeap(int A[], int n) {
      for (int i = (n - 2) / 2; i >= 0; i--) {
        maxheapIfy(A, i, n);
      }
    } 

    /**
     * 维护从下标i开始的最大堆
     *
     * @param A
     * @param i
     * @param n
     */
    private static void maxheapIfy(int A[], int i, int n) {
      int left, right, loc; 

      while (i < n) {
        left = 2 * i + 1;
        right = 2 * i + 2;
        loc = i; 

        if (left < n && A[left] > A[i]) {
          i = left;
        } 

        if (right < n && A[right] > A[i]) {
          i = right;
        } 

        if (loc != i) {
          A[i] = A[loc] ^ A[i];
          A[loc] = A[loc] ^ A[i];
          A[i] = A[loc] ^ A[i];
        } else {
          break;
        }
      }
    } 

    /**
     * 直接选择排序
     *
     * @param A
     * @param n
     */
    public static void selectSort(int A[], int n) {
      int i, j, loc; 

      for (i = 0; i < n; i++) {
        loc = i; 

        for (j = i + 1; j < n; j++) {
          if (A[j] < A[loc]) {
            loc = j;
          }
        } 

        if (loc != i) {
          A[i] = A[i] ^ A[loc];
          A[loc] = A[i] ^ A[loc];
          A[i] = A[i] ^ A[loc];
        }
      }
    } 

    /**
     * 直接插入排序
     *
     * @param A
     * @param n
     */
    public static void insertSort(int A[], int n) {
      int i, j, tmp; 

      for (i = 1; i < n; i++) {
        tmp = A[i]; 

        for (j = i - 1; j >= 0; j--) {
          if (A[j] > tmp) {
            A[j + 1] = A[j];
          } else {
            break;
          }
        } 

        A[j + 1] = tmp;
      }
    } 

    /**
     * 冒泡排序
     *
     * @param A
     * @param n
     */
    public static void bubbleSort(int A[], int n) {
      int i, j; 

      for (i = 0; i < n - 1; i++) {
        for (j = 0; j < n - i - 1; j++) {
          if (A[j] > A[j + 1]) {
            A[j] = A[j] ^ A[j + 1];
            A[j + 1] = A[j] ^ A[j + 1];
            A[j] = A[j] ^ A[j + 1];
          }
        }
      }
    } 

    /**
     * 打印数组
     *
     * @param A
     */
    public static void printArr(int A[]) {
      for (int i = 0; i < A.length; i++) {
        if (i == A.length - 1) {
          System.out.printf("%d\n", A[i]);
        } else {
          System.out.printf("%d ", A[i]);
        }
      }
    }
  }
(0)

相关推荐

  • 详解快速排序算法中的区间划分法及Java实现示例

    快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序.该方法的基本思想是: 1.先从数列中取出一个数作为基准数. 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边. 3.再对左右区间重复第二步,直到各区间只有一个数. 算法的思路很清晰,但是如果在区间划分过程中边界值没有处理好,也是很容易出现bug的.下面给出两种比较清晰的思维来指导区间划分代码的编写. 第一种思维即所谓的挖坑法思维,下面通过分析一个实例来分析一下挖坑法的过程: 以一个数组作为示例,取区间

  • Java实现冒泡排序与双向冒泡排序算法的代码示例

    冒泡排序: 就是按索引逐次比较相邻的两个元素,如果大于/小于(取决于需要升序排还是降序排),则置换,否则不做改变 这样一轮下来,比较了n-1次,n等于元素的个数:n-2, n-3 ... 一直到最后一轮,比较了1次 所以比较次数为递减:从n-1 到 1 那么总的比较次数为:1+2+3+...+(n-1),  以等差公式计算:(1+n-1)/2*(n-1) ==> n/2*(n-1) ==> (n^2-n) * 0.5 用大O表示算法的时间复杂度:O(n^2) ,  忽略了系数0.5和常数-n

  • Java实现直接插入排序和折半插入排序算法示例

    直接插入排序​ 1 排序思想: 将待排序的记录Ri插入到已经排好序的记录R1,R2,--,R(N-1)中. 对于一个随机序列而言,就是从第二个元素开始,依次将这个元素插入到它之前的元素中的相应位置.它之前的元素已经排好序. 第1次排序:将第2个元素插入到前边的有序列表(此时前边只有一个元素,当然是有序的),之后,这个序列的前2个元素就是有序的了. 第2次排序:将第3个元素插入到前边长度为2的有序列表,使得前2个元素是有序的. 以此类推,直到将第N个元素插入到前面长度为(N-1)的有序列表中. 2

  • java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序算法的描述

    算法是在有限步骤内求解某一问题所使用的一组定义明确的规则.通俗点说,就是计算机解题的过程.在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法.前者是推理实现的算法,后者是操作实现的算法. 一个算法应该具有以下五个重要的特征: 1.有穷性: 一个算法必须保证执行有限步之后结束: 2.确切性: 算法的每一步骤必须有确切的定义: 3.输入:一个算法有0个或多个输入,以刻画运算对象的初始情况: 4.输出:一个算法有一个或多个输出,以反映对输入数据加工后的结果.没有输出的算法是毫无意义的:

  • 深入探究TimSort对归并排序算法的优化及Java实现

    简介 MergeSort对已经反向排好序的输入时复杂度为O(n^2),而timsort就是针对这种情况,对MergeSort进行优化而产生的,平均复杂度为n*O(log n),最好的情况为O(n),最坏情况n*O(log n).并且TimSort是一种稳定性排序.思想是先对待排序列进行分区,然后再对分区进行合并,看起来和MergeSort步骤一样,但是其中有一些针对反向和大规模数据的优化处理. 归并排序的优化思想 归并排序有以下几点优化方法: 和快速排序一样,对于小数组可以使用插入排序或者选择排

  • 用java实现冒泡排序算法

    冒泡排序的算法分析与改进 交换排序的基本思想是:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止. 应用交换排序基本思想的主要排序方法有:冒泡排序和快速排序. 复制代码 代码如下: public class BubbleSort implements SortUtil.Sort{ public void sort(int[] data) { int temp; for(int i=0;i<data.length;i++){ for(int j=data.le

  • 简单讲解奇偶排序算法及在Java数组中的实现

    奇偶排序是一个比较有个性的排序,基本思路是奇数列排一趟序,偶数列排一趟序,再奇数排,再偶数排,直到全部有序 举例吧, 待排数组 [6 2 4 1 5 9] 第一次比较奇数列,奇数列与它的邻居偶数列比较,如6和2比,4和1比,5和9比 [6 2 4 1 5 9] 交换后变成 [2 6 1 4 5 9] 第二次比较偶数列,即6和1比,5和5比 [2 6 1 4 5 9] 交换后变成 [2 1 6 4 5 9] 第三趟又是奇数列,选择的是2,6,5分别与它们的邻居列比较 [2 1 6 4 5 9] 交

  • Java对数组实现选择排序算法的实例详解

    一. 算法描述     选择排序:比如在一个长度为N的无序数组中,在第一趟遍历N个数据,找出其中最小的数值与第一个元素交换,第二趟遍历剩下的N-1个数据,找出其中最小的数值与第二个元素交换......第N-1趟遍历剩下的2个数据,找出其中最小的数值与第N-1个元素交换,至此选择排序完成. 以下面5个无序的数据为例: 56 12 80 91 20(文中仅细化了第一趟的选择过程) 第1趟:12 56 80 91 20 第2趟:12 20 80 91 56 第3趟:12 20 56 91 80 第4趟

  • Java各种排序算法汇总(冒泡,选择,归并,希尔及堆排序等)

    本文实例汇总了Java各种排序算法.分享给大家供大家参考,具体如下: 1. 冒泡排序: public class SortTest { public static void main(String[] args) { int[] a = {345,7,32,5,4,-1,3,12,23,110,45645,321,456,78,-1,78,78,32,444,345}; show(a); bubbleSort(a); show(a); } private static void bubbleSo

  • 排序算法的Java实现全攻略

    Collections.sort() Java的排序可以用Collections.sort() 排序函数实现. 用Collections.sort方法对list排序有两种方法: 第一种是list中的对象实现Comparable接口,如下: /** * 根据order对User排序 */ public class User implements Comparable<User>{ private String name; private Integer order; public String

  • 微信公众帐号开发教程之图文消息全攻略

    引言及内容概要 已经有几位读者抱怨"柳峰只用到文本消息作为示例,从来不提图文消息,都不知道图文消息该如何使用",好吧,我错了,原本以为把基础API封装完.框架搭建好,再给出一个文本消息的使用示例,大家就能够照猫画虎的,或许是因为我的绘画功底太差,画出的那只猫本来就不像猫吧-- 本篇主要介绍微信公众帐号开发中图文消息的使用,以及图文消息的几种表现形式.标题取名为"图文消息全攻略",这绝对不是标题党,是想借此机会把大家对图文消息相关的问题.疑虑.障碍全部清除掉. 图文消

  • 剖析各类恶意网页对策分析—注册表使用全攻略之七

    剖析各类恶意网页对策分析-注册表使用全攻略之七 互联网利用IE等的漏洞完全可以让你通过浏览网页让你的电脑面目全非,或者格盘,甚至中下木马,传播病毒,而且这种形式的传播愈演愈烈,闲话少说了,现在来分析一下各类恶意网页. 分析前先介绍一下注册表的修改方法,因为注册表在网页病毒中是中枢,就是通过它让你的电脑面目全非. 第一种方法:直接修改法 就是在运行里敲入regedit,然后进行编辑,这是大家通常修改注册表的方法. 第二种方法:reg包导入法 现在以解锁注册表为例(其实解锁用兔子等工具更好更方便,这

  • VSCode插件开发全攻略之命令、菜单、快捷键

    命令 我们在前面HelloWord章节中已经提到了命令写法,这里再重温一下. context.subscriptions.push(vscode.commands.registerCommand('extension.sayHello', () => { vscode.window.showInformationMessage('您执行了extension.sayHello命令!'); })); 然后在清单文件声明: "commands": [ { "command&q

  • 生成PDF全攻略之在已有PDF上添加内容的实现方法

    项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此记录总结,方便下次以不变应万变,需要的 jar 请移步:生成PDF全攻略 PdfReader reader = new PdfReader("E:\\A.pdf"); PdfStamper stamper = new PdfStamper(reader, new FileOutputStr

  • 将TOMCAT装入IIS全攻略

    来源:网友提供如有版权问题请与我们联系<BR><BR>Tomcat IIS             HowTo:将Tomcat装入IIS全攻略<BR>1,我的安装环境是W2K(日文版),IIS5<BR>Tomcat             3.1下载地址<BR>http://jakarta.apache.org/builds/tomcat/release/v3.1/bin/<BR><BR>isapi_redirect.dl

  • 三种简单排序算法(使用java实现)

    一.冒泡排序 算法思想:遍历待排序的数组,每次遍历比较相邻的两个元素,如果他们的排列顺序错误就交换他们的位置,经过一趟排序后,最大的元素会浮置数组的末端.重复操 作,直到排序完成. 示例演示: 算法实现: for(int i=0;i<array.length-1;i++){//最多排序n-1次 for(int j=0;j<array.length-i-1;j++){//需要交换的次数 if(array[j]>array[j+1]){ int temp=array[j]; array[j]

  • 文件关联及应用—注册表使用全攻略之二

    注册表的文件关联及应用-注册表使用全攻略之二  喜欢使用Windows右键快捷菜单的朋友可能知道,当你选择了一个文件(或者是文件夹或是系统图标)再单击鼠标右键,系统就会弹出一个菜单,菜单上面的各种"功能"(或称"操作")任你选择,但是你是否注意到,当你安装一些应用软件之后,你的右键菜单是不是膨胀,以winzip为例,安装winzip之后,文件或文件夹的右键菜单当中就增加了功能选择项"Add to Zip"和"Add to xxx.zip

  • 巧改注册表来增强网络功能—注册表使用全攻略之五

    巧改注册表来增强网络功能-注册表使用全攻略之五 1.指定首选的网络服务器 在注册表中依次展开[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWNP32\NetworkProvider],并在其主键下创建或更改串值AuthenticatingAgent,附值为指定的服务器 2.禁止自动登陆网络 在注册表中依次展开[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWNP32\Ne

  • 注册表REG文件全攻略—注册表使用全攻略之十五

    注册表REG文件全攻略-注册表使用全攻略之十五 1.何谓REG文件 REG文件实际上是一种注册表脚本文件,双击REG文件即可将其中的数据导入到注册表中.利用REG文件我们可以直接对注册表进行任何修改操作,它对注册表的操作可以不受注册表编辑器被禁用的限制,因此功能更为强大.灵活,另外,由于REG文件可以用任何文本文件编辑工具(例如记事本)进行修改,因此通过它对注册表数据进行修改后,如果发生错误,还可以通过改回REG文件中的数据后再导入,从而实现恢复操作,因此它又较之直接用注册表编辑器修改更安全,所

随机推荐