算法初级----经典排序详讲

38 篇文章 0 订阅
9 篇文章 0 订阅
  • 插入排序:时间复杂度为O(N^2),空间复杂度为O(1)
  • 选择排序:时间复杂度为O(N^2),空间复杂度为O(1)
  • 冒泡排序:时间复杂度为O(N^2),空间复杂度为O(1)
  • 归并排序:时间复杂度为O(N*logN),空间复杂度为O(N)
  • 快速排序:时间复杂度为O(N*logN),空间复杂度为O(logN)
  • 堆排序:时间复杂度为O(N*logN),空间复杂度为O(1)

一、冒泡排序细节详解

        数组6 5 1 2 4 3,从小到大排序

        流程:先将6和5比较,后面的比前面的小就交换,否则不交换,再将5 6 1 2 4 3中,6和1进行比较,一直到最后完成一次排序,时间复杂度为O(N);继续重复上述流程。冒泡排序的时间复杂度为O(N^2)。

        代码:

def bubbleSort(myList):
    #首先获取list的总长度,为之后的循环比较作准备
    length = len(myList)
    
    #一共进行几轮列表比较,一共是(length-1)轮
    for i in range(0,length-1):
        
        #每一轮的比较,注意range的变化,这里需要进行length-1-长的比较,注意-i的意义(可以减少比较已经排好序的元素)
        for j in range(0,length-1-i):
            
            #交换
            if myList[j] > myList[j+1]:
                tmp = myList[j]
                myList[j]=myList[j+1]
                myList[j+1] = tmp
                
        #打印每一轮交换后的列表       
        for item in myList:
            print(item)
        print("=============================")

print("Bubble Sort: ")
myList = [6,5,1,2,4,3]
bubbleSort(myList)

二、插入排序细节详解

        对数组6 3 2 4进行插入排序,从小到大。

        流程:第一个数6放着不动;3进来后与6比较,3比6小,与6进行交换;2进来后,与6比较比6小,与6交换,再与3比较,比3小,再交换;4进来后比6小,比3大,与6交换后就停。时间复杂度为O(N^2)。

        代码:

def insertSort(arr):
    length = len(arr)
    for i in range(1,length):
        x = arr[i]
        for j in range(i,-1):
            # j为当前位置,试探j-1位置
            if x < arr[j-1]:
                arr[j] = arr[j-1]
            else:
                # 位置确定为j
                break
        arr[j] = x

def printArr(arr):
    for item in arr:
        print(item)
arr = [6,3,2,4]
insertSort(arr)
printArr(arr)

  注:一般看到的时间复杂度都是最坏情况。

三、选择排序细节详解

        对数组1 4  5 0 6进行选择排序,从小到大。

        流程:选择一个基准1; 将基准和余下的数进行一一比较,如果比基准小,则进行交换;第一轮过后获得最小的数;再挑一个基准数,执行相同的动作得到第二小的数;继续执行比较操作,直到排序好。时间复杂度为O(N^2)。

        代码:

def selectedSort(myList):
    #获取list的长度
    length = len(myList)
    #一共进行多少轮比较
    for i in range(0,length-1):
        #默认设置最小值得index为当前值
        smallest = i
        #用当先最小index的值分别与后面的值进行比较,以便获取最小index
        for j in range(i+1,length):
            #如果找到比当前值小的index,则进行两值交换
            if myList[j]<myList[smallest]:
                tmp = myList[j]
                myList[j] = myList[smallest]
                myList[smallest]=tmp
        #打印每一轮比较好的列表
        print("Round ",i,": ",myList)



myList = [1,4,5,0,6]
print("Selected Sort: ")
selectedSort(myList)

四、归并排序细节详解

        流程:其实是一个递归过程,递归利用的是栈结构(先进后出)。将数组按照middle进行递归拆分,最后分到最细之后再将其使用对两个有序数组进行排序的方法对其进行排序。

        代码:

'''
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
'''
def QuickSort(myList,start,end):
    #判断low是否小于high,如果为false,直接返回
    if start < end:
        i,j = start,end
        #设置基准数
        base = myList[i]

        while i < j:
            #如果列表后边的数,比基准数大或相等,则前移一位直到有比基准数小的数出现
            while (i < j) and (myList[j] >= base):
                j = j - 1

            #如找到,则把第j个元素赋值给第个元素i,此时表中i,j个元素相等
            myList[i] = myList[j]

            #同样的方式比较前半区
            while (i < j) and (myList[i] <= base):
                i = i + 1
            myList[j] = myList[i]
        #做完第一轮比较之后,列表被分成了两个半区,并且i=j,需要将这个数设置回base
        myList[i] = base

        #递归前后半区
        QuickSort(myList, start, i - 1)
        QuickSort(myList, j + 1, end)
    return myList


myList = [49,38,65,97,76,13,27,49]
print("Quick Sort: ")
QuickSort(myList,0,len(myList)-1)
print(myList)

五、快速排序细节详解

        流程:首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面。

        代码:

def QuickSort(myList,start,end):
    #判断low是否小于high,如果为false,直接返回
    if start < end:
        i,j = start,end
        #设置基准数
        base = myList[i]

        while i < j:
            #如果列表后边的数,比基准数大或相等,则前移一位直到有比基准数小的数出现
            while (i < j) and (myList[j] >= base):
                j = j - 1

            #如找到,则把第j个元素赋值给第个元素i,此时表中i,j个元素相等
            myList[i] = myList[j]

            #同样的方式比较前半区
            while (i < j) and (myList[i] <= base):
                i = i + 1
            myList[j] = myList[i]
        #做完第一轮比较之后,列表被分成了两个半区,并且i=j,需要将这个数设置回base
        myList[i] = base

        #递归前后半区
        QuickSort(myList, start, i - 1)
        QuickSort(myList, j + 1, end)
    return myList


myList = [49,38,65,97,76,13,27,49]
print("Quick Sort: ")
QuickSort(myList,0,len(myList)-1)
print(myList)

六、堆排序细节详解

        流程:本质是使用大根堆(每个结点的值都大于或等于左右子结点)或小根堆(每个结点的值都小于或等于左右子结点)来对一个数组进行排序。

         以由对数组从小到大进行排序的情况,需要构建大根堆。

  1. 首先将整个数组进行构建一个大根堆得到[0,R1,....,Rn]
  2. 由于R1是最大的数,所以把R1与Rn改变位置,变成[0,Rn,...,Rn-1,R1],此时[0,Rn...,Rn-1]是无序的,[R1]是有序的
  3. 对数组[0,Rn...,Rn-1]进行重构大根堆,得到[0,R2,....,Rn-1]
  4. 由于R2是最大的数,所以把R2与Rn-1改变位置,变成[0,Rn-1,...Rn-2,R2,R1],此时[0,Rn-1...,Rn-2]是无序的,[R2,R1]是有序的
  5. 重复以上步骤,直到无序列表只有[0],最终得到的有序序列则是按照从小到大规律排列的。

        代码:

import math,random

#网上找的打印树的一个函数,很好用,谁用谁知道
def print_tree(array): #打印堆排序使用
    '''
    深度 前空格 元素间空格
    1     7       0
    2     3       7
    3     1       3
    4     0       1
    '''
    # first=[0]
    # first.extend(array)
    # array=first
    index = 1
    depth = math.ceil(math.log2(len(array))) # 因为补0了,不然应该是math.ceil(math.log2(len(array)+1))
    sep = '  '
    for i in range(depth):
        offset = 2 ** i
        print(sep * (2 ** (depth - i - 1) - 1), end='')
        line = array[index:index + offset]
        for j, x in enumerate(line):
            print("{:>{}}".format(x, len(sep)), end='')
            interval = 0 if i == 0 else 2 ** (depth - i) - 1
            if j < len(line) - 1:
                print(sep * interval, end='')
        index += offset
        print()

def sort(arr,start,end):
    if end == start * 2:
        if arr[start * 2] > arr[start]:
            arr[start * 2], arr[start] = arr[start], arr[start * 2]
    else:
        if end < start * 2 + 1:
            return
        else:
            left = arr[start*2]
            right = arr[start*2+1]
            if left>right and left > arr[start]:
                arr[start * 2 ], arr[start] = arr[start], arr[start * 2 ]
                sort(arr,start*2,end)
            if left<right and right > arr[start]:
                arr[start * 2+1], arr[start] = arr[start], arr[start * 2+1]
                sort(arr, start * 2+1, end)

def heapfiy(arr):
    x = len(arr) - 1
    n = x // 2
    while n > 0:
        # print(n)
        sort(arr, n, x)
        n -= 1

#以下是主函数

#第一个0是占位用
orignal_list=[0, 74, 73, 59, 72, 64, 69, 43, 36, 70, 61, 40, 16, 47, 67, 17, 31, 19, 24, 14, 20, 48, 5, 7, 3, 78, 84, 92, 97, 98, 99]
print(orignal_list)
#第一次构建最大堆
heapfiy(orignal_list)
#打印树
print_tree(orignal_list)

x= len(orignal_list) - 1
while x!=1:
    #交换最大的数和最后一个
    orignal_list[1],orignal_list[x]=orignal_list[x],orignal_list[1]
    x-=1
    #由于交换了,不再是最大堆,重新构建最大堆
    n=x//2
    while n>0:
        sort(orignal_list,n,x)
        n-=1

#打印最后结果
print_tree(orignal_list)
print(orignal_list)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值