python八种排序方法(尽可能简单化)

本文深入探讨了八种经典的排序算法,包括冒泡法、选择排序法、快速排序法、插值法排序、希尔排序法、桶排序、基数排序法和归并排序,详细解释了每种算法的时间复杂度、稳定性及实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、冒泡法

时间复杂度:O(N^2);
稳定性:稳定;

#python冒泡法排序,两两比较,开始排序。将单极最值放在最(左)右端,然后循环剩下的元素。
class BubbleSort():
    def sort_w(self,nums):
        for i in range(len(nums)-1):#i,j都是下角标序号;这里减一根本原因是作相邻交换时,数间个数总是比元素少一个
                                     #这里用i来表示总循环次数
                                    #j用来表示剩余循环次数
            for j in range(len(nums)-i-1):#
                print("j=%d"%j,end="   ")
                if nums[j]<nums[j+1]:
                    nums[j],nums[j+1]=nums[j+1],nums[j]
        return nums

另外,在python中,列表中的两个元素交换是不需要第三给变量了做容器的,直接用:

nums[j],nums[j+1]=nums[j+1],nums[j]

2、选择排序法

时间复杂度:O(N^2);
稳定性:不稳定;

选择排序法和冒泡法其实有一点点相似,其原理是:
1、选取一个(第一次为首元素)元素作为最小(最大)元素;
2、记住该元素下角标min
3、将该元素与余下的元素作比较,若遇到比该元素小(大)的元素,就与min交换值
5、循环n-1次

class Selection():
    def selection_sort(self,nums):
        for i in range(0,len(nums)-1):
            min_=i
            for j in range(i+1,len(nums)):
                if nums[j]<nums[min_]:
                    nums[j],nums[min_]=nums[min_],nums[j]
        return nums
y=Selection()
print(y.selection_sort([17,3,13,4,5]))

需要注意的是,在第二循环中交换的两个下角标的值,而不是元素值本身。

3、快速排序法

时间复杂度:O(NlogN)
稳定性:不稳定

思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列;

用人话讲就是:
1、取出一个元素,然后与它对比,将所有元素分为【小元素】+取出元素+【大元素】;
2、再在【小元素】【大元素】中取一个值,再比较,分成【小元素】+取出元素+【大元素】,以此类推直到不可以分割为止;
3、合起来;

class Selection():
    def selection_sort(self,nums):

        #递归条件判断:
        if len(nums)>=2:
            #定义左右两个子集
            left,right=[],[]
            #取出第一个元素
            first=nums[1]
            nums.remove(nums[1])
            for i in nums:
                if i>first:
                    right.append(i)
                else:
                    left.append(i)
            return Selection.selection_sort(None,left)+[first]+Selection.selection_sort(None,right)
        else:
            return nums

y=Selection()
print(y.selection_sort([2,3,5,7,1,4,6,15,5,2,7,9,10,15,9,17,12]))

4、插值法排序

时间复杂度:O(N^2)
稳定性:稳定

class Selection():
    def selection_sort(self,nums):
        for i in range(1,len(nums)):#i一定从1开始,首元素要用来比较
            intermediate=nums[i]#先将nums[i]的值传递给中间变量
            j=i-1#也就是i的左面一位
            while j>=0 and nums[j]>intermediate:#比较左一位与中间变量的值,如果左面大:
                nums[j+1]=nums[j]#:就将左值赋给右边一位,这里不用担心右面一位的值没有保留,而是在中间变量中
                j=j-1#将j值减小一个,向左移一位,继续比较
            nums[j+1]=intermediate#循环结束后,记得把中间变量的值赋给nums[j+1]
        return nums

5、希尔排序法

通常认为是O(N^(3/2)) ,未验证
稳定性:不稳定

仔细看代码,看得懂。其实我不知道这是不是希尔排序。。。

class ShellSort():
    def shell_sort(self,nums):
        chunt=int(len(nums)/2)
        while chunt>=1:
            i=0
            while i+chunt<len(nums):
                if nums[i]>nums[i+chunt]:
                    print("nums[%d]=%d,nums[%d+%d]=%d"%(i,nums[i],i,chunt,nums[i+chunt]))
                    nums[i],nums[i+chunt]=nums[i+chunt],nums[i]
                i+=1
                if i>len(nums):
                    break
            chunt-=1
        for i in range(0,len(nums)-1):#这里不要问我为什么,有时候有问题是难免的,找个办法解决就好了
            print(i)
            if nums[i]>nums[i+1]:
                nums[i],nums[i+1]=nums[i+1],nums[i]
        return nums

6、桶排序

时间复杂度:O(x*N)
稳定性:稳定

关键是将列表里面的数字转化成空桶列表里面的位置:
关键步骤:
1、找出最大值,将空桶长度设为最大值个数
2、将数值转化成列表的位置,相同的加1
3、除去空位置,将位置转化成有序数列
注意:
IndexError: list index out of range
len()函数取出来的是个数,而列表的初始位置是从0开始计算的,不要溢出来了!!!

class BuketSort():
    def buket_sort(self,nums):
        #查看nums中最大的数,并让空桶也有同样位置
        max_=nums[1]
        for i in range(len(nums)):
            max_=(max(max_,nums[i]))
        #输出最大数字
        print("max_=",max_)
        buket=[0 for i in range(max_+1)]
        #s输出空桶原始状态
        print("buket:",buket)
        for n in range(len(nums)):
                buket[nums[n]]+=1#nums中元素在buket中的位置加一
        #输出现在的buket
        print(buket)
        i=0
        for m in range(len(buket)):
            while buket[m]>0:#只有大于0的位置才出现过数字
                nums[i]=m    #将位置转化为数字
                buket[m]-=1  #此位置上的数字减一(大于1的表示出现过多次)
                i+=1
        return nums
y=BuketSort()
print(y.buket_sort([2,3,5,7,1,4,6,15,5,2,7,9,10,15,9,17,12]))

结果:

max_= 17
空buket: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
转化后的buket: [0, 1, 2, 1, 1, 2, 1, 2, 0, 2, 1, 0, 1, 0, 0, 2, 0, 1]
最终结果:[1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 9, 9, 10, 12, 15, 15, 17]

7、基数排序法

时间复杂度:O(x*N)
稳定性:稳定

基数排序法可以叫做“同位数比较法”,其基本原理就是所有数字从最低位开始比较,然后排序,然后依次向高位进行比较排序(反之即是:由大到小排序)。
1、遍历数列,取得大数字,然后取出最大数位数max_bit;
2、从i=0开始循环,一直到i<max_bit为止,也就是从个位开始,一直到最高位为止;
3、建立一个空桶,空桶内含有10个列表,分别表示0,1,…,8,9;
4、依据比较当前位数上,各个数值的大小,放在空桶的相应位置,例如22,就在buket[2]中;
5、清空原数列,然后按顺序将buket中的元素放在原数列中;
6、进行下一位的比较。

import math
class RadixSort():
    def radix_sort(self,nums):
        #寻找最高位数
        max_bit=int(math.ceil(math.log(max(nums),10)))#math.ceil():向上取整;math.log(数值,进制):求该数值的位数
        i=0
        while i<max_bit:
            buket=[[]for i in range(10)]#一定要在循环体内部,因为每次循环的时候,都需要桶子是空的
            for p in nums:
                m=int(p/(10**i))%10#求p的在10**i位上的余数
                buket[int(m)].append(p)#将该数添加到桶子相应位置
            i+=1
            nums.clear()#因为所有数字现在都在buket中,所以可以清空原数列
            for x in buket:   
                for y in x:
                    nums.append(y)#然后从buket中,按顺序放回原数列
        return nums
y=RadixSort()
print(y.radix_sort([2,3,13,23,5,7,11,11,21,10]))

结果:
[2, 3, 5, 7, 10, 11, 11, 13, 21, 23]

8、归并排序

时间复杂度:O(NlogN)
稳定性:稳定

归并排序的思想简单说来就是:把一个无序的数列分成左右两半,再在子数列中继续分左右两半,直到不可再细分为止。然后开始从最小的子数列比较左右的大小,依次向上返回有序数列。
class Merge():
    def merge_sort_1(self,nums):
        #递归结束判断语句
        if len(nums)<=1:
            return nums
        middle=int(len(nums)/2)
        left=self.merge_sort_1(nums[:middle])
        right = self.merge_sort_1(nums[middle:])
        list=self.merge_sort_2(left,right)
        return list
    def merge_sort_2(self,left,right):
        i,p=0,0
        list_return=[]
        while i<len(left) and p<len(right):
            if left[i]>right[p]:
                list_return.append(right[p])
                p+=1
            else:
                list_return.append(left[i])
                i+=1
        if i==len(left):#因为是有序数列,所以可以直接将没有比较的数字按顺序添加到桶子中
            for x in right[p:]:
                list_return.append(x)
        else:
            for x in left[i:]:
                list_return.append(x)
        return list_return
y=Merge()
print(y.merge_sort_1([2,3,5,7,1,4,6,15,5,2,7,9,10,15,9,17,12]))

归并原理示意图:
图片来源:@su_bao图片来源:@su_bao

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值