常见的排序算法如下:
1. 基于比较的低效算法
这类算法时间复杂度一般都是 O ( n 2 ) O(n^2) O(n2)
选择排序
选择排序(Selection Sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法。
基本步骤
以下是选择排序的基本步骤:
-
在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置。
-
再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。
-
以此类推,直到所有元素均排序完毕。
代码实现
我们首先遍历整个列表。对于每个位置"i",我们假设它是当前未排序部分的最小值,并记录下它的索引"min_idx"。然后,我们遍历从"i+1"到列表末尾的所有元素,寻找是否存在比当前假设的最小值还要小的元素。如果存在,我们更新"min_idx"为那个更小的元素的索引。完成内层循环后,我们已经找到了从位置"i"到列表末尾的最小元素的索引,于是我们交换位置"i"和"min_idx"处的元素。这样,位置"i"处的元素就是到目前为止排序好的部分中的最小元素。
def selection_sort(lst):
for i in range(len(lst)):
#不断拿出第一小的,第二小的……
min_idx=i
for j in range(i+1,len(lst)):
if lst[min_idx]>lst[j]:
lst[min_idx],lst[j]=lst[j],lst[min_idx]
选择排序的时间复杂度是 O ( n 2 ) O(n^2) O(n2),其中n是列表的长度。这是因为我们需要两层循环:一层遍历整个列表,另一层在未排序的部分寻找最小值。尽管选择排序在效率上不如一些更先进的排序算法(如快速排序、归并排序等),但它的实现简单直观,对于小规模数据或特定场景,有时仍具有实用价值。
冒泡排序
冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
def bubble_sort(lst):
#相当于一共要比较len(lst)-1次
for i in range(len(lst)):
#每次比较都是相邻的两个数比较,比较完放到数组的末尾
for j in range(len(lst)-i-1):
if lst[j]>lst[j+1]:
lst[j],lst[j+1]=lst[j+1],lst[j]
插入排序
插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
以下是插入排序的基本步骤:
-
从第一个元素开始,该元素可以认为已经被排序;
-
取出下一个元素,在已经排序的元素序列中从后向前扫描;
-
如果该元素(已排序)大于新元素,将该元素移到下一位置;
-
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
-
将新元素插入到该位置后;
-
重复步骤2~5。
def insertion_sort(lst):
for i in range(1,len(lst)):
#要插入的值key
key=lst[i]
#前面已经排好序的数组,从后往前遍历
j=i-1
#已排序的元素的值大于要插入的值,该已排序元素往后挪一位
while j>=0 and key<lst[j]:
lst[j+1]=lst[j]
j-=1
#找到正确的位置,插入
lst[j+1]=key
2. 基于比较的高效算法
时间复杂度一般为 O ( n l o g n ) O(nlogn) O(nlogn)。
归并排序
归并排序(Merge Sort)是一种分而治之的排序算法。它将一个待排序的列表递归地分割成两个子列表,直到每个子列表只包含一个元素(此时认为它是已排序的)。然后,算法开始合并这些子列表,并在合并过程中进行排序。
合并两个已排序的子列表是归并排序算法的核心部分。假设我们有两个有序列表,我们将从这两个列表的起始位置开始比较元素,并将较小的元素放入一个新的列表中,直到其中一个列表为空。然后,我们将另一个列表的剩余部分(如果有的话)添加到新列表的末尾。
以下是归并排序的基本步骤:
-
分解:将列表分解成两个大致相等的子列表,直到子列表的大小为1。
-
递归进行排序并合并:递归地对子列表进行归并排序,并将已排序的子列表合并成一个大的有序列表,直到合并为1个完整的列表。
def merge(l,r):
merged=[]
l_id=0
r_id=0
while l_id<len(l) and r_id<len(r):
if l[l_id]<=r[r_id]:
merged.append(l[l_id])
l_id+=1
else:
merged.append(r[r_id])
r_id+=1
merged.extend(l[l_id:])
merged.extend(r[r_id:])
return merged
def merge_sort(lst):
if len(lst)<=1:
return lst
mid=len(lst)//2
l=merge_sort(lst[:mid])
r=merge_sort(lst[mid:])
return merge(l,r)
快速排序
快速排序(Quick Sort)是一种高效的排序算法,其基本思想是采用分而治之(Divide and Conquer)的策略。快速排序通过选择一个“基准”(pivot)元素,将待排序的序列划分为两个子序列,左边子序列的元素都比基准小,右边子序列的元素都比基准大,然后再对这两个子序列分别进行快速排序,最终得到有序的序列。
以下是快速排序的基本步骤:
-
选择一个基准元素(通常选择序列的第一个元素)。
-
通过一趟排序将待排序的序列分割成独立的两部分,其中一部分的所有数据都比基准小,另一部分的所有数据都比基准大。
-
对这两部分数据分别进行快速排序。
快速排序的关键在于“分区”操作,即如何划分出两个子序列。通常使用双指针法,一个指针从左向右扫描,另一个指针从右向左扫描,直到两个指针相遇。
def quick_sort(lst):
if len(arr)<=1:
return arr
else:
pivot=arr[0]
less=[x for x in arr[1:] if x<=pivot]
more=[x for x in arr[1:] if x>pivot]
return quick_sort(less)+[pivot]+quick_sort(more)
然而,这种实现方式并不是最高效的,因为它使用了额外的空间来创建子列表。在实际应用中,我们通常会使用“原地”(in-place)分区方法来避免额外的空间开销,直接在原数组上进行操作。下面是一个原地分区的快速排序实现:
n= int(input())
a=list(map(int,input().split()))
# 求出基准值的位置排序即可
def partition(a,left,right):
#找基准值,为a[left]
idx=left+1
for i in range(left+1,right+1):
if a[i]<=a[left]:
a[i],a[idx]=a[idx],a[i]
idx+=1
#把前半部分的最后一个和基准值对调
a[left],a[idx-1]=a[idx-1],a[left]
#返回基准值坐标
return idx-1
def quicksort(a,left,right):
if left<right:
mid=partition(a,left,right)
#此时a分为三部分:a[left:mid],a[mid],a[mid+1:right+1]
quicksort(a, left, mid-1)
quicksort(a,mid+1,right)
#只需要考虑怎么把当前的问题分成两个子问题
quicksort(a, 0, n-1)
print(' '.join(map(str,a)))
3. 基于数值划分的高效算法
时间复杂度一般为 O ( n ) O(n) O(n)
桶排序
桶排序(Bucket Sort)是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点:
-
首先要使得数据分散得尽可能均匀;
-
对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。
桶排序的基本思想是:将待排序的数据分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)。
以下是桶排序的基本步骤:
-
设置一个定量的数组当作空桶子。
-
寻访序列,并且把项目一个一个放到对应的桶子去。
-
对每个不是空的桶子进行排序。
-
从不是空的桶子里把项目再放回原来的序列中。
def bucket_sort(arr):
# 1. 获取数组的最大值和最小值
max_val = max(arr)
min_val = min(arr)
# 2. 计算桶的数量
bucket_range = (max_val - min_val) // len(arr) + 1 #多加一个桶以防不够
bucket_list = [[] for _ in range(len(arr) + 1)]
# 3. 将元素分配到桶中
for num in arr:
index = int((num - min_val) // bucket_range)
bucket_list[index].append(num)
# 4. 对每个桶中的元素进行排序
for bucket in bucket_list:
bucket.sort()
# 5. 将桶中的元素放回原数组
sorted_arr = []
for bucket in bucket_list:
sorted_arr.extend(bucket)
return sorted_arr
# 测试桶排序
arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = bucket_sort(arr)
print("排序后的数组:")
for num in sorted_arr:
print(num),
4. 自带函数
sort()
只能用在列表上,在原列表基础上排序
list.sort()
sorted()
可以用在任何迭代器上,产生一个新的列表,不对原列表造成影响
sorted(iterable,key=None,reverse=False)
key是指可迭代对象中的用来排序的某个元素
reverse指排序规则,True默认是降序,False是升序