简单排序

*用处:简单,体现思路,特殊情况下有用,改进特殊排序

*选择排序:从后面j中拎出一个最小值与前面元素i交换。比如人眼排列有限数据(可以一眼看出最小值的话,如1, 10, 7, 8)

def selectionSort(nums):
    for i in range(0, len(nums)):
        min = i
        for j in range(i + 1, len(nums)):
            if nums[j] < nums[min]:
                min = j # find the place of the min value in range(i + 1, len(nums))
        nums[i], num[min] = nums[min], nums[i] # swap current value with min value
public static void selectionSort(int[] nums) {
    for (int i = 0; i < nums.length; i++) {
        int min = i;
        for (int j = i + 1; j < nums.length; j++) {
            if (nums[j] < nums[min]) {
                min = j;
            }
        }
        swap(nums, min, i);
    }

*插入排序:先从后面拎出一个元素i和前面已经排好序的j进行比较,如打牌的时候摸牌。

public static void insertionSort(int[] nums) {
    for (int i = 1; i < nums.length; i++) {
        int key = nums[i];
        int j = i - 1;
        while (j >= 0 && nums[j] > key) {
            nums[j + 1] = nums[j]; // shift bigger number to right
            j--; // compare previous
        }
        nums[j + 1] = key;
    }
}

交换法:

public static void swap(int[] nums, int a, int b) {
    int tmp = nums[a];
    nums[a] = nums[b];
    nums[b] = tmp;
}

public static void insertionSort1(int[] nums) {
    for (int i = 1; i < nums.length; i++) {
        for (int j = i; j > 0 && nums[j - 1] > nums[j]; j--) {
            swap(nums, j, j - 1);
        }
    }
}

*冒泡排序:i代表需要进行两两排序的数字(所以边界是数组长度减去一),j代表剩下的需要排序的数字。

def bubbleSort(nums):
    for i in range(0, len(nums) - 1):
        for j in range(0, len(nums) - 1 - i):
            if nums[j] > nums[j + 1]:
                nums[j], nums[j + 1] = nums[j + 1], nums[j]

# different boundary
def bubbleSort2(nums):
    for i in range(0, len(nums)):
        for j in range(1, len(nums) - i):
            if nums[j - 1] > nums[j]:
                nums[j], nums[j - 1] = nums[j - 1], nums[j]

桶排序:洗扑克牌,先按花色分成四堆,再排

Merge Sort:适合链表

排序算法比较

一个完整的插入排序和选择排序算法的运行时间比较:

包括产生测试用例/检查算法正确性的辅助函数:

  • randomArray
  • nearlySortedArray
  • isSorted

计算时间的函数(使用到反射):

  • testSort
import java.util.Arrays;
import java.util.Random;
import java.lang.reflect.Method;

public class Sort {
    public static int[] randomArray(int n, int l, int r) {
        Random rand = new Random();
        if (l >= r) {
            throw new ArrayIndexOutOfBoundsException();
        }
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = rand.nextInt(r - l + 1) + l;
        }
        return arr;
    }

    public static int[] nearlySortedArray(int n, int swapTimes) {
        Random rand = new Random();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = i;
        }
        // swap several pairs in a sorted array
        for (int i = 0; i < swapTimes; i++) {
            int x = rand.nextInt(n); // the upper bound is exclusive
            int y = rand.nextInt(n);
            while (y == x)          // maybe add this to reduce self duplications
                y = rand.nextInt(n);
            swap(nums, x, y);
        }
        return nums;
    }

    public static boolean isSorted(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            if (arr[i + 1] < arr[i])
                return false;
        }
        return true;
    }

    public static void swap(int[] nums, int a, int b) {
        int tmp = nums[a];
        nums[a] = nums[b];
        nums[b] = tmp;
    }

    public static void insertionSort1(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            int key = nums[i];
            int j = i - 1;
            while (j >= 0 && nums[j] > key) {
                nums[j + 1] = nums[j]; // shift bigger number to right
                j--; // compare previous
            }
            nums[j + 1] = key;
        }
    }

    public static void insertionSort1_1(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            int key = nums[i];
            int j = i;
            while (j > 0 && nums[j - 1] > key) {
                nums[j] = nums[j - 1]; // shift bigger number to right
                j--; // compare previous
            }
            nums[j] = key;
        }
    }

    public static void insertionSort1_2(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            int key = nums[i];
            int j;
            for (j = i; j > 0 && nums[j - 1] > key; j--) {
                nums[j] = nums[j - 1]; // shift bigger number to right
            }
            nums[j] = key;
        }
    }

    public static void insertionSort2(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            for (int j = i; j > 0 && nums[j - 1] > nums[j]; j--) {
                swap(nums, j, j - 1);
            }
        }
    }

    public static void selectionSort(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            int min = i;
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[j] < nums[min]) {
                    min = j;
                }
            }
            swap(nums, min, i); // swap the min value with current index
        }
    }

    public static void testSort(String sortName, int[] nums) throws Exception {
        Method method = Sort.class.getMethod(sortName, int[].class);
        long startTime = System.currentTimeMillis();
        method.invoke(null, nums);
        long timeElapsed = System.currentTimeMillis() - startTime;
        System.out.println(sortName + ": " + timeElapsed + " ms");
    }

    public static void main(String[] args) throws Exception {
        // create two test arrays
        int length = 100000;
        String[] func = {"insertionSort1", "insertionSort1_1", "insertionSort1_2",
                "insertionSort2", "selectionSort"};
        int[] random = Sort.randomArray(length, 1, length);
        int[] dummy = Arrays.copyOf(random, length);
        // System.arraycopy(random, 0, copy1, 0, length); //alternatives
        System.out.println("Dummy call:");
        Sort.testSort("insertionSort1", dummy); // dummy call


        System.out.println("Test Random Array:");
        for (int i = 0; i < func.length; i++) {
            int[] c = Arrays.copyOf(random, length);
            Sort.testSort(func[i], c);
        }

        System.out.println("Test Nearly Sorted Array:");
        int[] sorted = Sort.nearlySortedArray(length, 10);
        for (int i = 0; i < func.length; i++) {
            int[] s = Arrays.copyOf(sorted, length);
            Sort.testSort(func[i], s);
        }
    }
}

output: insertion比selection快的原因是insertion可以比较并且终止没有必要的操作(一旦找到合适的位置就会终止),所以效率较高,特别是数组元素近乎有序的时候,可以退化成O(n),所以当数组元素较小或者有序的时候,可以使用插入排序。

// not sure why this happend(the first funciton call always cost more time), but I'm just make a dummy call here..
Dummy call:
insertionSort1: 1245 ms
Test Random Array:
insertionSort1: 937 ms
insertionSort1_1: 977 ms
insertionSort1_2: 970 ms
insertionSort2: 1700 ms
selectionSort: 4673 ms
Test Nearly Sorted Array:
insertionSort1: 1 ms
insertionSort1_1: 2 ms
insertionSort1_2: 2 ms
insertionSort2: 3 ms
selectionSort: 4628 ms

results matching ""

    No results matching ""