排序算法之插入排序及其优化

#插入排序html


其余排序方法:选择排序冒泡排序归并排序快速排序插入排序希尔排序python


##思想 先将数组第一个元素做为一个排好序的序列,而后将数组中剩下的元素从左往右一个一个地按照大小插进此序列里,所插位置后面的元素都日后移一位,直到元素所有插完。 这个很好理解,就像咱们玩扑克牌的时候,一张一张地摸牌,刚摸到手的一张牌,找到合适的位置后,插进去,右边的牌就要挪个位置。算法

##图解 再次借用一下百科的图emmm: shell

##性能 插入排序最好的状况就是你每次插入的元素都恰好是插在最后,那就只用进行n-1次比较就好了,时间复杂度为O(n); 最坏状况的时间复杂度显然是O(n2),平均时间复杂度也为O(n2)。数组

##代码 在找出正确的插入位置时,先比较先后元素位置是否正确,正确的话就结束循环;不正确的话,前面的元素日后移一位,继续比较前一位。 有两种方式,一种就是每比较一次就互换位置,另外一种就是先记住须要插入的元素,须要换位置的时候就先把前一位元素后移一位,等找到合适的位置在插入。 这时候有些人就会图方便(譬如我),选择第一种方式,这样代码写起来好看,也容易理解,但这样子效率会比第二种方式低。 因此仍是推荐使用第二种方式。数据结构

# 插入排序
def insertionSort1(arr):
    for i in range(1, len(arr)):
        j = i
        while j > 0:
            if arr[j] < arr[j - 1]:
                arr[j], arr[j - 1] = arr[j - 1], arr[j] #这里能够改进一下
                j -= 1
            else:
                break

def insertionSort2(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i
        while j > 0:
            if arr[j - 1] > key:
                arr[j] = arr[j - 1]
                j -= 1
            else:
                break
        if (i != j): arr[j] = key

##优化 上面的排序算法也叫直接插入排序,那也就是说有不那么直接的插入排序咯。 直接插入排序是从后往前一个个地进行比较来找出插入位置的。学过查找算法的人都知道这样并不高效,咱们能够利用其余查找方法来代替它。性能

###优化一 二分插入排序 二分插入排序是指在简单插入排序的基础上用二分查找算法来找出插入位置的排序算法。大数据

# 二分查找
# size 为有序部分大小
def binarySearch(arr, size, key):
    # 最左下标为0, 最右下标为size-1
    left, right = 0, size - 1
    while left <= right:
        # mid为中间元素的下标
        mid = left + right >> 1
        # 中间元素恰好与插入元素相同时,返回中间元素后一位的下标
        if key == arr[mid]:
            return mid + 1
        elif key < arr[mid]:
            # 查找左半边
            right = mid - 1
        else:
            # 查找右半边
            left = mid + 1
    # 结束循环时,left一定等于right+1
    # 最后一次查找若是是查找左半边,则key比arr[mid]小,key应该插入到mid的位置,而mid等于如今的right+1等于left
    # 最后一次查找若是是查找右半边,则key比arr[mid]大,key应该插入到mid+1的位置,而mid+1等于如今的left
    # 因此只需返回left
    return left


# 二分插入排序(插入排序优化一)
def binarySort(arr):
    for i in range(1, len(arr)):
        # 须要插入的元素
        key = arr[i]
        # 利用二分查找来找到插入的位置
        pos = binarySearch(arr, i, key)
        j = i
        # 插入位置后面的元素所有后移一位
        while j > pos:
            arr[j] = arr[j - 1]
            j -= 1
        # 插入元素
        arr[j] = key

###优化二 希尔排序 直接插入排序在找到插入位置时,须要一个一个地日后移动元素。有没有什么办法能够一会儿移动多个呢?答案是不能够哈哈。 由于元素已是有序的,新的元素插到中间,那其右边的元素一定都要日后移一位。 咱们换个角度来想,有序不行,那就在元素仍是无序的时候,跳着来移动。这就要提到希尔排序算法了。优化

希尔排序大概就是,选一组递减的整数做为增量序列。最小的增量必须为1:\(D_M>D_{M-1}>...>D_1=1\)spa

  • 先用第一个增量把数组分为若干个子数组,每一个子数组中的元素下标距离等于增量;
  • 而后对每一个子数组进行简单插入排序
  • 再使用第二个增量,继续一样的操做,直到增量序列里的增量都使用过一次。 (增量为1时,其实就是对整个数组进行简单插入排序)

看图更容易理解吧: (借用一下慕课的浙大数据结构课件。由于课件本来是ppt,而我只有pdf,因此颜色没有上齐,请将就将就emmm)

希尔排序快不快主要取决于咱们怎么取增量序列,最多见的取法就是:\(D_M=\lfloor N/2 \rfloor, D_k=\lfloor D_{k+1}/2 \rfloor\)

# 希尔排序
# 增量序列为D(M)=N/2, D(k)=D(k+1)/2 向下取整
def shellSort(arr):
    size = len(arr)
    # 正整数右移一位至关于除以2且向下取整
    step = size >> 1
    while step > 0:
        for i in range(step, size):
            j = i
            tmp = arr[j]
            while j >= step:
                if tmp < arr[j - step]:
                    arr[j] = arr[j - step]
                    j -= step
                else:
                    break
            arr[j] = tmp
        step = step >> 1

这就是原始希尔排序,关于希尔排序的其余增量序列我会在下一篇文章再做介绍:希尔排序


其余排序方法:选择排序冒泡排序归并排序快速排序插入排序希尔排序

相关文章
相关标签/搜索