python实现十大排序算法

算法和数据结构是程序员的必修课
在这里插入图片描述
前两篇博文我们分别用C++和Java实现了十大排序算法

C++实现十大排序算法

Java实现十大排序算法

现在我们用python来实现一下十大排序算法
具体代码可以访问我的GitHub地址获取

https://github.com/liuzuoping/Algorithms

在这里插入图片描述

1 冒泡排序

冒泡排序无疑是最为出名的排序算法之一,从序列的一端开始往另一端冒泡(你可以从左往右冒泡,也可以从右往左冒泡,看心情),依次比较相邻的两个数的大小(到底是比大还是比小也看你心情)。

在这里插入图片描述

python实现冒泡排序
def bubble_sort(arr):
    """冒泡排序"""
    # 第一层for表示循环的遍数
    for i in range(len(arr) - 1):
        # 第二层for表示具体比较哪两个元素
        for j in range(len(arr) - 1 - i):
            if arr[j] > arr[j + 1]:
                # 如果前面的大于后面的,则交换这两个元素的位置
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
    return arr

2 选择排序

选择排序的思路是这样的:首先,找到数组中最小的元素,拎出来,将它和数组的第一个元素交换位置,第二步,在剩下的元素中继续寻找最小的元素,拎出来,和数组的第二个元素交换位置,如此循环,直到整个数组排序完成。
至于选大还是选小,这个都无所谓,你也可以每次选择最大的拎出来排,也可以每次选择最小的拎出来的排,只要你的排序的手段是这种方式,都叫选择排序。

在这里插入图片描述

python实现选择排序
def selection_sort(arr):
    """选择排序"""
    # 第一层for表示循环选择的遍数
    for i in range(len(arr) - 1):
        # 将起始元素设为最小元素
        min_index = i
        # 第二层for表示最小元素和后面的元素逐个比较
        for j in range(i + 1, len(arr)):
            if arr[j] < arr[min_index]:
                # 如果当前元素比最小元素小,则把当前元素角标记为最小元素角标
                min_index = j
        # 查找一遍后将最小元素与起始元素互换
        arr[min_index], arr[i] = arr[i], arr[min_index]
    return arr

3 插入排序

插入排序的思想和我们打扑克摸牌的时候一样,从牌堆里一张一张摸起来的牌都是乱序的,我们会把摸起来的牌插入到左手中合适的位置,让左手中的牌时刻保持一个有序的状态。那如果我们不是从牌堆里摸牌,而是左手里面初始化就是一堆乱牌呢? 一样的道理,我们把牌往手的右边挪一挪,把手的左边空出一点位置来,然后在乱牌中抽一张出来,插入到左边,再抽一张出来,插入到左边,再抽一张,插入到左边,每次插入都插入到左边合适的位置,时刻保持左边的牌是有序的,直到右边的牌抽完,则排序完毕。

在这里插入图片描述

python实现插入排序
def insertion_sort(arr):
    """插入排序"""
    # 第一层for表示循环插入的遍数
    for i in range(1, len(arr)):
        # 设置当前需要插入的元素
        current = arr[i]
        # 与当前元素比较的比较元素
        pre_index = i - 1
        while pre_index >= 0 and arr[pre_index] > current:
            # 当比较元素大于当前元素则把比较元素后移
            arr[pre_index + 1] = arr[pre_index]
            # 往前选择下一个比较元素
            pre_index -= 1
        # 当比较元素小于当前元素,则将当前元素插入在 其后面
        arr[pre_index + 1] = current
    return arr

4 希尔排序

希尔排序这个名字,来源于它的发明者希尔,也称作“缩小增量排序”,是插入排序的一种更高效的改进版本。我们知道,插入排序对于大规模的乱序数组的时候效率是比较慢的,因为它每次只能将数据移动一位,希尔排序为了加快插入的速度,让数据移动的时候可以实现跳跃移动,节省了一部分的时间开支。
在这里插入图片描述希尔排序:每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1。

在这里插入图片描述

python实现希尔排序
def shell_sort(arr):
    """希尔排序"""
    # 取整计算增量(间隔)值
    gap = len(arr) // 2
    while gap > 0:
        # 从增量值开始遍历比较
        for i in range(gap, len(arr)):
            j = i
            current = arr[i]
            # 元素与他同列的前面的每个元素比较,如果比前面的小则互换
            while j - gap >= 0 and current < arr[j - gap]:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = current
        # 缩小增量(间隔)值
        gap //= 2
    return arr

5 归并排序

归并字面上的意思是合并,归并算法的核心思想是分治法,就是将一个数组一刀切两半,递归切,直到切成单个元素,然后重新组装合并,单个元素合并成小数组,两个小数组合并成大数组,直到最终合并完成,排序完毕。
在这里插入图片描述

python实现归并排序
def merge_sort(arr):
    """归并排序"""
    if len(arr) == 1:
        return arr
    # 使用二分法将数列分两个
    mid = len(arr) // 2
    left = arr[:mid]
    right = arr[mid:]
    # 使用递归运算
    return marge(merge_sort(left), merge_sort(right))


def marge(left, right):
    """排序合并两个数列"""
    result = []
    # 两个数列都有值
    while len(left) > 0 and len(right) > 0:
        # 左右两个数列第一个最小放前面
        if left[0] <= right[0]:
            result.append(left.pop(0))
        else:
            result.append(right.pop(0))
    # 只有一个数列中还有值,直接添加
    result += left
    result += right
    return result

6 快速排序

快速排序的核心思想也是分治法,分而治之。它的实现方式是每次从序列中选出一个基准值,其他数依次和基准值做比较,比基准值大的放右边,比基准值小的放左边,然后再对左边和右边的两组数分别选出一个基准值,进行同样的比较移动,重复步骤,直到最后都变成单个元素,整个数组就成了有序的序列。
在这里插入图片描述

python实现快速排序
import random


def fun1(list1, low, high):
    # 以列表中的第一个数据为关键字
    key = list1[low]
    while low < high:
        while low < high and list1[high] >= key:
            high -= 1
        list1[low] = list1[high]
        while low < high and list1[low] <= key:
            low += 1
        list1[high] = list1[low]
    list1[low] = key
    return low


# 递归实现
def fun(list1, low, high):
    if low < high:
        # 获取中轴位置
        mid = fun1(list1, low, high)
        # 分为左右两个子表
        # 左表
        fun(list1, low, mid - 1)
        # 右表
        fun(list1, mid + 1, high)


def main():
    # 定义一个列表,存放十个数据,排序使用
    list1 = []
    for i in range(10):
        number = random.randint(1, 10)
        list1.append(number)
    fun(list1, 0, 9)
    print(list1)


if __name__ == '__main__':
    main()

7 堆排序

堆排序顾名思义,是利用堆这种数据结构来进行排序的算法。堆是一种优先队列,两种实现,最大堆和最小堆,由于我们这里排序按升序排,所以就直接以最大堆来说吧。
我们完全可以把堆(以下全都默认为最大堆)看成一棵完全二叉树,但是位于堆顶的元素总是整棵树的最大值,每个子节点的值都比父节点小,由于堆要时刻保持这样的规则特性,所以一旦堆里面的数据发生变化,我们必须对堆重新进行一次构建。
既然堆顶元素永远都是整棵树中的最大值,那么我们将数据构建成堆后,只需要从堆顶取元素不就好了吗? 第一次取的元素,是否取的就是最大值?取完后把堆重新构建一下,然后再取堆顶的元素,是否取的就是第二大的值? 反复的取,取出来的数据也就是有序的数据

在这里插入图片描述

python实现堆排序
import time, random


def sift_down(arr, node, end):
    root = node
    # print(root,2*root+1,end)
    while True:
        # 从root开始对最大堆调整

        child = 2 * root + 1  # left child
        if child > end:
            # print('break',)
            break
        print("v:", root, arr[root], child, arr[child])
        print(arr)
        # 找出两个child中交大的一个
        if child + 1 <= end and arr[child] < arr[child + 1]:  # 如果左边小于右边
            child += 1  # 设置右边为大

        if arr[root] < arr[child]:
            # 最大堆小于较大的child, 交换顺序
            tmp = arr[root]
            arr[root] = arr[child]
            arr[child] = tmp

            # 正在调整的节点设置为root
            # print("less1:", arr[root],arr[child],root,child)

            root = child  #
            # [3, 4, 7, 8, 9, 11, 13, 15, 16, 21, 22, 29]
            # print("less2:", arr[root],arr[child],root,child)
        else:
            # 无需调整的时候, 退出
            break
    # print(arr)
    print('-------------')


def heap_sort(arr):
    # 从最后一个有子节点的孩子还是调整最大堆
    first = len(arr) // 2 - 1
    for i in range(first, -1, -1):
        sift_down(arr, i, len(arr) - 1)
    # [29, 22, 16, 9, 15, 21, 3, 13, 8, 7, 4, 11]
    print('--------end---', arr)
    # 将最大的放到堆的最后一个, 堆-1, 继续调整排序
    for end in range(len(arr) - 1, 0, -1):
        arr[0], arr[end] = arr[end], arr[0]
        sift_down(arr, 0, end - 1)
        # print(arr)


def main():
    # [7, 95, 73, 65, 60, 77, 28, 62, 43]
    # [3, 1, 4, 9, 6, 7, 5, 8, 2, 10]
    # l = [3, 1, 4, 9, 6, 7, 5, 8, 2, 10]
    # l = [16,9,21,13,4,11,3,22,8,7,15,27,0]
    array = [16, 9, 21, 13, 4, 11, 3, 22, 8, 7, 15, 29]
    # array = []
    # for i in range(2,5000):
    #    #print(i)
    #    array.append(random.randrange(1,i))

    print(array)
    start_t = time.time()
    heap_sort(array)
    end_t = time.time()
    print("cost:", end_t - start_t)
    print(array)
    # print(l)
    # heap_sort(l)
    # print(l)


if __name__ == "__main__":
    main()

8 计数排序

计数排序是一种非基于比较的排序算法,我们之前介绍的各种排序算法几乎都是基于元素之间的比较来进行排序的,计数排序的时间复杂度为 O(n + m ),m 指的是数据量,说的简单点,计数排序算法的时间复杂度约等于 O(n),快于任何比较型的排序算法。
在这里插入图片描述

python实现计数排序
from numpy.random import randint


def ConutingSort(A):
    k = max(A)  # A的最大值,用于确定C的长度
    C = [0] * (k + 1)  # 通过下表索引,临时存放A的数据
    B = (len(A)) * [0]  # 存放A排序完成后的数组
    for i in range(0, len(A)):
        C[A[i]] += 1  # 记录A有哪些数字,值为A[i]的共有几个
    for i in range(1, k + 1):
        C[i] += C[i - 1]  # A中小于i的数字个数为C[i]
    for i in range(len(A) - 1, -1, -1):
        B[C[A[i]] - 1] = A[i]  # C[A[i]]的值即为A[i]的值在A中的次序
        C[A[i]] -= 1  # 每插入一个A[i],则C[A[i]]减一
    return B


A = list(randint(1, 99, 10))
print(A)
A = ConutingSort(A)
print(A)

桶排序

桶排序可以看成是计数排序的升级版,它将要排的数据分到多个有序的桶里,每个桶里的数据再单独排序,再把每个桶的数据依次取出,即可完成排序。
在这里插入图片描述

python实现桶排序
import random
# 计时器:
import time


def cal_time(func):
    def wapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("%s running time is %s s:" % (func.__name__, end_time - start_time))
        return result

    return wapper


@cal_time
def count_sort(li, max_num):
    count = [0 for i in range(max_num + 1)]
    for num in li:
        count[num] += 1
    i = 0
    for num, m in enumerate(count):
        for j in range(m):
            li[i] = num
            i += 1


# 创建一个随机数列
data = []
for i in range(1000):
    data.append(random.randint(0, 100))
print(data)

count_sort(data, 100)
print(data)

10 基数排序

基数排序是一种非比较型整数排序算法,其原理是将数据按位数切割成不同的数字,然后按每个位数分别比较。
假设说,我们要对 100 万个手机号码进行排序,应该选择什么排序算法呢?排的快的有归并、快排时间复杂度是 O(nlogn),计数排序和桶排序虽然更快一些,但是手机号码位数是11位,那得需要多少桶?内存条表示不服。
这个时候,我们使用基数排序是最好的选择。

在这里插入图片描述

python实现基数排序
import math


# 基数排序

def radix_sort(the_list, radix=10):
    # print math.log(max(the_list), radix)
    # print max(the_list)
    i = int(math.ceil(math.log(max(the_list), radix)))
    print
    i
    # log(radix)max(the_list),radix为底,max(the_list)的对数,其中radix为底数,max(the_list)为真数,这样就巧妙的获取了数字的位数
    bucket = [[] for i in range(radix)]
    # print bucket
    for i in range(1, i + 1):  # i次循环
        # print(the_list)
        for val in the_list:
            # print val
            # print radix
            # print val % (radix ** i)
            # print(radix ** (i - 1))
            print
            "+++++++++++++++" + str(val % (radix ** i) / (radix ** (i - 1)))
            bucket[int(val % (radix ** i) / (radix ** (i - 1)))].append(val)  # 析取整数第K位数字 (从低到高)
        print
        bucket
        # print the_list[:]
        del the_list[:]  # 把列表清空但列表还在,效果同the_list=[]一样

        for each in bucket:
            the_list.extend(each)  # 桶合并
        # the_list=bucket
        print
        "======================"
        # print the_list
        bucket = [[] for i in range(radix)]

    return the_list


if __name__ == '__main__':
    the_list = [10, 1, 18, 30, 23, 12, 7, 5, 18, 17]
    print("排序前:" + str(the_list))
    print("排序后:" + str(radix_sort(the_list)))

好啦,python,C++,Java版本的排序算法都更新好了
欢迎fork,star我的GitHub

  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值