堆排序、冒泡、选择、插入、归并、希尔等排序算法的Python实现

先引用这哥们的博客:https://blog.csdn.net/qq_41239584/article/details/82193879

一,冒泡排序

 

时间复杂度:O(n2)

 

稳定性:稳定

 

   冒泡排序我就不多讲了,大体上就是比较相邻的两个数,每次把较大的数沉底。流程图大致上如下:

  图是截得别人的,只是说明一下,代码没有参看别人的,写的不好,有更好的写法可以一起探讨。下面是代码:

 1 def bubble(list):
 2     #print(list)
 3     for index in range(1,len(list)):  #比较6趟
 4         print("    index: %d" %index)
 5         for index2 in range(len(list)-1,0,-1):
 6             print("index2 =  %d:" %index2)
 7             if list[len(list) - index2-1] > list[len(list) - index2]:
 8                 temp = list[len(list) - index2-1]
 9                 list[len(list) - index2 - 1] = list[len(list) - index2]
10                 list[len(list) - index2] = temp
11         print(list)
12 list = [3, 6, 4, 2, 11, 10, 5,12,1,7,10]
13 bubble(list)

这里添加了新的解法(2019.6.25):

'''
若list长度为n则迭代n-1次,每次迭代只要有前面大于后面便交换
'''
def buble_sort(list):

    n = 1
    while len(list)-n:
        for i in range(len(list)-1):
            if list[i] > list[i+1]:
                list[i],list[i+1] = list[i+1],list[i]
        n +=1
        print(n-1,":",list)

l = [3,6,4,2,11,10,5,1]
buble_sort(l)
=================再精简一下===================
def bubble(list):
for i in range(len(list)-1):
for j in range(len(list)-1):
if list[j] > list[j+1]:
list[j + 1],list[j] =list[j], list[j + 1]
print(list)
bubble([3, 6, 4, 2, 11, 10, 5,20])
 

二,选择排序

时间复杂度:O(n2)

稳定性:不稳定

如:8,9,8,6,7中第四个数6位最小的,将与第一个8交换,这时候第一个8就变为了第二个了,因此不稳定。

  选择排序大体上就是每次在列表中找出最小的数,拿出来,然后再把拿出最小值后的列表在找最小数,就是这个思路。如图:

 1 def xuanze(list):
 2     list2 = []
 3     for index in range(1,len(list)):
 4         print("第 %d 次排序list,list2分别为:" %index)
 5         min = list[0]   #最小值
 6         for i in list:  #这里的i是里面的数值,而不是序号,print(i)可验证
 7             #print(i)
 8             if i < min:
 9                 min = i
10         #print(list.index(min))   #知道值求位置
11         locate = list.index(min)  #最小值的序号
12         temp = list[0]        #以下三行是交换
13         list[0] = list[locate]
14         list[locate] = temp
15 
16         print(list)
17         list2.append(list[0])
18         list.remove(list[0])
19         '''当交换位置后的list第一个值被remove出去后,
20         此时的list是[56,80,91,20]了,依此类推,这里是
21         本算法利用list最好玩的地方,可以少写一个for'''
22         print(list2)
23 
24     print("最终的list2:")
25     list2.append(list[0])
26     print(list2)
27 if __name__ == '__main__':
28     list = [56,12,80,91,20,33,89,99]
29     xuanze(list)

17:06:26  2018-05-24

这里添加了新的解法(2019.6.25):

 

def selection_sort(list):
    new_list = []
    while len(list):
        min = list[0]
        for i in range(0,len(list)):
            if list[i] < min:
                min= list[i]
        new_list.append(min)
        list.remove(min)
    print(new_list)

l = [10,6,7,11,8,3]
selection_sort(l)

 

三,插入排序

时间复杂度:O(n2)

稳定性:稳定

 

基本就是这个样子吧,看示意图能看明白,不再赘述。代码如下:

 1 def charu(list):
 2     num = len(list)
 3     for i in range(1,num):
 4         for j in range(0,i):
 5             print("i=",i,"j=",j,"      list[i]=",list[i],"list[j]=",list[j])
 6             if list[i] < list[j]:
 7                 temp = list[i]
 8                 list.remove(list[i])
 9                 list.insert(j,temp)
10                 print(list)
11                 break
12 list = [3,44,39,5,47,15,36,26,27,2,46,4,19,50,48]  #13个数
13 charu(list)

 

这里添加了新的解法(2019.6.26):

def  insertion_sort(list):
    for i in range(1,len(list)):
        for j in range(0,i):
            temp = list[i]
            if temp < list[j]:
                list.pop(i)
                list.insert(j,temp)
    return list

l = [3,44,39,5,47,15,36,26,27,2,46,4,19,50,48]
insertion_sort(l)

四,归并排序

O(n*logn),稳定

 归并用到了分治的思想。

def merge_sort(list):
    if len(list) == 1:
        return list
    else:
        mid = len(list)//2  #地板除
        left = list[:mid]
        right = list[mid:]
        return merge(left,right)
#合并两个排好的list
def merge(left,right):
    left.extend(right)
    sort_list = sorted(left)
    return sort_list

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

 五,快速排序

O(n*logn)  不稳定

引用:https://blog.csdn.net/morewindows/article/details/6684558

'''
基本思想:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
'''
def quick_sort(list):
    if len(list) == 1:
        return list
    else:
        base = list[0]
        left = []
        right = []
        for i in list:
            if i>=base:
                right.append(i)
            else:
                left.append(i)
        return combine(left,right)
#合并两个排好的list
def combine(left,right):
    left.extend(right)
    sort_list = sorted(left)
    return sort_list

l = [5,1,7,3,4,45,0,2,6]
result = quick_sort(l)
print(result)

====================================
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)
print(quicksort([3,6,8,10,1,2,1]))
 

六,希尔排序

不稳定

def shell_sort(list,gap):
#导入的list的长度
length = len(list)
#gap为0则停止,不为0则继续迭代
if gap == 0:
return list
else:
#list_container用于装按照gap打散(分组)后的列表
list_container = []
for i in range(0,gap):
temp_list = []
for j in range(i,length,gap):
temp_list.append(list[j])
# print(temp_list)
list_sep = sort(temp_list)
list_container.append(list_sep)
print("按照对应gap划分出的列表:",list_container)

sorted_list = sort_all_list(list_container, length, gap)
print("调用sort_all_list后:",sorted_list)
#gap减小以达到最终迭代终止条件
gap = gap//2
#最后调用自己以迭代
return shell_sort(sorted_list, gap)

def sort(list1):
return sorted(list1)
#把按照gap打散(分组)后的列表排到一个理好顺序的list中
def sort_all_list(list2,length,gap):
new_list = []
for mm in range(length):
new_list.append(0)
#把l2每个数组按照每隔gap组成一个new_list
for list in list2:
N = list2.index(list)
for i in range(N,length,gap):
num = int((i-N)/gap)
new_list[i] = list[num]
# print("sort_all_list:",new_list)
return new_list

l = [9,1,3,6,87,12,64,9,11,65,7]
#初始gap
if len(l) % 2 == 0:
gap = int(len(l) / 2)
else:
gap = int((len(l) - 1) / 2)
shell_sort(l,gap)

 七,堆排序

堆排序是不稳定的,因为建堆后的堆顶要和最后一个数交换。但我这里的稳定性这里是稳定的,因为第我没用这个方法,而是在42pop出最大值,然后再把pop后的list进行建堆,再pop,所以不用交换。后期我会改进。

 1 def adjuste_tree(non_leaf,list):
 2     #先验证non_leaf是否有右子节点。若相等则有右子树,否则没有。  还得分大于3和小于等于3.
 3     if list[non_leaf] < list[2 * non_leaf + 1] or list[non_leaf] < list[2 * non_leaf + 2]:
 4         if (list[2 * non_leaf + 1] > list[2 * non_leaf + 2]):
 5             list[non_leaf], list[2 * non_leaf + 1] = list[2 * non_leaf + 1], list[non_leaf]
 6             # print("Left:", list[non_leaf], [2 * non_leaf + 1], [2 * non_leaf + 2])
 7         elif (list[2 * non_leaf + 1] < list[2 * non_leaf + 2]):
 8             list[non_leaf], list[2 * non_leaf + 2] = list[2 * non_leaf + 2], list[non_leaf]
 9             # print("Right:",list[non_leaf],[2 * non_leaf + 1],[2 * non_leaf + 2])
10     return list
11 
12 def Heap_sort(list):
13     #1,建堆,以找出最大值(因为不管怎样都能找出最大根,即使下面排的不对)
14     #第一个非叶子节点为len/2-1
15     n = int(len(list) / 2 - 1)
16     for non_leaf in range(n,-1,-1):
17         #若节点小于他的子节点。
18         adjuste_tree(non_leaf, list)
19 
20     #2,取出根再调整堆
21 
22     #3,重复2直到只剩下一个数
23 
24 list =[4,1,3,2,16,9,10,14,8,7]
25 Heap_sort(list)

 

这里的错误是因为在第3行没有管它有没右子树,所以我们要加上这一步。

 现在,我们吧24行的list随便加一个数使他除叶子节点外都有右节点,经过多次验证,发现得出的结果没问题,因此我们字需要关注他‘第一个非叶子结点’没有右子节点时候的情形:

 1 def adjuste_tree(non_leaf, list):
 2     # 先验证最后一个非叶子节点是否有右子节点。
 3     # 若相等则有右子树,否则没有。
 4     # 还得分大于3和小于等于3.
 5 
 6     if non_leaf == int(len(list)/2-1):  #是否是最后一个非叶子节点
 7         if 2*non_leaf+2 == len(list)-1:  #这个最后一个非叶子节点是否有右子节点
 8             if list[non_leaf] < list[2 * non_leaf + 1] or list[non_leaf] < list[2 * non_leaf + 2]:
 9                 if (list[2 * non_leaf + 1] > list[2 * non_leaf + 2]):
10                     list[non_leaf], list[2 * non_leaf + 1] = list[2 * non_leaf + 1], list[non_leaf]
11                     # print("Left:", list[non_leaf], [2 * non_leaf + 1], [2 * non_leaf + 2])
12                 elif (list[2 * non_leaf + 1] < list[2 * non_leaf + 2]):
13                     list[non_leaf], list[2 * non_leaf + 2] = list[2 * non_leaf + 2], list[non_leaf]
14                     # print("Right:",list[non_leaf],[2 * non_leaf + 1],[2 * non_leaf + 2])
15         else: #进入这里证明没有右子节点
16             if list[non_leaf] < list[2*non_leaf+1]:  #这个最后一个非叶子节点是否比它的左子节点大
17                 list[2 * non_leaf + 1], list[non_leaf] = list[non_leaf], list[2 * non_leaf + 1]
18     else:
19         if list[non_leaf] < list[2 * non_leaf + 1] or list[non_leaf] < list[2 * non_leaf + 2]:
20             if (list[2 * non_leaf + 1] > list[2 * non_leaf + 2]):
21                 list[non_leaf], list[2 * non_leaf + 1] = list[2 * non_leaf + 1], list[non_leaf]
22                 # print("Left:", list[non_leaf], [2 * non_leaf + 1], [2 * non_leaf + 2])
23             elif (list[2 * non_leaf + 1] < list[2 * non_leaf + 2]):
24                 list[non_leaf], list[2 * non_leaf + 2] = list[2 * non_leaf + 2], list[non_leaf]
25                 # print("Right:",list[non_leaf],[2 * non_leaf + 1],[2 * non_leaf + 2])
26     print(non_leaf,list)
27 
28 def Heap_sort(list):
29     #1,建堆,以找出最大值(因为不管怎样都能找出最大根,即使下面排的不对)
30     #第一个非叶子节点为len/2-1
31     n = int(len(list) / 2 - 1)
32     for non_leaf in range(n,-1,-1):
33         #若节点小于他的子节点。
34         adjuste_tree(non_leaf, list)
35 
36     #2,取出根再调整堆
37 
38     #3,重复2直到只剩下一个数
39 
40 list = [4,1,3,2,16,9,10,14,8,7]
41 Heap_sort(list)

这样一次建堆就一定能把最大值找出来,但是上层改变之后下层还是没变,不影响最后结果。

最后结果:

 1 #调整树的三个节点,不能调整调整后的下层节点,但不影响结果
 2 def adjuste_tree(non_leaf, list):
 3     # 一定注意得先验证最后一个非叶子节点是否有右子节点。
 4     if len(list) == 1 or len(list) == 0:
 5         return list
 6     else:
 7         if non_leaf == int(len(list)/2-1):  #是否是最后一个非叶子节点
 8             if 2*non_leaf+2 == len(list)-1:  #这个最后一个非叶子节点是否有右子节点
 9                 if list[non_leaf] < list[2 * non_leaf + 1] or list[non_leaf] < list[2 * non_leaf + 2]:
10                     if (list[2 * non_leaf + 1] > list[2 * non_leaf + 2]):
11                         list[non_leaf], list[2 * non_leaf + 1] = list[2 * non_leaf + 1], list[non_leaf]
12                         # print("Left:", list[non_leaf], [2 * non_leaf + 1], [2 * non_leaf + 2])
13                     elif (list[2 * non_leaf + 1] < list[2 * non_leaf + 2]):
14                         list[non_leaf], list[2 * non_leaf + 2] = list[2 * non_leaf + 2], list[non_leaf]
15                         # print("Right:",list[non_leaf],[2 * non_leaf + 1],[2 * non_leaf + 2])
16             else: #进入这里证明没有右子节点
17                 if list[non_leaf] < list[2*non_leaf+1]:  #这个最后一个非叶子节点是否比它的左子节点大
18                     list[2 * non_leaf + 1], list[non_leaf] = list[non_leaf], list[2 * non_leaf + 1]
19         else:
20             if list[non_leaf] < list[2 * non_leaf + 1] or list[non_leaf] < list[2 * non_leaf + 2]:
21                 if (list[2 * non_leaf + 1] > list[2 * non_leaf + 2]):
22                     list[non_leaf], list[2 * non_leaf + 1] = list[2 * non_leaf + 1], list[non_leaf]
23                 elif (list[2 * non_leaf + 1] < list[2 * non_leaf + 2]):
24                     list[non_leaf], list[2 * non_leaf + 2] = list[2 * non_leaf + 2], list[non_leaf]
25 
26 def Heap_sort(list):
27     #1,建堆,以找出最大值
28     #第一个非叶子节点为len/2-1
29     n = int(len(list) / 2 - 1)
30     for non_leaf in range(n,-1,-1):  #根节点序号为0时也要排序
31         #若节点小于他的子节点。
32         adjuste_tree(non_leaf, list)
33 
34 if __name__ == '__main__':
35     list = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
36     soted_heap_list = []
37 
38     #2,取出根再调整堆
39     #3,重复2直到只剩下一个数
40     while(len(list)):
41         Heap_sort(list)
42         soted_heap_list.append(list.pop(0))
43     print(soted_heap_list)

 昨天太晚了,没做改进,今天上午来进行了修改,把调整树函数变为递归形式,使他能在换位后改变子节点的位置。

 1 #调整树的三个节点,调整调整后的下层节点。
 2 def adjuste_tree(heap,root):
 3     HeapSize = len(heap)
 4     #有右子节点 且  (左节点 > 根  or  右节点 > 根)
 5     if 2*root+2 <= len(heap)-1 and (heap[2*root+2] > heap[root] or heap[2*root+1] > heap[root]):
 6         if heap[2*root+1] > heap[2*root+2]:
 7             heap[2 * root + 1], heap[root] = heap[root], heap[2 * root + 1]
 8             adjuste_tree(heap, 2 * root + 1)
 9         else:
10             heap[2 * root + 2], heap[root] = heap[root], heap[2 * root + 2]
11             adjuste_tree(heap, 2 * root + 2)
12     # 无右子节点 且 (左节点 > 根)
13     if  2*root+2 <= len(heap) and (heap[2*root+1] > heap[root]):
14         heap[2 * root + 1],heap[root] = heap[root],heap[2 * root + 1]
15         adjuste_tree(heap, 2 * root + 1)
16 
17 def Heap_sort(list):
18     #1,建堆,以找出最大值
19     #第一个非叶子节点为len/2-1
20     n = int(len(list) / 2 - 1)
21     for non_leaf in range(n,-1,-1):  #根节点序号为0时也要排序
22         #若节点小于他的子节点。
23         adjuste_tree(list,non_leaf)
24 
25 if __name__ == '__main__':
26     list = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]
27     soted_heap_list = []
28 
29     #2,取出根再调整堆
30     #3,重复2直到只剩下一个数
31     while(len(list)):
32         Heap_sort(list)
33         soted_heap_list.append(list.pop(0))
34     print(soted_heap_list)

 

posted @ 2019-06-27 22:46  puppet洛洛  阅读(273)  评论(0编辑  收藏  举报