拉勾技术人年薪【50W+】成长计划!

说明:

用Python实现十大排序算法,仅有简单解释,无算法的详细介绍。

相关术语:

稳定排序:如果a原本在b的前面,且a==b,排序之后a仍然在b的前面,则为稳定排序。

非稳定排序:如果a原本在b的前面,且a==b,排序之后a可能不在b的前面,则为非稳定排序。

原地排序:指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换。

非原地排序:需要利用额外的数组来辅助排序。

排序算法(默认从小到大进行排序)

选择排序、插入排序、冒泡排序、希尔排序、归并排序、快速排序、堆排序、基数排序、桶排序、基数排序

1.选择排序

步骤:

1.找到数组中最小的元素

2.将它和数组中的第一个元素交换位置

3.在剩下的元素中找到最小的元素,将它与数组中的第二个元素交换位置

4.重复以上操作,直到将整个数组排序

def selectSort(arr):
    length = len(arr)
    for i in range(length-1):
        min_index = i
        for j in range(i+1,length):
            if arr[j] < arr[min_index]:
                min_index = j
        arr[i], arr[min_index] = arr[min_index], arr[i]
    return arr

性质:时间复杂度:O(n2)、空间复杂度:O(1)、非稳定排序、原地排序

2.插入排序

步骤:

1.从数组的第2个元素开始抽取

2.将它与左边的第一个元素比较,如果左边第一个元素比它大,则继续与左边第二个元素比较,直到遇到不比它大的元素,插入到该元素的右边

3.继续抽取第3、4、5……n个元素,重复步骤2,选择适当的位置插入

def insertSort(arr):
    length = len(arr)
    for i in range(1,length):
        j = i - 1
        while j >= 0 and arr[j] > arr[i]:
            j -= 1
        t = arr.pop(i)
        arr.insert(j+1,t)
    return arr

性质:时间复杂度:O(n2)、空间复杂度:O(1)、稳定排序、原地排序

3.冒泡排序

步骤:

1.把第一个元素和第二个元素进行比较,如果第一个比第二个大,则交换他们的位置

2.比较第二个元素和第三个元素,如果第二个比第三个大,则交换位置

3.一直比较到数组的最后一个元素,这样一趟交换下来,最后一个元素就会是最大的数

4.除去最后一个元素,对剩余的元素重复以上操作,直到排序完成

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

性质:时间复杂度:O(n2)、空间复杂度:O(1)、稳定排序、原地排序

4.希尔排序

步骤:

1.将较大的数据集分为若干小组,比如第一组:[0,h,2h,3h……]、第二组:[1,h+1,2h+1……]……(这里h为增量)

2.轮流对每一小组进行插入排序,使得整个数组部分有序

3.令h=h/2,重新进行分组,轮流对每一小组进行插入排序

4.重复3操作,直到h=1,即整个数组被分为一组

5.对这一组数据进行排序

def ShellSort(arr):
    length = len(arr)
    gap = length // 2
    while gap > 0:
        for i in range(gap,length):
            insertI(arr,gap,i)
        gap = gap // 2
    return arr

def insertI(arr,gap,i):
    temp = arr[i]
    j = i - gap
    while j >= 0 and temp < arr[j]:
        arr[j+gap] = arr[j]
        j = j - gap
    arr[j+gap] = temp

性质:时间复杂度:O(nlogn)、空间复杂度:O(1)、非稳定排序、原地排序

5.归并排序

步骤:

1.将待排序的数组分为两个后分别排好序,再将排好序的两个数组合并成一个有序数组

2.可以将数组一直分割,直到数组的大小为1,此时只有一个元素,那么该数组即为有序的

3.再将两个大小为1的数组合并成一个大小为2的,再把大小为2的数组合并成一个大小为4的……直到全部合并

def mergerSort(arr):
    n = len(arr)
    if n == 1:
        return arr
    mid = n // 2
    left = mergerSort(arr[:mid])
    right = mergerSort(arr[mid:])
    return mergeArray(left,right)

#合并两个有序数组
def mergeArray(arr1,arr2):
    n1 = len(arr1)
    n2 = len(arr2)
    temp = []
    i = 0
    j = 0
    while i <= n1-1 and j <= n2-1:
        if arr1[i] < arr2[j]:
            temp.append(arr1[i])
            i += 1
        else:
            temp.append(arr2[j])
            j += 1
    if i <= n1-1:
        temp.extend(arr1[i:])
    if j <= n2-1:
        temp.extend(arr2[j:])
    return temp

性质:时间复杂度:O(nlogn)、空间复杂度:O(n)、稳定排序、非原地排序

6.快速排序

步骤:

1.选取数组的某个元素,称之为主元

2.将大于等于主元的元素放到主元的右边,将小于主元的元素放到主元的左边

3.主元把数组分成了两部分,采用递归,对左右两部分分别采取1、2步骤,直到子数组只有1个或0个元素

def quickSort(arr):
    return q_sort(arr, 0, len(arr)-1)

#选取第一个元素作为主元
def q_sort(arr, left, right):
    if left < right:
        mid = Partition(arr, left, right)
        arr = q_sort(arr, left, mid - 1)
        arr = q_sort(arr, mid + 1, right)
    return arr

def Partition(arr, left, right):
    pivot = arr[left]
    i = left + 1
    j = right
    while i <= j:
        while i <= j and arr[i] < pivot:
            i += 1
        while i <= j and arr[j] > pivot:
            j -= 1
        if i >= j:
            break
        arr[i],arr[j] = arr[j], arr[i]
    arr[left] = arr[j]
    arr[j] = pivot
    return j

性质:时间复杂度:O(nlogn)、空间复杂度:O(logn)、非稳定排序、原地排序

7.堆排序

堆顶的元素是堆的最大值或最小值,这里考虑大顶堆。

步骤:

1.将堆顶元素与最后一个元素互换

2.破坏了堆的特性后,将剩余元素再次构成一个大顶堆

3.将堆顶元素与最后第二个元素互换

4.重复以上操作,直到剩余一个元素,则完成排序

def headSort(arr):
    #构建堆
    length = len(arr)
    t = (length - 2) // 2
    for i in range(t,-1,-1): #下标不包含-1
        downHead(arr,i,length-1)
    #互换后下沉进行堆排序
    for i in range(length-1,0,-1):
        arr[0], arr[i] = arr[i], arr[0]
        downHead(arr,0,i-1)
    return arr

def downHead(arr,parent,length):
    temp = arr[parent]
    #左孩子
    child = 2 * parent + 1
    while child <= length:
        #定位到较大的孩子
        if child + 1 <= length and arr[child+1] > arr[child]:
            child += 1
        if temp > arr[child]:
            break
        arr[parent] = arr[child]
        parent = child
        child = 2 * parent + 1
    arr[parent] = temp

性质:时间复杂度:O(nlogn)、空间复杂度:O(1)、非稳定排序、原地排序

8.计数排序

计数排序适合最大值和最小值的差值不是很大的排序

步骤:

1.找出数组中的最大值和最小值

2.构建一个长度为(max-min+1)的连续数组A

3.统计数组中每个元素出现的次数,存入A中

4.再把临时数组A中的数据从小到大汇总起来,出现几次就输出几次

def countSort(arr):
    min_arr = min(arr)
    max_arr = max(arr)
    len = max_arr - min_arr + 1
    temp = [0] * len
    result = []
    for t in arr:
        temp[t-min_arr] = temp[t-min_arr] + 1
    for i in range(min_arr,max_arr+1):
        p = [i]*temp[i-min_arr]
        result.extend(p)
    return result

性质:时间复杂度:O(n+k)、空间复杂度:O(k)、稳定排序、非原地排序(k为临时数组的大小)

9.桶排序

当数列取值范围过大,或者不是整数时,不能适用计数排序

步骤:

1.创建若干个桶,确定每一个桶的区间范围,里面可以承载一个或多个元素

2.遍历原数列,把元素对号入座放入各个桶中

3.每个桶内部的元素分别排序

4.遍历所有桶,输出所有元素

def bucketSort(arr):
    n = len(arr)
    min_arr = min(arr)
    max_arr = max(arr)
    result = []
    #创建n个桶
    new_list = [[] for _ in range(n)]
    #区间跨度大小
    length = (max_arr - min_arr) // (n - 1)
    for data in arr:
        index = int((data - min_arr) // (length + 1))
        new_list[index].append(data)
    for i in range(n):
        new_list[i].sort()
    for i in range(n):
        for j in range(len(new_list[i])):
            result.append(new_list[i][j])
    return result

性质:时间复杂度:O(n+k)、空间复杂度:O(n+k)、稳定排序、非原地排序(k为桶的个数)

10.基数排序

步骤:

1.先以个位数的大小来对数据进行排序,接着以十位数的大小来对数据进行排序,接着是百位数……

2.在以某位数进行排序时,需要准备0-9的10个桶,把相同数值的数放在同一个桶里

def radioSort(arr):
    #计算最大值是几位数
    num = 1
    max_arr = max(arr)
    while max_arr // 10 > 0:
        max_arr = max_arr // 10
        num += 1
    for i in range(1,num+1):
        bucket = [[] for _ in range(10)]
        for j in range(len(arr)):
            radio = (arr[j] // int(pow(10,i-1))) % 10
            bucket[radio].append(arr[j])
        k = 0
        for i in range(10):
            for j in range(len(bucket[i])):
                arr[k] = bucket[i][j]
                k += 1
    return arr

性质:时间复杂度:O(kn)、空间复杂度:O(n+k)、稳定排序、非原地排序(k为桶的个数)

 

内容来源于网络如有侵权请私信删除