排序算法学习笔记

排序算法学习笔记

排序算法目录如下:

  • 冒泡排序
  • 选择排序
  • 快速排序
  • 堆排序
  • 归并排序

冒泡排序

冒泡排序[1]:时间复杂度O(n^2)
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

def bubble_sort(arr):  # 冒泡排序
    for i in range(len(arr) - 1):
        for j in range(len(arr) - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
def bubble_sort_2(arr):  # 冒泡排序优化
    """假如在某一趟没有发生交换,则说明已经排好顺序,结束算法"""
    for i in range(len(arr) - 1):
        exchange = False
        for j in range(len(arr) - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
                exchange = True
        if not exchange:
            break

选择排序

选择排序[2]:时间复杂度O(n^2)
对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量min_loc来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较如果后面的元素比他要小则用变量min_loc记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。

def select_sort(arr):  # 选择排序
    """每趟找最小元素对应的下标,然后与第i个元素交换"""
    for i in range(len(arr) - 1):
        min_loc = i
        for j in range(i + 1, len(arr)):
            if arr[i] < arr[min_loc]:
                min_loc = j
        arr[i], arr[min_loc] = arr[min_loc], arr[i]

快速排序

快速排序[3]:一般时间复杂度O(nlog(n)),缺点:极端情况复杂度O(n^2)。
通过一趟排序将要排序的数据分割成独立的两部分(如下代码的position函数实现将数据分成两部分),其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

def position(arr, left, right):
    tmp = arr[left]
    while left < right:
        while left < right and arr[right] >= tmp:
            right -= 1
        arr[left] = arr[right]
        while left < right and arr[left] <= tmp:
            left += 1
        arr[right] = arr[left]
    arr[left] = tmp
    return left

def quick_sort(arr, left, right):
    if left < right:
        mid = position(arr, left, right)
        quick_sort(arr, left, mid - 1)
        quick_sort(arr, mid + 1, right)

堆排序

堆排序[4]:平均时间复杂度O(nlogn),缺点:在较快排序算法中速度较慢。
1.建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2) 其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。
2.调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调整的。
3.堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。堆排序过程的时间复杂度是O(nlgn)。因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,堆排序的时间复杂度是O(nlgn) 。

def sift(arr, low, high):
    """
    构造堆,节点的左右孩子都是堆,但本身不是堆
    arr:非堆数组
    low:第一个索引
    high:最后一个索引
    """
    i = low  # root node
    tmp = arr[i]  # root value
    j = 2 * i + 1  # left child node
    while j <= high:
        if j < high and arr[j] < arr[j + 1]:  # 如果左孩子值小于右孩子值,j指向右孩子
            j += 1
        if arr[j] > tmp:   #孩子比父亲节点大
            arr[i] = arr[j]#孩子填到父节点
            i = j          #新的父节点
            j = 2 * i + 1  #新的子节点
        else:
            break
    arr[i] = tmp#将父节点放到该放的位置


def heap_sort(arr):#堆排序
    n = len(arr)
    #构建堆
    for i in range(n // 2 - 1, -1, -1):
        sift(arr, i, n - 1)
    #堆排序
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]
        sift(arr, 0, i-1)

归并排序

归并排序[5]:时间复杂度O(nlogn),缺点:需要另开内存空间。
归并操作的工作原理如下:
1:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2:设定两个指针,最初位置分别为两个已经排序序列的起始位置
3:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾

def merge(arr, low, mid, high):
"""一次归并操作,假设low~mid和mid~high是有序序列"""
    i = low
    j = mid + 1
    tmp_arr = []
    while i <= mid and j <= high:
        if arr[i] < arr[j]:
            tmp_arr.append(arr[i])
            i += 1
        else:
            tmp_arr.append(arr[j])
            j += 1
    while i <= mid:
        tmp_arr.append(arr[i])
        i += 1
    while j <= high:
        tmp_arr.append(arr[j])
        j += 1
    arr[low:high+1] = tmp_arr


def merge_sort(arr, low, high):
"""先分解,后合并,这里的递归调用很巧妙"""
    if low < high:
        mid = (low + high) // 2
        merge_sort(arr, low, mid)
        merge_sort(arr, mid + 1, high)
        merge(arr, low, mid, high)

联系邮箱[email protected]

参考

  1. https://baike.baidu.com/item/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F
  2. https://baike.baidu.com/item/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F
  3. https://baike.baidu.com/item/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95
  4. https://baike.baidu.com/item/%E5%A0%86%E6%8E%92%E5%BA%8F。
  5. https://baike.baidu.com/item/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F

你可能感兴趣的:(算法笔记)