插入排序算法

算法过程类似扑克牌抓牌排序手牌:遍历数组中的第二个元素到最后一个元素,每个遍历中的元素都与它前面的元素进行比较大小,将遍历中的元素插入到合适位置。

下图展示了这个过程,但这里的数组下标基于1,而代码中的下标基于0。
插入排序算法_第1张图片

下面是最基本的插入排序实现。

// 输入一个数组,就地升序排序。
public void InsertSort<T>(T[] array) {
    for (var i = 1; i < array.Length; i++) {
        var key = array[i];
        var j = i - 1;
        while (j >= 0 && Comparer.Default.Compare(array[j], key) > 0) {
            array[j + 1] = array[j];
            j--;
        }
        array[j + 1] = key;
    }
}

还可以用递归进行改写:为了排序numbers[0..n],可以递归的排序numbers[0..n-1],然后把number[n]插入到已经排序的数组numbers[0..n-1]:

private void Sort<T>(IList<T> numbers, int insertNumberIndex = 1) {
    if (insertNumberIndex < numbers.Count - 1)
        Sort(numbers, insertNumberIndex + 1);
    // insert numbers[insertNumberIndex] into sorted numbers[0..insertNumberIndex - 1]
    var key = numbers[insertNumberIndex];
    var i = insertNumberIndex - 1;
    while (i >= 0 && Comparer.Default.Compare(numbers[i], key) > 0) {
        numbers[i + 1] = numbers[i];
        i--;
    }
    numbers[i + 1] = key;
}

也可以二分查找法找到插入元素的位置,这样可能提高插入排序算法的效率:当使用链表数据结构,插入元素不需要移动现有元素,那么使用二分查找法的插入排序算法效率可以提高到Θ(nlgn):

private int FindInsertPosition<T>(IList<T> list, T target, int start, int end, Func<T, T, int> comparer) {
    if (start > end)
        return Math.Max(start, end);
    var middle = (start + end) / 2;

    if (comparer.Invoke(target, list[middle]) < 0)
        return FindInsertPosition<T>(list, target, start, middle - 1, comparer);

    if (comparer.Invoke(target, list[middle]) > 0)
        return FindInsertPosition<T>(list, target, middle + 1, end, comparer);

    return middle;
}

private void Sort<T>(IList<T> list, Func<T, T, int> comparer) {
    for (var i = 1; i < list.Count; i++) {
        var key = list[i];

        var insertPosition = FindInsertPosition(list, key, 0, i - 1, comparer);    // Θ(nlgn)

        list.RemoveAt(i);    // Θ(1)
        list.Insert(insertPosition, key);    // Θ(1)
    }
}

插入排序算法的运行效率为Θ(n2),不高。

你可能感兴趣的:(算法,插入排序,sort,insertion)