排序(python)

目录

时间和空间复杂度总结

                     选择排序

                     冒泡排序

                     插入排序

                     快速排序

                     归并排序


时间和空间复杂度总结

选择排序

思想

         选择+交换。在待排序列中,选出最小(最大)的一个数与第一个位置的数交换,然后在剩下数中,再找最小(最大)的数与第二个位置的数交换位置,依次类推,直到第N-1个元素与第N个元素交换位置,选择排序结束。

步骤

  1. 遍历数组,找到最小的数,把最小的数与第一个数位置交换;
  2. 对除第一个数的剩余数进行第二轮遍历,找到最小数,和第二个数位置交换。以此类推,直至进行比较的数只剩一个停止

模板代码

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

冒泡排序

思想

       每一轮,从杂乱无章的数组头部开始,每两个元素比较大小并进行交换,直到这一轮当中最大或最小的元素被放置在数组的尾部,然后不断地重复这个过程,直到所有元素都排好位置。其中,核心操作就是元素相互比较

步骤

  1. 首先指针指向第一个数,比较第一个数和第二个数的大小,若当前数比下一个大则交换这两个数,若小则两者位置不变;
  2. 接下来指针往前移动一步,继续比较当前值和下一个值的大小,直到最大数在数组的最后面;
  3. 进行第二轮比较,把指针重新指向第一个元素,重复步骤1、2;
  4. 若没有交换元素,说明列表已排好序,结束。

模板代码

def bubble_sort(self, arr):
    for i in range(len(arr) - 1):  #外循环:i代表比较的轮次(由于每轮比较完,都会选出最大数,而下一轮最大数不需要在比较)
        indicator = False                  #定义一个flag,用来标记每轮遍历中是否发生了交换
        for j in range(len(arr) - 1 - i):   #内循环:遍历数组所有元素,使最大值放到最后面
            if arr[j] > arr[j + 1]:        #若当前值比下一个大则交换这两个数
                arr[j], arr[j+1] = arr[j+1], arr[j]
                indicator = True       #记录有交换发生
        if not indicator:      #如果没有交换说明列表已经有序,结束循环
            break

插入排序

思想

         通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入

步骤

  1. 首先将数组分成左右两部分,左边是已经排好序部分,右边是未排好序部分,刚开始左边已排好序部分只有第一个元素
  2. 每次取右边未排好序部分第一个数,在已排序序列中从后向前依次比较。若右元素比左元素小,则将右元素插入早左元素前,交换位置;若大,保持位置不变;
  3. 找到相应位置并插入(经过每一轮的排序处理后,数组前端的数都是排好序的,区别于冒泡)

模板代码

def insertSort(self, nums):
    #外循环用来遍历数组
    for i in range(1,len(nums)):     #将第一个元素当做已经排好序的,从第二个元素开始,即i从1开始遍历数组
        temp = nums[i]               #把当前i指向的值用temp保存,即插入值
        #内循环用来将当前元素进行比较
        for j in range(i,-1,-1):     #从列表下标为0的元素开始,倒序取到下标为0的元素。j为当前位置
            if temp < nums[j-1]:     #如果当前位置的值小于比较的值,则将比较的值赋值给当前位置
                nums[j] = nums[j-1]
            else:
                break       
            nums[j] = temp   #当前的值插入到比它大的元素之前
    return nums

快速排序(重点)

思想

          快速排序使用分治法策略来把一个序列分为较小和较大的2个子序列,然后递归地排序两个子序列。(注意:快速排序是直接在原始数组里进行各种交换操作,所以当子数组被分割出来的时候,原始数组里的排列也被改变了)

步骤

  1. 选择基准值:从数列中挑出一个元素,即被比较数,称为"基准"(pivot),本文随机产生基准值(注:若固定基准值,当数组已经有序时,此时每次划分只能使待排数组减一,沦为冒泡排序

  2. 分割操作:从头开始遍历序列,将所有比pivot值小的元素放在pivot前面,所有比pivot值大的元素放在pivot后面(与pivot值相等的数可以到任何一边,本示例中放在了前面);

  3. 递归排序:将"基准"元素左边的序列和"基准"元素右边的序列进行partition操作;直到所有子序列的元素只有一个时,结束。

模板代码

#分组函数:选择基准值 pivot 将数组分成两个子数组,≤该元素的值放在左子数组,>该元素的值放在右子数组 
def partition(self, arr, low, high):        #arr: 列表;low: arr的第一个索引0;high: arr的最后一个索引
    rand = random.randint(low, high)       #随机取一个作为基准值
    i = low                                       # 最小元素索引
    pivot = arr[rand]                             # 随机选择一个数作为基准值,我们把列表中的所有元素同它比较
    #从左到右用每个数和基准值比较,若比基准值小,则放到指针i所指向的位置。循环完毕后,i 指针之前的数都比基准值小
    for j in range(low, high):                    #遍历整个数组,j为数组的每一个元素
        if arr[j] <= pivot:                      
            arr[i], arr[j] = arr[j], arr[i]       #≤除了基准值的所有元素依次放在左边索引0~i的位置(交换两元素值)
            i = i + 1                             #比pivot大的元素索引值不变,即i不加1
    arr[i], arr[rand] = arr[rand], arr[i]         #基准值放置到指针 i 的位置,i 指针之后的数都比基准值大
    return i                                      #返回指针i,作为基准点的位置
# 快速排序主体函数
def quickSort(arr, low, high):
    if low < high:                                #如果列表有1个以上的元素
        pi = partition(arr, low, high)            #利用partition函数找到一个随机的基准点
        #递归的对基准点左半边和右半边的数进行排序
        quickSort(arr, low, pi - 1)               
        quickSort(arr, pi + 1, high)              

归并排序(重点)

思想

          核心是分治(拆分、合并),就是把一个复杂的问题分成两个或多个相同或相似子问题,然后把子问题分成更小子问题,直到子问题可以简单的直接求解,原问题的解就是子问题解的合并。

步骤

  1. 将一个序列从中间位置拆分成两个子序列,递归不断的对子序列继续二分下去,直到所有的子序列长度都为1
  2. 按照大小顺序合并两个元素,依次按照递归的返回顺序,两两合并成有序序列,直到最后把整个数组的顺序排好;

模板代码

#主体函数
def merge_sort(self, lists):
    if len(lists) <= 1:
        return lists
    mid = len(lists) // 2     #将列表分成更小的两个列表
    #分别对左右两个列表进行处理,分别返回两个排好序的列表
    left = merge_sort(lists[:mid]) 
    right = merge_sort(lists[mid:])
    return merge(left, right)   
#对排序好的两个列表合并,产生一个新的排序好的列表(递归:压栈、出栈的过程;其中压栈的值暂时存在栈中)
#归并操作
def merge(self, left, right):
    #合并两个已排好序的列表,产生一个新的已排序好的列表
    result = []  #新的已排序好的列表
    i = 0   #i指针表示左列表的起始位置
    j = 0   #j指针表示右列表的起始位置
# 对两个列表中的元素两两对比;将最小的元素,放到result中,并对当前列表下标加1
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
 # 当两个列表中的其中一个指针走完了,则剩余的列表直接追加到result(由于剩下的都是有序的)
    result += left[i:]
    result += right[j:]
    return result

例题:LeetCode88题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值