常见10种排序算法的python实现

4 篇文章 0 订阅
1 篇文章 0 订阅

在这里插入图片描述
(图片来源网络)

说到基础算法,不得不提排序,结合一些比较好的资料学习了一下排序算法。首先了解每种排序算法的基本原理,可以结合十大经典排序算法(动图演示) - 一像素 - 博客园里面的动图演示来看,大部分都很清晰易懂,然后了解一下每种排序算法的复杂度,一些排序算法是基于其他排序算法优化的,最后再看看哪些算法是可以在链表上使用的。

当然单纯的看,很难理解到精髓,最好自己动手实现一下。我这里根据leetcode上的一道题,来实现了常见的10种经典排序算法,单纯记录一下。

排序的时间空间复杂度对比

在这里插入图片描述

排序的数据对象

在这里插入图片描述

具体排序算法及代码

使用的题:https://leetcode-cn.com/problems/sort-colors/
这道题其实本身有其他方法,但是我看也可以用排序,就用这道题来验证排序算法了。

冒泡排序

不断对比前后两个元素,如果顺序错误,即交换前后两个元素

class Solution:
   #冒泡排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n=len(nums)
        for i in range(n):
            for j in range(n-i-1):
                if nums[j]>nums[j+1]:
                    tmp=nums[j]
                    nums[j]=nums[j+1]
                    nums[j+1]=tmp
                j+=1
            i+=1
        return nums
选择排序

分有序区和无序区,从无序区中选出最小的,与无序区中第一个元素交换,无序区第一个元素成为有序区。

class Solution:
    #选择排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n=len(nums)
        for i in range(n-1):
            minIndex=i
            for j in range(i,n):
                if nums[j]<nums[minIndex]:
                    minIndex=j
            tmp=nums[minIndex]
            nums[minIndex]=nums[i]
            nums[i]=tmp
        return nums
插入排序

in-space操作(就地操作)。分有序区和无序区。
取出一个元素,遍历有序区的元素,当小于某个有序区元素时,插入,剩下的元素都往后挪。

class Solution:
    #插入排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n=len(nums)
        for i in range(1,n):
            j=i
            cur=nums[i]
            while j >0 and cur <= nums[j-1]:
                nums[j]=nums[j-1]
                nums[j-1]=cur
                j-=1
            i+=1
        return nums
希尔排序

插入排序的改进版,将序列分组排序,组数满足{n/2,(n/2)/2…1},中间每组采用插入排序。希尔排序光看前面的动图图解其实不是很好理解,这里又找到一个不错的资料:图解排序算法(二)之希尔排序 - dreamcatcher-cx - 博客园

class Solution:
    #希尔排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n=len(nums)
        gap=n//2
        #按增量序列不断重复分组与排序,直到分组gap=1
        while gap > 0:
            i=gap
            #每次一分组完以后开始插入排序
            while i < n:
                #同一组里的前后元素开始两两对比,进行插入排序
                j=i
                cur=nums[i]
                while j-gap>=0 and cur < nums[j-gap]:
                    nums[j]=nums[j-gap]
                    nums[j-gap]=cur
                    j-=gap
                i+=1
            gap//=2
        return nums
归并排序

分治法,采用递归的方法,参考资料里的动图很好很清晰:先拆分,再排序。拆分后,左右均为有序的,只需要挨个对比排序。

class Solution:
    ##归并排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        nums[:] = self.merge(nums)
    
    def merge(self, nums):
        if len(nums)<2:
           return nums
        mid=len(nums)//2
        left=nums[0:mid]
        right=nums[mid:]
        return self.subsort(self.merge(left),self.merge(right))

    def subsort(self,left,right):
        result=[]
        while len(left)>0 and len(right)>0:
            if left[0]<=right[0]:
                result.append(left.pop(0))
            else:
                result.append(right.pop(0))
        while len(left)>0:
            result.append(left.pop(0))
        while len(right)>0:
            result.append(right.pop(0))
        return result
快速排序

分治法,也用了递归。找到一个基准元素,然后把小于基准元素的放左边,大于的放右边,再基于这个基准元素左右的序列进行同样操作。

class Solution:
    #快速排序
    def sortColors(self, nums: List[int],left=None,right=None) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n=len(nums)
        left = left if left is not None else 0
        right = right if right is not None else n-1
        if left < right:
            indexPartition=self.partition(nums, left, right)
            self.sortColors(nums,left,indexPartition-1)
            self.sortColors(nums,indexPartition+1,right)
        return nums

    def partition(self, arr, left, right):
        pivot=left
        index=pivot+1
        i = left
        while i <= right:
            if arr[i]<arr[pivot]:
                arr[i],arr[index]=arr[index],arr[i]
                index+=1
            i+=1
        arr[pivot],arr[index-1]=arr[index-1],arr[pivot]
        return index-1
堆排序

首先了解堆是什么:数据结构:堆(Heap)
利用堆的特性,先构建一个最大堆,再利用shiftUp()进行修复排序

class Solution:
    #堆排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        self.len=len(nums)
        self.builtMinHeap(nums)
        i=self.len-1
        while i > 0:
            nums[i],nums[0]=nums[0],nums[i]
            self.len-=1
            self.heap(nums,0)
            i-=1
            
    def builtMinHeap(self, arr):
        i=len(arr)//2
        while i >= 0:
            self.heap(arr,i)
            i-=1
        return arr
    
    def heap(self, arr,i):
        smallest=i
        left = 2*i + 1 
        right = 2*i + 2
        if left < self.len and arr[left] > arr[smallest]:
            smallest=left
        if right < self.len and arr[right] > arr[smallest]:
            smallest=right
        if i != smallest:
            arr[i],arr[smallest]=arr[smallest],arr[i]
            self.heap(arr,smallest)        
计数排序

计数排序需要先找到序列中的最大值,构建一个存储序列。统计计数,然后根据统计结构形成一个新序列。
当输入的元素是 n 个 0到 k 之间的整数,k不是很大并且序列比较集中时,计数排序是一个较有效的排序。

class Solution:
    #计数排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        countBucket=[0 for i in range(max(nums)+1)]
        #计数
        for i in range(len(nums)):
            countBucket[nums[i]]+=1
        index=0
        #重排列
        for i in range(len(countBucket)):
            while countBucket[i]>0:
                nums[index]=i
                index+=1
                countBucket[i]-=1
        return nums 
桶排序

找到数组最大最小值,确定每个桶中元素个数(bucket size),算出总桶数。将元素按大小范围插入到桶中。每个桶内部排序(比如用插入排序),最后将桶中元素,挨个连接起来。

class Solution:
    #桶排序
    def sortColors(self, nums: List[int],bucketSize=2) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        length=len(nums)
        arrMax,arrMin=max(nums),min(nums)
        #根据最大最小值,确定桶的个数
        bucketCount=(arrMax-arrMin)//bucketSize+1
        bucket=[[] for i in range(bucketCount)]

        #根据取值范围,把数据装入桶中
        for i in range(length):
            bucketIndex=(nums[i]-arrMin)//bucketSize
            bucket[bucketIndex].append(nums[i])
        
        #每个桶内部排序并合并
        arrIndex=0
        for i in range(bucketCount):
            bucket[i]=self.insertSort(bucket[i])
            nums[arrIndex:arrIndex+len(bucket[i])]=bucket[i]
            arrIndex+=len(bucket[i])

        return nums

    def insertSort(self,arr):
        length=len(arr)
        for i in range(1,length):
            preIndex=i-1
            cur=arr[i]
            while preIndex>=0 and arr[preIndex]>cur:
                arr[preIndex+1]=arr[preIndex]
                preIndex-=1
            arr[preIndex+1]=cur
        return arr
基数排序

利用位数排序,先排个位,再排十位…依次这么几轮,就可以了

class Solution:
    #基数排序
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        length=len(nums)
        arrMax=max(nums)
        i=1
        while i <= arrMax:
            bucket=[[] for i in range(10)]
            for j in range(length):
                bucketIndex=(nums[j]//i)%10
                bucket[bucketIndex].append(nums[j])
            bucketIndex=0  
            arrIndex=0  
            while bucketIndex<10:
                if len(bucket[bucketIndex])<1:
                    bucketIndex+=1
                else:
                    nums[arrIndex]=bucket[bucketIndex].pop()
                    arrIndex+=1
            i*=10

        return nums

建议大家也动手实现一遍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值