java实现5种常见排序方式(附性能测试)
冒泡排序
依次比较相邻的两个元素,通过一次比较把未排序序列中最大(或最小)的元素放置在未排序序列的末尾。
public static int[] bubbleSort(int[] arr)
{
int length = arr.length;
for (int i = 1; i < length; i++) {
for (int j = 0; j < length - i; j++) {
if (arr[j] > arr[j + 1]){
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
选择排序
每一次从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
public static int[] selectSort(int[] arr)
{
int length = arr.length;
for (int i = 0; i < length - 1; i ++) {
int min = i;
for (int j = i + 1; j < length; j++) {
if (arr[j] < arr[min]){
min = j;
}
}
if (i != min) {
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
return arr;
}
插入排序
将数列分为有序和无序两个部分,每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。
public static int[] insertSort(int[] arr)
{
int length = arr.length;
for (int i = 1; i < length; i++) {
int temp = arr[i];
for (int j = i - 1; j >= 0; j--) {
if (arr[j] > temp) {
arr[j + 1] = arr[j];
arr[j] = temp;
} else {
break;
}
}
}
return arr;
}
快速排序
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
递归方式
public static int getMiddleware(int[] arr, int left, int right)
{
int temp = arr[left];
while (left < right) {
while (left < right && arr[right] >= temp){
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] <= temp){
left++;
}
arr[right] = arr[left];
}
arr[left] = temp;
return left;
}
public static int[] quickSort(int[] arr, int left, int right)
{
if (left < right) {
int middleware = getMiddleware(arr, left, right);
quickSort(arr, left, middleware - 1);
quickSort(arr, middleware + 1, right);
}
return arr;
}
非递归方式
public static int[] nonRecQuickSort(int[] a, int start, int end) {
// 用栈模拟
Stack<Integer> stack = new Stack<>();
if (start < end) {
stack.push(end);
stack.push(start);
while (!stack.isEmpty()) {
int l = stack.pop();
int r = stack.pop();
int index = partition(a, l, r);
if (l < index - 1) {
stack.push(index - 1);
stack.push(l);
}
if (r > index + 1) {
stack.push(r);
stack.push(index + 1);
}
}
}
return a;
}
private static int partition(int[] a, int start, int end) {
int pivot = a[start];
while (start < end) {
while (start < end && a[end] >= pivot)
end--;
a[start] = a[end];
while (start < end && a[start] <= pivot)
start++;
a[end] = a[start];
}
a[start] = pivot;
return start;
}
二叉树排序
使用第一个元素作为根节点,如果之后的元素比第一个小,则放到左子树,否则放到右子树,之后按中序遍历。
public class Node {
private Node leftNode;
private Node rightNode;
private Object value;
public void add(Object v) {
if (null == value) {
value = v;
} else {
if ((Integer)v - (Integer)value <= 0) {
if (null == leftNode)
leftNode = new Node();
leftNode.add(v);
} else {
if (null == rightNode)
rightNode = new Node();
rightNode.add(v);
}
}
}
public List<Object> values()
{
List<Object> values = new ArrayList<>();
if (null != leftNode)
values.addAll(leftNode.values());
values.add(value);
if (null != rightNode)
values.addAll(rightNode.values());
return values;
}
}
public static Object[] nodeSort(int[] arr)
{
Node root = new Node();
for (int number : arr) {
root.add(number);
}
return root.values().toArray();
}
性能测试
public class TestSort {
public static void main(String[] args) {
int n = 10000;
int[] a = new int[n];
int[] b = new int[n];
int[] c = new int[n];
int[] d = new int[n];
int[] e = new int[n];
int[] f = new int[n];
for (int i = 0; i < n; i++) {
int random = (int)(Math.random() * n);
a[i] = random;
b[i] = random;
c[i] = random;
d[i] = random;
e[i] = random;
f[i] = random;
}
long start = System.currentTimeMillis();
Sort.bubbleSort(a);
System.out.println("冒泡排序耗时:" + (System.currentTimeMillis() - start) + "毫秒");
start = System.currentTimeMillis();
Sort.selectSort(b);
System.out.println("选择排序耗时:" + (System.currentTimeMillis() - start) + "毫秒");
start = System.currentTimeMillis();
Sort.insertSort(c);
System.out.println("插入排序耗时:" + (System.currentTimeMillis() - start) + "毫秒");
start = System.currentTimeMillis();
Sort.quickSort(d, 0, d.length - 1);
System.out.println("递归快速排序耗时:" + (System.currentTimeMillis() - start) + "毫秒");
start = System.currentTimeMillis();
Sort.nonRecQuickSort(e, 0, e.length - 1);
System.out.println("非递归快速排序耗时:" + (System.currentTimeMillis() - start) + "毫秒");
start = System.currentTimeMillis();
Sort.nodeSort(f);
System.out.println("二叉树排序耗时:" + (System.currentTimeMillis() - start) + "毫秒");
}
}
测试结果
冒泡排序耗时:147毫秒
选择排序耗时:47毫秒
插入排序耗时:22毫秒
递归快速排序耗时:2毫秒
非递归快速排序耗时:7毫秒
二叉树排序耗时:8毫秒