一直以来,我只是在大学学过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
我是头一次见到计数排序这种思路,让我大开眼界。
好了,关于排序的算法节写这么多,以后还要总结一下关于数据结构方面的知识。