排序
将一组无序列表调整为有序列表。
python内置函数(内部使用的是顺序查找方法):sort()。
Li=[23,45,21,56]
a=sorted(Li) #返回排序后的新列表,不会修改原有列表
Li.sort() #无返回值,在原有序列上进行升序排序
print(Li)
Li.sort(reverse=True) #在原有序列上进行降序排序
print(Li)
-
排序的方法):
- 冒泡排序:
- 时间复杂度为O(n2),在原有列表上进行修改
- 每一趟排序逐个对相邻的两个数进行对比,一趟排序固定一个有序数据
- 如果有一趟排序没有发生交换,说明列表已经有序可以直接结束算法,提高效率
- 选择排序:
- 时间复杂度为O(n2),在原有列表上进行修改
- 每次从列表的无序区选择最小元素和无序区第一个元素交换,并将其加入有序区
- 插入排序:
- 时间复杂度为O(n2),在原有列表上进行修改
- 把无序区的元素逐个放入有序区的合适位置
- 快速排序:
- 时间复杂度为O(nlog2n)
- 逐个取列表元素将其归位,左边元素比它小,右边元素都比它大,递归完成
- 最坏情况:当列表是逆序时,每次只能排序一个元素,时间复杂度为O(n2)。解决方法可以在第一次取随机位置的元素与第一个元素交换,再进行排序。
- 堆排序:
- 时间复杂度为O(nlog2n)
- 归并排序:
- 时间复杂度为O(logn)
- 希尔排序:
- 时间复杂度为O(logn)
- 计数排序:
- 时间复杂度为O(logn)
- 基数排序:
- 时间复杂度为O(logn)
如果查找需要执行很多次,可以考虑先将列表进行排序,使用二分查找执行。可以提高效率。
- 时间复杂度为O(logn)
- 冒泡排序:
冒泡排序
如果有一趟排序没有发生交换,说明列表已经有序可以直接结束算法,提高效率。
def bubble_sort(Li): #在Li列表上直接进行修改
for i in range(len(Li)-1):
exchange=False
for j in range(len(Li)-i-1):
if Li[j]>Li[j+1]:
Li[j],Li[j+1]=Li[j+1],Li[j]
exchange=True
if not exchange:
return
选择排序
#每次选择最小的元素放入新的列表中
#时间复杂度为O(n**2),并且空间复杂度为T(n)
def select_sort_simple(Li):
Li_new=[]
for i in range(len(Li)):
min_val=min(Li) #时间复杂度为O(n)
Li_new.append(min_val)
Li.remove(min_val) #时间复杂度为O(n)
return Li_new
#每次从列表的无序区选择最小元素和无序区第一个元素交换
#时间复杂度为O(n**2),在原有列表上进行修改
def select_sort(Li):
for i in range(len(Li)-1):
min_index=i
for j in range(i+1,len(Li)):
if Li[min_index]>Li[j]:
min_index=j
Li[i],Li[min_index]=Li[min_index],Li[i]
插入排序
#把无序区的元素逐个放入有序区的合适位置
#时间复杂度为O(n**2)
def inert_sort(Li):
for i in range(1,len(Li)):
j=i-1
temp=Li[i]
while j>=0 and Li[j]>temp:
Li[j+1]=Li[j]
j-=1
Li[j+1]=temp
快速排序
#逐个取列表元素将其归位,左边元素比它小,右边元素都比它大,递归完成
def partition(Li,left,right):
tmp=Li[left]
while left<right:
while left<right and Li[right]>tmp:
right-=1
Li[right],Li[left]=Li[left],Li[right]
while left<right and Li[left]<tmp:
left+=1
Li[right],Li[left]=Li[left],Li[right]
Li[left]=tmp
return left
def quick_sort(Li,left,right):
if left<right:
mid=partition(Li,left,right)
quick_sort(Li,left,mid-1)
quick_sort(Li,mid+1,right)
堆排序
完全二叉树顺序存储时,父节点与孩子节点下标的关系为:
左孩子节点下标=2父节点下标+1
左孩子节点下标=2父节点下标+2
大根堆:一个完全二叉树,满足任意节点都比其孩子节点大
小根堆:一个完全二叉树,满足任意节点都比其孩子节点小
堆的向下调整:假设节点的左右子树都是堆,但是自身不是堆。可以通过一次向下调整将其变换成一个堆。(逐步将左右子树中的最大的元素向上移动,遇到左右子树的节点都比该节点小,将该节点填补在此处)
堆排序的方法为:
1、建立一个堆。(从最后一个非叶子节点开始使用堆的向下调整构建堆)
2、得到堆顶元素为最大元素
3、去掉堆顶,将堆的最后一个元素放到堆顶,此时可以通过一次调整(堆的向下调整)重新使堆有序
4、循环重复
#向下调整函数
def sift(Li,low,high):
:param Li:列表
:param low:堆的根节点位置
:param high:堆的最后一个元素位置
i=low #i最开始指向根节点
j=2*i+1 #j开始是左孩子
tmp=Li[low] #把堆顶存起来
while j <=high: #只要j位置有数
if j+1<=high and Li[j+1]>Li[j]: #如果有右孩子并且比左孩子大
j=j+1 #j指向右孩子
if Li[j]>tmp:
Li[i]=li[j]
i=j #往下看一层
j=2*i+1
else: #tmp更大,把tmp放到i的位置上
Li[i]=tmp
break
else:
Li[i]=tmp #把tmp放到叶子节点上
#构造堆
def heap_sort(data):
n=len(data)
for i in range(n//2-1,-1,-1):
sift(data,i,n-1)
for i in range(n-1,-1,-1):
data[0],data[i]=data[i],data[0]
sift(data,0,i-1)