Python学习——排序算法实现


一直以来,我只是在大学学过C语言的数据结构中关于冒泡排序的算法,到现在这么多年也没有学习过其它算法,现在借着学习python的机会研究一下其它几种排序算法。听说现在面试的时候冒泡排序算法是最基本的。想想也是,几年前我面试的时候还当场写过C语言的冒泡排序,可惜当时只会这一种,现在总不能过了几年还是只会一种吧,说来惭愧。下面就好好写写这几种排序算法。

时间复杂度

时间复杂度是用来估算算法运行效率的描述,不可精确定量计算,一般用O(n)表示。

#代码片1
print("Hello World!")	#时间复杂度O(1)
#代码片2
for i in range(n):		#时间复杂度O(n)
	print("Hello World!")
#代码片3
for i in range(n):		#时间复杂度O(n*n)
	for j in range(n):
		print("Hello World!")
#代码片4
for i in range(n):		#时间复杂度O(n*n*n)
	for j in range(n):
		for j in range(n):
			print("Hello World!")
#代码片5
while n > 1:			
	print(n)
	n = n // 2
  • 代码片1时间复杂度O(1)
  • 代码片2时间复杂度O(n)
  • 代码片3时间复杂度O(n2)
  • 代码片4时间复杂度O(n3)
  • 代码片4时间复杂度O(log2n)可以简写为O(logn)
    小结:
  • 时间复杂度是用来估算算法运行时间的一个单位
  • 一般来说,时间复杂度越高的算法比复杂度低的算法慢,效率低
  • 常见的时间复杂度安效率排序:O(1) > O(logn) > O(n) > O(nlogn) > O(n2) > O(n2logn) > O(n3)

空间复杂度

空间复杂度用来评估算法对内存占用的估算单位。为了提高算法的运行效率,降低时间复杂度,经常使用一空间换时间的算法。
未使用额外空间的算法空间复杂度为O(1);
使用额外空间的算法空间复杂度为O(n)

二分查找

# 此算法的前提是data_list是一个按升序排列的列表
# 循环版本的二分查找
def bin_search(data_list, value):
	low = 0
	high = len(data_list) - 1
	while low <= high :
		mid = (low + high) // 2
		if data_list[mid] == value:
			return mid
		elif data_list[mid] > value:
			high = mid -1
		else:
			low = mid + 1
# 递归版本的二分查找
def bin_search_rec(data_list, vaule, low, high):
	if low <= high:
		mid = (low + high) // 2
		if data_list[mid] == value:
			return mid
		elif data_list[mid] > value:
			return bin_search_rec(data_list, vaule, low, mid -1)
		else:
			return bin_search_rec(data_list, vaule, mid + 1, high)
	else:
		return None

冒泡排序

时间复杂度: O(n2)
空间复杂度:O(1)

def bubble_sort(data_list):
	for i in range(len(data_list) - 1):
		for j in range(len(li) - i - 1):
			if data_list[j] > data_list[j + 1]:
				data_list[j], data_list[j+1] = data_list[j+1], data_list[j]

# 冒泡排序优化, 如果执行一趟比较,没有发生交换,则列表已经是有序状态,可以直接结束算法
def bubble_sort_2(data_list):
	for i in range(len(data_list) - 1):
		exchange = False
		for j in range(len(li) - i - 1):
			if data_list[j] > data_list[j + 1]:
				data_list[j], data_list[j+1] = data_list[j+1], data_list[j]
				exchange = True
		if not exchange:
			return

选择排序

思路:初始时认为最小的元素位于0,然后遍历列表与元素0比较,找出最小元素的位置,然后交换,然后依次比较剩余区的最小元素,进行交换。
时间复杂度: O(n2)
空间复杂度:O(1)

def select_sort(data_list):
	for i in range(len(data_list) - 1):
		min_location = i
		for j in range(i+1, len(data_list)):
			if data_list[j] < data_list[min_location]:
				min_location = j
		if min_location != i:
			data_list[i], data_list[min_location ] = data_list[min_location ], data_list[i]

插入排序

思路:列表被分为有序区与无序区,最初有序区只有一个元素,即为第0个元素,依次从无序区拿出一个元素,与有序区比较,将元素插入到有序区相应的位置,直到无序区没有元素,排序完成
时间复杂度: O(n2)
空间复杂度:O(1)

def insert_sort(data_list):
	for i in range(1, len(data_list)):
		tmp = data_list[i]	#从无序区拿出的第一个元素
		j = i - 1
		while j >= 0 and tmp < data_list[j]:
			data_list[j + 1] = data_list[j]
			j = j - 1
		data_list[j + 1] = tmp	

快速排序

快速排序思路:

  • 取第一个元素p, 使p元素归位
  • 所谓归位,是指将p元素移动到一个位置,此位置的右边元素都比p大,左边都比p小
  • 归位后的返回值为p元素归位后的位置
  • 然后根据此位置递归完成左边与右边的元素的归位
    • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)
# partition函数首先从left位置取出一个元素p,暂存到tmp,
# 然后从right位置开始比较,当right元素比tmp小时,将此right元素移动到left位置,否则right-1;
# 然后再从left位置开始与tmp比较,当left元素比tmp大时,将left元素移动到right位置,否则left+1
# 最后当left与right相等时,使tmp元素归位,即可保证元素右边比p大,左边比p小
def partition(data, left, right):
	tmp = data[left]
	while left < right:
		while left < right and data[right] >= tmp:
			right -= 1
		data[left] = data[right]
		while left < right and data[left] <= tmp:
			left += 1
		data[right] = data[left]
	data[left] = tmp
	return left
def quick_sort(data, left, right):
	if left < right:
		mid = partition(data, left, right)
		quick_sort(data, left, mid-1)
		quick_sort(data, mid+1, right)

归并排序

归并排序思路:

  • 分解,首先将列表分解,直至分解成单个元素
  • 单个元素永远是有序的
  • 合并,将两个有序的列表合并,
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(n)
    在这里插入图片描述
def merge(data, low, mid, high):
	i = low
	j = mid + 1
	Ltmp = []
	while i <= mid and j <= high:
		if data[i] <= data[j]:
			Ltmp.append(data[i])
			i += 1
		else:
			Ltmp.append(data[j])
			j += 1
	while i <= mid:
		Ltmp.append(data[i])
		i += 1
	while j <= high:
		Ltmp.append(data[j])
		j += 1
	data[left:high+1 ] = Ltmp
def merge_sort(data, low, high):
	if low < high:
		mid = (low + high) // 2
		merge_sort(data, low, mid)
		merge_sort(data, mid+1, high)
		merge(data, low, mid, high)

计数排序

计数排序思路:

  • 首先创建一个以待排序列表中最大值为元素个数的计数列表,
  • 列表每个元素的初始值均为0
  • 然后统计待排序列表中的元素, 以元素的值为下标,每出现一次;在计数列表中次数加1
  • 然后根据计数列表中不为0的元素,按照下标顺序以及次数,将下标放置到新的排序列表,排序完成
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
def count_sort(data_list, max_value):
	count = [0 for i in range(max_value + 1)]
	for data in data_list:
		count[data] += 1
	i = 0
	for num, v in enumerate(count):
		for j in range(v):
			data_list[i] = num
			i += 1

我是头一次见到计数排序这种思路,让我大开眼界。
好了,关于排序的算法节写这么多,以后还要总结一下关于数据结构方面的知识。

猜你喜欢

转载自blog.csdn.net/zhaoyun_zzz/article/details/83549856