之前在这C语言实现八大排序算法(一)C语言实现八大排序算法(二)2篇文章中,已经详细介绍了各种排序算法的思想,参考资料主要是用C语言实现的。本文主要用python语言再次实现十大排序算法

十大排序算法的复杂度及稳定性分析如下表所示:

插入排序

代码

''' 1. 从第一个元素开始,该元素可以认为已经被排序 2.取出下一个元素,在已经排序的元素序列中从后向前扫描 3.如果该元素(已排序)大于新元素,将该元素移到下一位置 4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置 5.将新元素插入到该位置中 6.重复步骤2 '''
def insert_sort(list):
    for i in range(1,len(list)):
        print("第{}轮:".format(i))
        key=list[i]
        j=i-1
        while j>=0:
            if list[j]>key:
                list[j+1]=list[j]
                list[j]=key
            j-=1
        print(list)
    return list

a=[2,4,3,8,1,5,7,6]
result=insert_sort(a)
#print(result)

结果

1轮:
[2, 4, 3, 8, 1, 5, 7, 6]2轮:
[2, 3, 4, 8, 1, 5, 7, 6]3轮:
[2, 3, 4, 8, 1, 5, 7, 6]4轮:
[1, 2, 3, 4, 8, 5, 7, 6]5轮:
[1, 2, 3, 4, 5, 8, 7, 6]6轮:
[1, 2, 3, 4, 5, 7, 8, 6]7轮:
[1, 2, 3, 4, 5, 6, 7, 8]

希尔排序

代码

''' 1.希尔排序是把记录按下标的一定量分组,对每组使用直接插入算法排序; 2.随着增量逐渐减少,每组包1含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法被终止。 '''
def shell_sort(list):
    # 设定步长
    step = int(len(list)/2)
    while step > 0:
        print(step)
        for i in range(step, len(list)):
            # 类似插入排序, 当前值与指定步长之前的值比较, 符合条件则交换位置
            while i >= step and list[i-step] > list[i]:
                list[i], list[i-step] = list[i-step], list[i]
                i -= step
        step = int(step/2)
        print(list)
    return list

a=[2,4,3,8,1,5,7,6]
result=shell_sort(a)
#print(result)

结果

4
[1, 4, 3, 6, 2, 5, 7, 8]
2
[1, 4, 2, 5, 3, 6, 7, 8]
1
[1, 2, 3, 4, 5, 6, 7, 8]

冒泡排序

代码

''' 1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。 2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 3.针对所有的元素重复以上的步骤,除了最后一个。 4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 '''
def bubble_sort(list):
    global flag
    for i in range(len(list)-1):
        print("第{}轮:".format(i))
        flag=False                         #本次冒泡是否发生交换的标志
        for j in range(len(list)-i-1):
            if list[j]>list[j+1]:
                list[j],list[j+1]=list[j+1],list[j]
                flag=True
        print(list)
        if flag==False:                    #未交换,数组已经有序,无须冒泡
            return

a=[2,4,3,8,1,5,7,6]
result=bubble_sort(a)

结果

0轮:
[2, 3, 4, 1, 5, 7, 6, 8]1轮:
[2, 3, 1, 4, 5, 6, 7, 8]2轮:
[2, 1, 3, 4, 5, 6, 7, 8]3轮:
[1, 2, 3, 4, 5, 6, 7, 8]4轮:
[1, 2, 3, 4, 5, 6, 7, 8]

快速排序

代码

''' 1.从数列中挑出一个元素,称为 “基准”(pivot); 2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边); 3.对所有两个小数列重复第二步,直至各区间只有一个数。 '''
def quicksort(list,start,end):
    if start>=end:
        return
    low=start
    high=end
    base=list[start]
    while low<high:
        while low<high and list[high]>=base:  #从后向前找第一个小于基准值的数
            high-=1
        if low<high:
            list[low]=list[high]
            low+=1
        while low<high and list[low]<base:    #从前向后找第一个大于基准值的数
            low+=1
        if low<high:
            list[high]=list[low]
            high-=1
    list[low]=base                           #填坑

    quicksort(list,start,low-1)              #递归排序
    quicksort(list,low+1,end)

a=[2,4,3,8,1,5,7,6]
quicksort(a,0,len(a)-1)
print(a)

结果

[1, 2, 3, 4, 5, 6, 7, 8]

选择排序

代码

''' 选择排序的基本思想:比较 + 交换。 第一趟,在待排序记录r1 到 r[n]中选出最小的记录,将它与r1交换; 第二趟,在待排序记录r2 到 r[n]中选出最小的记录,将它与r2交换; 以此类推,第 i 趟,在待排序记录ri 到 r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕。 '''
def select_sort(list):
    for i in range(0,len(list)):
        print("第{}轮:".format(i))
        min=i
        for j in range(i+1,len(list)):
            if list[min]>list[j]:
                min=j
        list[min],list[i]=list[i],list[min]          #每轮找出最小的交换
        print(list)
    return list

a=[2,4,3,8,1,5,7,6]
result=select_sort(a)
#print(result)

结果

0轮:
[1, 4, 3, 8, 2, 5, 7, 6]1轮:
[1, 2, 3, 8, 4, 5, 7, 6]2轮:
[1, 2, 3, 8, 4, 5, 7, 6]3轮:
[1, 2, 3, 4, 8, 5, 7, 6]4轮:
[1, 2, 3, 4, 5, 8, 7, 6]5轮:
[1, 2, 3, 4, 5, 6, 7, 8]6轮:
[1, 2, 3, 4, 5, 6, 7, 8]7轮:
[1, 2, 3, 4, 5, 6, 7, 8]

堆排序

代码

''' 大根堆:每个节点的值都大于或等于其子节点的值,用于升序排列; 小根堆:每个节点的值都小于或等于其子节点的值,用于降序排列。 以大根堆为例,每次将最大元素放置在堆顶 '''
def adjust_heap(lists, i, size):                      #向下调整大根堆
    ''' :param lists: 数组元素 :param i: 当前结点 :param size: 数组长度 '''
    # 非叶子结点的左右两个孩子
    lchild = 2 * i + 1
    rchild = 2 * i + 2
    # 在当前结点、左孩子、右孩子中找到最大元素的索引
    max = i
    if i < size // 2:
        if lchild < size and lists[lchild] > lists[max]:
            max = lchild
        if rchild < size and lists[rchild] > lists[max]:
            max = rchild
        # 如果最大元素的索引不是当前结点,把大的结点交换到上面,继续调整堆
        if max != i:
            # 第 2 个参数传入 max 的索引是交换前大数字对应的索引
            # 交换后该索引对应的是小数字,应该把该小数字向下调整
            lists[max], lists[i] = lists[i], lists[max]
            adjust_heap(lists, max, size)

def build_heap(lists, size):                    #建立大根堆
    for i in range(0, (size//2))[::-1]:         # 从倒数第一个非叶子结点开始建立大根堆
        adjust_heap(lists, i, size)             # 对所有非叶子结点进行堆的调整

def heap_sort(lists):
    size = len(lists)
    build_heap(lists, size)
    for i in range(0, size)[::-1]:
        lists[0], lists[i] = lists[i], lists[0]     # 每次根结点都是最大的数,最大数放到后面
        adjust_heap(lists, 0, i)       # 交换完后还需要继续调整堆,只需调整根节点,此时数组的 size 不包括已经排序好的数
        print("第{}轮:".format(size-i))
        print(lists)                     # 由于每次大的都会放到后面,因此最后的 lists 是从小到大排列

a=[2,4,3,8,1,5,7,6]
result=heap_sort(a)

结果

1轮:
[7, 6, 5, 4, 1, 2, 3, 8]2轮:
[6, 4, 5, 3, 1, 2, 7, 8]3轮:
[5, 4, 2, 3, 1, 6, 7, 8]4轮:
[4, 3, 2, 1, 5, 6, 7, 8]5轮:
[3, 1, 2, 4, 5, 6, 7, 8]6轮:
[2, 1, 3, 4, 5, 6, 7, 8]7轮:
[1, 2, 3, 4, 5, 6, 7, 8]8轮:
[1, 2, 3, 4, 5, 6, 7, 8]

归并排序

代码

''' 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列; 2.设定两个指针,最初位置分别为两个已经排序序列的起始位置 3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置; 4.重复步骤③直到某一指针达到序列尾; 5.将另一序列剩下的所有元素直接复制到合并序列尾。 '''
def merge(left_list,right_list):
    left_index=0
    right_index=0
    merge_list=[]
    while left_index<len(left_list) and right_index<len(right_list):
        if left_list[left_index]<right_list[right_index]:   #哪一部分小,就添加到合并的列表中
            merge_list.append(left_list[left_index])
            left_index+=1
        else:
            merge_list.append(right_list[right_index])
            right_index+=1
    merge_list+=left_list[left_index:]                   #将剩余的部分添加到合并列表中
    merge_list+=right_list[right_index:]
    return merge_list

def merge_sort(list):
    if len(list)<=1:
        return list
    mid_index=len(list)//2            #拆分数组为两部分
    left_list=merge_sort(list[:mid_index])
    right_list=merge_sort(list[mid_index:])
    return merge(left_list,right_list)

a=[2,4,3,8,1,5,7,6]
result=merge_sort(a)
print(result)

结果

[1, 2, 3, 4, 5, 6, 7, 8]

基数排序

代码

''' 将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。 然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。 '''
def radix_sort(list):
    i = 0 # 记录当前正在排拿一位,最低位为1
    max_num = max(list)  # 最大值
    j = len(str(max_num))  # 记录最大值的位数
    while i < j:
        bucket_list =[[] for _ in range(10)] #初始化桶数组
        for x in list:
            bucket_list[int(x / (10**i)) % 10].append(x) # 找到位置放入桶数组
        print("第{}轮:".format(i+1))
        print(bucket_list)
        list.clear()
        for x in bucket_list:   # 放回原序列
            for y in x:
                list.append(y)
        print(list)
        i += 1
    return list


a = [334,5,67,345,7,5345,99,4,23,78,45,1,453,3424]
result=radix_sort(a)
# print(result)

结果

1轮:
[[], [1], [], [23, 453], [334, 4, 3424], [5, 345, 5345, 45], [], [67, 7], [78], [99]]
[1, 23, 453, 334, 4, 3424, 5, 345, 5345, 45, 67, 7, 78, 99]2轮:
[[1, 4, 5, 7], [], [23, 3424], [334], [345, 5345, 45], [453], [67], [78], [], [99]]
[1, 4, 5, 7, 23, 3424, 334, 345, 5345, 45, 453, 67, 78, 99]3轮:
[[1, 4, 5, 7, 23, 45, 67, 78, 99], [], [], [334, 345, 5345], [3424, 453], [], [], [], [], []]
[1, 4, 5, 7, 23, 45, 67, 78, 99, 334, 345, 5345, 3424, 453]4轮:
[[1, 4, 5, 7, 23, 45, 67, 78, 99, 334, 345, 453], [], [], [3424], [], [5345], [], [], [], []]
[1, 4, 5, 7, 23, 45, 67, 78, 99, 334, 345, 453, 3424, 5345]

计数排序

代码

''' 1.找到给定序列的最小值与最大值 2.创建一个长度为最大值-最小值+1的数组,初始化都为0 然后遍历原序列,记录每个数据出现的次数 此时数组中已经记录好每个值的数量,自然也就是有序的了 '''
def count_sort(list):
    # 找到最大最小值
    min_num = min(list)
    max_num = max(list)
    # 计数列表,即桶的个数
    count_list = [0]*(max_num-min_num+1)
    print(count_list)
    # 将元素值作为键值存储在桶中,记录其出现的次数
    for i in list:
        count_list[i-min_num] += 1   #最小值作为一个偏移量存在,因为数据可能存在负数的
    print(count_list)
    list.clear()
    # 填回
    for ind,i in enumerate(count_list):  #ind为索引,i为数据
        while i != 0:
            list.append(ind+min_num)     #数据的真实值
            i -= 1                       #该数据出现的次数
    return list

a = [34,5,7,34,9,5,23,12,1]
result=count_sort(a)
print(result)

结果

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]
[1, 5, 5, 7, 9, 12, 23, 34, 34]

桶排序

代码

''' 桶排序与计数排序类似,但可以解决非整数的排序 1.桶排序相当于把计数数组划分为按顺序的几个部分 2.每一部分叫做一个桶,它来存放处于该范围内的数 3.然后再对每个桶内部进行排序,可以使用其他排序方法如快速排序 4.最后整个桶数组就是排列好的数据,再将其返回给原序列 '''
def bucket_sort(list):

    min_num = min(list)
    max_num = max(list)
    # 桶的大小
    bucket_range = (max_num-min_num) / len(list)
    # 桶数组
    count_list = [ [] for i in range(len(list) + 1)]
    print(count_list)
    # 向桶数组填数
    for i in list:
        count_list[int((i-min_num)//bucket_range)].append(i)
    print(count_list)
    list.clear()
    # 回填,这里桶内部排序直接调用了sorted
    for i in count_list:
        for j in sorted(i):
            list.append(j)
        print(list)
    return list

a = [37,5,7.8,37,9,5,23,12,1]
result=bucket_sort(a)
#print(result)

结果

[[], [], [], [], [], [], [], [], [], []]
[[1], [5, 7.8, 5], [9, 12], [], [], [23], [], [], [], [37, 37]]
[1]
[1, 5, 5, 7.8]
[1, 5, 5, 7.8, 9, 12]
[1, 5, 5, 7.8, 9, 12]
[1, 5, 5, 7.8, 9, 12]
[1, 5, 5, 7.8, 9, 12, 23]
[1, 5, 5, 7.8, 9, 12, 23]
[1, 5, 5, 7.8, 9, 12, 23]
[1, 5, 5, 7.8, 9, 12, 23]
[1, 5, 5, 7.8, 9, 12, 23, 37, 37]