【数据结构】 排序

概述总览

稳定性不是说效果稳不稳定,而是说改变位置的数值是否多。
在这里插入图片描述
工程上的排序常常是多种排序的综合。
没有说哪种排序好哪种不好,知识看场景适合不适合,快速排序之所以被认为功能强大是因为“在最好的情况下,它的渐进复杂度和堆排序和并归排序是相同的,但是常量系数比较小”。
输入比较小的时候,选择插入排序。
数组比较大的时候,使用快速排序或者其他时间复杂度是O(n*logn)的排序

一、冒泡排序

# 冒泡排序 最好O(n),最坏O(n^2),稳定
def bubblesort(arr):
    '''
    相邻两个元素交换顺序,把值较大的往后排,最坏时间复杂度为O(n2),最好的O(n)
    '''
    for i in range(1, len(arr)):
        for j in range(0, len(arr)-1):
            if arr[i] <= arr[j]:
                arr[i],arr[j] = arr[j],arr[i]
            else:
                pass
    return arr

二、选择排序

# 选择排序 总是O(n^2),不稳定
def selectionSort(arr):
    '''
    先找出数组中的最小值(或者最大值),然后不断找出剩余(i-N)中最小值排列在左端
    最坏时间复杂度O(n2)
    '''
    for i in range(len(arr)-1):
        minindex = i
        for j in range((i+1),len(arr)):
            if arr[minindex] > arr[j]:
                minindex = j
            if i != minindex:
                arr[i], arr[minindex] = arr[minindex], arr[i]
    return arr

三、插入排序

# 插入排序 最坏情况O(n),最好情况O(n^2),稳定
def insertSort(arr):
    '''
    插入的那个数不断和他前面的(每一个)数进行比较
    从arr[0]开始排列成一个有序的序列,一般来说插入排序是低效的
    preIndex相当于是索引i的一个子变量
    就好比是整理手中的牌,
    '''
    for i in range(len(arr)):
        preIndex = i-1
        current = arr[preIndex+1]
        while preIndex >= 0 and arr[preIndex] > current:
            arr[preIndex+1], arr[preIndex] = arr[preIndex], arr[preIndex+1]
            preIndex -= 1

    return arr

四、归并排序

# 归并排序 总是O(nlogn),十分稳定
def mergesort(arr):
    '''
    将数组不断变成左右两部分,然后排列成新的数组,递归,其实就是分成两个部分,
    一个是不断二分,直到数组里面就只有1个值,或者没有值,
    第二部分是将数组不断合并起来,挑选出小一点的值排在数组前面,大一点的在后面
    :return:
    '''
    if len(arr) <= 1:
        return arr
    right = len(arr)
    left = 0
    mid = int((right+left)/2)
    left_arr = arr[0: mid]
    right_arr = arr[mid:]
    return left_right_sort(mergesort(left_arr), mergesort(right_arr))

def left_right_sort(left_arr, right_arr):
    result = []
    while left_arr and right_arr:
        if left_arr[0] > right_arr[0]:
            result.append(right_arr.pop(0))
        else:
            result.append(left_arr.pop(0))
    while left_arr and not right_arr:
        result.append(left_arr.pop(0))
    while not left_arr and right_arr:
        result.append(right_arr.pop(0))
    return result

五、希尔排序

# 希尔排序 最好情况O(nlogn),最坏情况O(n(logn)^2),不稳定
def shellSort(arr):
    '''
    是在插入排序上进化而来,对于几乎已经排好的序列,希尔排序速度几乎是线性的

    '''
    n = len(arr)
    gap = int(n/2)
    while gap>0:
        for i in range(gap,n):
            j = i
            temp = arr[i]
            while j>=gap and arr[j-gap]>arr[j]:
                arr[j] = arr[j-gap]
                j-= gap
            arr[j] = temp
        gap = int(gap/2)
    return arr

六、快速排序

# 快速排序 最好情况O(nlogn),最坏情况O(n^2),不稳定
def quicksort(arr, i, j):
    '''实现快速排序的要点在于首先实现一个初步分区的代码,利用两个指针不断取值比较,最后再用递归法就可以了
    具体步骤:
    指定某个数为基准值,然后将这个值先做保存,然后比较右边指针指向的值,如果比基准值小就和基准值交换位置
    如果产生了交换行为,那么就比较另一个指针所对应的值和基准值的大小,
    再从第一个数开始两个子数组的内部排序
    '''
    if j > i:
        arr, k = adjustlocation(arr, i, j)    #得到一个初步的排序
        # 递归排序列表k下标左侧的列表
        quicksort(arr, i, k - 1)
         # 递归排序列表k下标右侧的列表
        quicksort(arr, k + 1, j)
        return arr
    else:
        i,j = j,i
        quicksort(arr, i,j)

def adjustlocation(arr, i, j):
    X = arr[i]
    keng_index = i
    while i<j:
        if i == keng_index:
            if arr[j] > X:
                j -= 1
                continue
            if arr[j] <= X:
                keng_index = j
                arr[i] = arr[j]
                i += 1
                continue
        if j == keng_index:
            if arr[i] > X:
                arr[j] = arr[i]
                keng_index = i
                j -= 1
                continue
            if arr[i] <= X:
                i += 1
                continue
    arr[keng_index] = X
    return arr, keng_index

七、堆排序

# 堆排序
def heapsort(arr):
    '''
    利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,
    堆和树的区别:堆是一种逻辑结构,树是一种存储结构,树的左孩子和右孩子有大小之分,堆没有。
    并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。
    :return:
    '''
    n = len(arr)
    # Build a maxheap.
    for i in range(n, -1, -1):
        heapify(arr, n, i)
    # 一个个交换元素
    for i in range(n-1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]  # 交换
        heapify(arr, i, 0)
    return arr


def heapify(arr,n,i):     #判断左右节点是否满足比根节点小,确保根节点的值最大
    '''
    :param arr:
    :param n: 树有几个节点
    :param i: 根节点的位置
    :return:
    '''
    largest = i
    l = 2 * i + 1  # left = 2*i + 1
    r = 2 * i + 2  # right = 2*i + 2
    if l < n and arr[i] < arr[l]:
        largest = l
    if r < n and arr[largest] < arr[r]:
        largest = r
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]  # 交换
        heapify(arr, n, largest)
    return arr

八、计数排序

# 计数排序
def countsort():
    '''
    计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
    比方说先划分成1-30,共30个段,然后再判断arr中值是属于哪一个段,对每个段元素个数进行计数。最后将元素依次取出。
    所以说计数排序对于重复性较大的数据比较方便吧
    :return:
    '''
    pass

九、基数排序

# 基数排序 
def basesort():
    '''
    0-9一共有十个段,按照数值的个位数分别对应,然后另外分一些空间将个位数按大小排列好;
    再根据十位数大小,重新分类,再重新根据十位数值大小排列好
    以此类推。。。
    :return:
    '''
    pass

十、桶排序

# 桶排序
def tongsort():
    '''
    桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:
    在额外空间充足的情况下,尽量增大桶的数量
    使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
    :return:
    '''
    pass

参考链接
https://mp.weixin.qq.com/s/vn3KiV-ez79FmbZ36SX9lg
菜鸟教程:https://www.runoob.com/w3cnote/merge-sort.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值