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