python 3 实现七大排序

本文详细介绍了Python 3中实现的七大排序算法,包括冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序和希尔排序。详细阐述了每个算法的原理,并给出了具体实现代码,帮助读者理解各种排序算法的时间复杂度和应用场景。

1、冒泡排序(bubble sort)

冒泡排序每次比较相邻的元素,如果前面一个数大,则交换,否则,不交换。

首先,定义了一个随机数列,然后是冒泡排序,时间复杂度O(n^2)

import random
import random
def get_list(num):
    list_ = []
    for i in range(num):
        list_.append(random.randint(0,num))
    return list_
def bubble_sort(list1):
    for i in range(len(list1)-1,0,-1):
        for j in range(i):
            if list1[j]>list1[j+1]:
                list1[j],list1[j+1]=list1[j+1],list1[j]
    return list1
list1 = get_list(10)
print(list1)
list2 = bubble_sort(list1)
print(list2)

 

结果:

 

[5, 5, 0, 4, 8, 5, 4, 6, 6, 1]
[0, 1, 4, 4, 5, 5, 5, 6, 6, 8]

每次运行的结果都不一样,但都是从小到大排序。

如果在排序的过程中已经有序,可以提前比较

def bubble_sort(arr):
    length=len(arr)
    if length<2:
        return arr
    else:
        for i in range(length-1):
            flag=False
            for j in range(length -1 -i):
                if arr[j]>arr[j+1]:
                    arr[j],arr[j+1] = arr[j+1],arr[j]
                    flag=True
            if not flag:
                break
        return arr

双向排序-鸡尾酒排序

def cocktail_sort(arr):
    length = len(arr)
    for i in range(length - 1):
        flag = False
        for j in range(length -1 -i):
            if arr[j]>arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
                flag = True
        if flag:
            flag=False
            for k in range(length -2 -i, 0, -1):
                if arr[k]<arr[k-1]:
                    arr[k], arr[k-1] = arr[k-1],arr[k]
                    flag = True
        if not flag:
            break
    return arr

2、选择排序

选择排序,选择最小的元素放在前,再从后面n-1个数,选择最小的,放在第二个位置,一直类推。。。

import random
def get_list(num):
    list_ = []
    for i in range(num):
        list_.append(random.randint(0,num))
    return list_
def selection_sort(list1):
    length = len(list1)
    for i in range(length-1):
        min_index = i
        for j in range(i+1,length):
            if list1[min_index] > list1[j]:
                min_index = j
        if min_index !=i:
            list1[i],list1[min_index] = list1[min_index],list1[i]
    return list1
list1 = get_list(10)
print(list1)
list2 = selection_sort(list1)
print(list2)

结果:

[6, 10, 3, 1, 6, 7, 5, 4, 10, 9]
[1, 3, 4, 5, 6, 6, 7, 9, 10, 10]

3、插入排序

插入排序,是待排序的元素,插入前面已经排序好的序列。

先把序列分为两部分,一是已经排序好的,二是待排序的混乱排序。

有两个序列,也就需要用for来遍历两个序列。

对于从小到大的升序排序,从未排序的序列中拿出一个元素,遍历已排序好的元素,比较大小后,确定其位置。

由于是未排序的元素插入到已经排序好的序列中,就做插入排序。

import random
import random
def get_list(num):
    list_ = []
    for i in range(num):
        list_.append(random.randint(0,num))
    return list_
def insertion_sort(list1):
    length = len(list1)
    for i in range(1,length):
        for j in range(i,0,-1):
            if list1[j] < list1[j-1]:
                list1[j-1],list1[j] = list1[j],list1[j-1]
    return list1
list1 = get_list(10)
print(list1)
list2 = insertion_sort(list1)
print(list2)

结果:

[3, 10, 2, 7, 10, 9, 5, 5, 10, 2]
[2, 2, 3, 5, 5, 7, 9, 10, 10, 10]

4,归并排序

归并排序,把序列分来,n是序列长度,n/2,n/4,n/8。。。一直分开到单个元素

然后是合并,合并前要排序

详细介绍归并排序,请看这个链接归并排序,博主写的很好

分开和合并的思路如下:

主要利用递归的思想,分开是递的过程,归是合并的过程。递归不好理解,要看成两部分,一个是递,一个是归。

递是逐渐展开,有一种从近到远的感觉;归是展开后的回归,有一种从远到近的感觉。

有一个数列,[4,5,2,1,9],分解过程如下:

         4 5 2 1 9                5个数,5//2=2,两个分支,左分支2个元素,右分支剩下的元素

               ||

    4 5         2 1 9    左边2个元素,分开。右边3个元素,3//2=1,左边一个元素 2,右边分支两个元素1 9

     ||               ||

4       5       2    1 9                                          

                          ||

                       1     9

然后是合并的过程:

比较两分支的第一个元素,拿出最小的

分开的两个元素1 , 9 合并,1,9 比较,结果【1,9】

2   1 9 的分支的合并,两个分支的第一个元素2 ,1 比较,拿出较小的1,然后2,9比较,拿出2,最后是9,结果【1,2,9】

4,5比较,结果【4,5】

【4,5】,【1,2,9】,同样两个分支的第一个元素比较拿出较小的,结果【1,2,4,5,9】

归并是先递归再合并

递归是二分法划分数据到树的子节点

合并是对两个有序序列的排序。

merge(A,B)是对两个有序序列的排序,从小到大排序

def merge(A,B):
    result = []
    left=right=0
    while left<len(A) and right<len(B):
        if A[left]<B[right]:
            result.append(A[left])
            left +=1
        else:
            result.append(B[right])
            right +=1
    if left == len(A):
        result.extend(B[right:])
    else:
        result.extend(A[left:])
    return result

def merge_sort(lis):
    mid = len(lis)//2
    if len(lis)==1:
        return lis
    left = merge_sort(lis[:mid])
    right = merge_sort(lis[mid:])
    return merge(left,right)

if __name__ == '__main__':
    a = [14, 2, 34, 4, 21, 19,1]
    print (merge_sort(a))

5 快速排序

快速排序首先选择一个基准值(pivot)

把比基准值小的元素放在基准值左边

把比基准值大的元素放在右边

最后的排序的数组就是:左边子数组 + 基准值 + 右边子数组

def quicksort(array):
        if len(array) <2:  # 基线条件:为空或者只包含一个元素的数组,它是有序的
            return array
        else:
            pivot = array[0]
            less = [each for each in array[1:] if each<=pivot]
            greater = [each for each in array[1:] if each>pivot]
            return quicksort(less) + [pivot] + quicksort(greater) # 记录了函数调用的状态当“归”时直接计算

快速排序的速度取决于选择的基准值

最佳情况:每层调用复杂度O(n),栈的高度O(log(n)) ,所以复杂度O(nlog(n))。

最坏的情况:每层调用复杂度O(n),栈的高度O(n) ,所以复杂度O(n**2)

最佳情况也是平均情况。

6 堆排序

首先根据序列构建一个完全二叉树
在完全二叉树的基础上,从最后一个非叶结点开始调整:比较三个元素的大小–自己,它的左孩子,右孩子。分为三种情况: 
自己最大,不用调整
左孩子最大,交换该非叶结点与其左孩子的值,并考察以左孩子为根的子树是否满足大顶堆的要求,不满足递归向下处理
右孩子最大,交换该非叶结点与其右孩子的值,并考察以右孩子为根的子树是否满足大顶堆的要求,不满足递归向下处理
参考https://blog.youkuaiyun.com/u011240016/article/details/53428489/ 

完成了初始堆的创建之后,就可以通过不断的重建堆进行堆排序,每次重建堆就是一趟排序,每次重建时都将堆顶节点与堆无序区的最后一个元素交换,因此每趟堆排序后堆的有序区就增加了一个元素(从数组最后与各元素开始,向前排列),下轮就使用无序区组成的堆进行重建,每次重建都只是对堆顶节点的调整,因为初始堆建成之后,其他节点都满足堆的定义。

代码实现

来源:https://www.cnblogs.com/bingabcd/p/7425039.html

升序-建立最大堆,降序-建立最小堆

def sift(data, low, high):
    i = low      # 父节点
    j = 2 * i + 1   # 左子节点
    tmp = data[i]   # 父节点值
    while j <= high:    # 子节点在节点中
        if j < high and data[j] > data[j + 1]:  # 有右子节点且右节点比父节点值大
            j += 1
        if tmp > data[j]:
            data[i] = data[j]   # 将父节点替换成新的子节点的值
            i = j   # 变成新的父节点
            j = 2 * i + 1   # 新的子节点
            data[i] = tmp

        else:
            break
    # 将替换的父节点值赋给最终的父节点


def heap_sort(data):
    n = len(data)
    # 创建堆
    for i in range(n//2-1, -1, -1):
        sift(data, i, n-1)

    # 挨个出数
    for i in range(n-1, -1, -1):    # 从大到小
        data[0], data[i] = data[i], data[0]     # 将最后一个值与父节点交互位置
        sift(data, 0, i-1)

import random
li = [5,11,7,2,3,17]
print(li)
heap_sort(li)
print(li)

时间复杂度

创建初始堆的时间复杂度是O(n),简单的解释是有n/2个节点需要调整,每次调整节点时只是上写移动常数个节点,因此创建初始堆的时间复杂度是O(n)。而实际进行堆排序时,需要进行n趟,每趟进行堆重建时就是调整堆顶节点,最多移动次数不会超过书的高度O(log n),因此时间复杂度是O(n*log n)。

堆排序对数据的原始排列状态并不敏感,所以其最坏时间复杂度、最好时间复杂度、平均时间复杂度均是O(n*log n),堆排序不是一种稳定的排序算法。

7 希尔排序

希尔排序是直接插入排序的改进

对有序序列插入排序有:直接插入排序,折半插入排序,希尔排序,后两个是改进。

L = [1, 3, 2, 32, 5, 4,7]
def Shell_sort(L):
    step = len(L)//2
    while step > 0:
        for i in range(step,len(L)):           
            while(i >= step and L[i] < L[i-step]):  
                i -= step
        step = step//2
    print(L)
Shell_sort(L)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值