每日一题之常见的排序算法

常见的排序算法

排序是最常用的算法,常见的排序算法有冒泡排序、选择排序、插入排序、快速排序、希尔排序和归并排序。除此之外,还有桶排序、堆排序、基数排序和计数排序。

1、冒泡排序

冒泡排序就是把小的元素往前放或大的元素往后放,比较的是相邻的两个元素。

时间复杂度: O ( n 2 ) O(n^2) O(n2),空间复杂度: O ( 1 ) O(1) O(1),稳定排序。

思想:

(1)比较相邻的两个元素,如果第一个比第二个大,就交换它俩的位置;

(2)对每一对相邻元素作同样的工作,从开始第一对到最后一对,一趟下来,最后的元素会是最大的数;

(3)针对所有的元素重复以上的步骤,除了最后一个;

(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对元素需要比较。此时,该数组排好序。

python 复制代码
def bubbleSort(list_1):
	len_1 = len(list_1)
	# 需要遍历的趟数
	for i in range(len_1):
		# 相邻元素的比较次数
		for j in range(len_1-i-1):
			# 如果第一个比第二个大,则交换两个元素的顺序
			if list_1[j]>list_1[j+1]:
				list_1[j], list_1[j+1] = list_1[j+1], list_1[j]
	return list_1				

改进后的排序算法,如果在一轮遍历中没有发生元素交换,就可以确定列表已经有序。可以修改冒泡排序函数,使其在遇到这种情况时提前终止。

python 复制代码
def shortBubble(list_2):
	# 判断是否需要交换
	exchange = False
	len_2 = len(list_2)
	# 如果在一轮遍历中没有发生元素交换,则提前终止
	for i in range(len_2):
		exchange = False
		for j in range(len_2-i-1):
			if list_2[j] > list_2[j+1]:
				list_2[j], list_2[j+1] = list_2[j+1], list_2[j]
		if not exchange:	
			break
	return list_2

2、选择排序

选择排序给每个位置选择当前最小的元素。

算法思想:

(1)在所有数组中找到最小(大)元素,将其存放到数组的起始位置;

(2)在剩余元素中继续找最小(大)元素,然后依次放到已排序数组的末尾;

(3)重复操作,直到所有元素均排列好。

时间复杂度: O ( n 2 ) O(n^2) O(n2),空间复杂度: O ( 1 ) O(1) O(1),非稳定排序

python 复制代码
def selectionSort(list_3):
	len_3 = len(list_3)
	for i in range(len_3):
		minIndex = i
		for j in range(i+1, len_3):
			if list_3[j] < list_3[minIndex]:
				minIndex = j
		list_3[i], list_3[minIndex] = list_3[minIndex], list_3[i]
	return list_3

3、插入排序

插入排序:在一个已经有序的小数组上,依次插入一个元素

算法思想:

(1)从第一个元素开始,该元素被认为是已经排好序的小数组;

(2)取出下一个元素,在已经排好序的小数组中从后向前遍历;

(3)如果排好序小数组的末尾元素大于待插入元素,将该末尾元素移动到下一个位置,并找小数组末尾元素的前面一个元素;

(4)重复步骤3,直到找到已排序的元素小于或等于待插入元素的位置;

(5)将待插入元素插入到该位置后,重复步骤2-5,直到该数组是有序的。

时间复杂度: O ( n 2 ) O(n^2) O(n2),空间复杂度: O ( 1 ) O(1) O(1),稳定排序

python 复制代码
def insertionSort(list_4):
	len_4 = len(list_4)
	#遍历除第一个元素外的所有元素
	for i in range(1, len_4):
		# 若第i个元素大于i-1元素,直接插入
		if list_4[i] < list_4[i-1]:
			j = i - 1
			# 待插入元素
			value = list_4[i]
			while j >= 0 and value < list_4[j]:
				# 向后移动元素
				list_4[j+1] = list_4[j]
				j -= 1
			list_4[j+1] = value
	return list_4

4、快速排序

快速排序:选取一个基准值,分成两段,左边放小于基准值的所有数,右边放大于基准值的数。

思想:

(1)选取基准值;

(2)将比基准值小的元素交换到前面,比基准值大的元素交换到后面;

(3)对左右区间重复步骤2,直到各区间只有一个数。

python 复制代码
# 分区操作
def partition(alist, first, last):
	# 基准
	pivotVal = alist[first]
	# 左右两个
	leftMark = first + 1
	rightMark = last
	flag = False
	while not flag:
		# 加大leftMark,直到遇到一个大于基准的元素
		while alist[leftMark] <= pivotVal and leftMark <= rightMark:
			leftMark += 1
		# 减少rightMark,直到遇到一个小于基准的元素
		while alist[rightMark] >= pivotVal and leftMark <= rightMark:
			rightMark -= 1
		# 当rightMark <leftMark时,过程终止
		if rightMark < leftMark:
			flag = True
		else:
		#将rightMark对应的元素与当前位于分割点的元素互换
			alist[leftMark], alist[rightMark] = alist[rightMark], alist[leftMark]
		alist[leftMark], alist[rightMark] = alist[rightMark], alist[leftMark]
	return rightMark

def quickSortHelper(alist, first, last):
	if first < last:
		mid = partition(alist, first, last)
		quickSortHelper(alist, first, mid)
		quickSortHelper(alist, mid+1, last)

def quickSort(alist):
	quickSortHelper(alist, 0, len(alist)-1)

5、希尔排序

希尔排序是插入排序的一种变种,为了加快速度改进的插入排序,交换不相邻的元素以对数组的局部进行排序。

思想:

(1)让数组中任意间隔为 h h h 的元素有序;

(2)刚开始 h = l e n g t h / 2 h = length / 2 h=length/2;

(3)接着让 h = l e n g t h / 4 h = length / 4 h=length/4,让 h h h 一直缩小,直到 h = 1 h=1 h=1,此时数组中任意间隔为1的元素有序。

python 复制代码
# 对每个子序列进行插入排序,需要得到子序列的起始点和长度
def gapInsertSort(list_6, start, gap):
	for i in range(start+gap, len(list_6), gap):
		# 当前待插入元素
		curValue = list_6[i]
		j = i - gap
		
		if list_6[i] < list_6[i-gap]:
			while j >= 0 and curValue < list_6[j]:
				list_6[j+gap] = list_6[j]
				j -= gap
			list_6[j+gap] = curValue
	return list_6

def shellSort(list_6):
	# 获取每个子序列的长度
	subListLen = len(list_6) // 2
	# 子序列的长度要始终大于0
	while subListLen > 0:
		# 起始位置的取值
		for startPos in range(subListLen):
			# 分段进行插入排序
			gapInsertSort(list_6, startPos, subListLen)
		# 每次都将子序列的长度减少一半
		subListLen = subListLen // 2
	return list_6

6、归并排序

思想:将一个无序数组有序,首先将这个数组分成两个,然后对这两个数组分别进行排序,之后再把这两个数组合并成一个有序的数组。此时该数组就有序了。

python 复制代码
# 合并两个有序数组
def merge(list_7, list_8):
	# 分别获取两个子序列的下标
	index1 = 0
	index2 = 0
	# 分别获取两个子序列的长度
	len_7 = len(list_7)
	len_8 = len(list_8)
	list_sum = []
	while index1 < len_7 or index2 < len_8:
		if list_7[index1] > list8[index2]:
			list_sum.append(list_8[index2])
			index2 += 1
		else:
			list_sum.append(list_7[index1])
			index1 += 1
	list_sum += list_7[index1:]
	list_sum += list_8[index2:]
	return list_sum

def mergeSort(list_9):
 	# 原数组的长度不能少于2
	if len(list_9) < 2:
		return list_9
	# 进行二路归并
	mid = len(list_9) // 2
	# 左边进行归并排序
	left = merge(list_9[:mid])
	# 右边进行归并排序
	right = merge(list_9[mid:])
	return merge(left, right)
相关推荐
Funny_AI_LAB7 分钟前
MetaAI最新开源Llama3.2亮点及使用指南
算法·计算机视觉·语言模型·llama·facebook
NuyoahC14 分钟前
算法笔记(十一)——优先级队列(堆)
c++·笔记·算法·优先级队列
jk_10116 分钟前
MATLAB中decomposition函数用法
开发语言·算法·matlab
penguin_bark1 小时前
69. x 的平方根
算法
一休哥助手1 小时前
Redis 五种数据类型及底层数据结构详解
数据结构·数据库·redis
这可就有点麻烦了1 小时前
强化学习笔记之【TD3算法】
linux·笔记·算法·机器学习
苏宸啊1 小时前
顺序表及其代码实现
数据结构·算法
lin zaixi()1 小时前
贪心思想之——最大子段和问题
数据结构·算法
FindYou.1 小时前
C - Separated Lunch
算法·深度优先
夜雨翦春韭1 小时前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法