1. 排序算法稳定性
如果在待排序的列表中,存在多个相同的数据,经过排序后,这些元素的相对次序保持不变,即可称这种排序算法是稳定的,反之则不稳定
2. 冒泡排序
2.1 基本思想
从小到大排序:两两比较,不符合条件时,就互换位置,直至序列中所有元素顺序正确。
2.2 实现分析
new_list = [5, 4, 3, 2, 1]
第一次:5和4比较,5和4位置互换 new_list = [4, 5, 3, 2, 1]
第二次:5和3比较,5和3位置互换 new_list = [4, 3, 5, 2, 1]
第三次,5和2比较,5和2位置互换 new_list = [4, 3, 2, 5, 1]
第四次,5和1比较,5和1位置互换,此时列表最后一个元素为最大值。 new_list = [4, 3, 2, 1, 5]
此时第一轮比较完成,开始进行第二轮
第一次,4和3比较,4和3位置互换 new_list = [3, 4, 2, 1, 5]
第二次,4和2比较,4和2位置互换 new_list = [3, 2, 4, 1, 5]
第三次,4和1比较,4和1位置互换 new_list = [3, 2, 1, 4, 5]
此时,4已经不用和5比较了,因为上一轮的结果就证明5是最大的。至此第二轮结束。
通过以上梳理发现,当元素个数为n时,一共需要比较n-1轮,来确定每个位置上符合条件的元素。
每一轮需要比较n-i次,其中i为当前轮数。
2.3 代码实现
def my_bubble_sort(my_list, is_desc=False):
"""
冒泡排序
:param my_list:需要进行排序的列表
:param is_desc:是否从大到小,默认是否
:return: new_list
"""
length = len(my_list)
out_num = 0 # 定义比较的轮数
comp_times = 0 # 每轮比较的次数
for i in range(length - 1): # 定义外层循环,一共需要比较n-1轮
out_num += 1
for j in range(length - out_num):
# 从小到大排序
if my_list[j] > my_list[j + 1]:
comp_times += 1 # 比较次数加一
my_list[j], my_list[j + 1] = my_list[j + 1], my_list[j]
# 如果这一轮比较的次数为0,说明是有序列表
if comp_times == 0:
break
if is_desc:
my_list.reverse()
return my_list
new_list = [5, 4, 3, 2, 1]
print(my_bubble_sort(new_list))
print(my_bubble_sort(new_list, True))
2.4 总结
冒泡排序是稳定算法
最优时间复杂度为O(n)
最差时间复杂度为O(n^2)
3. 选择排序
3.1 基本思想
从小到大:
从待排序列中指定一个最小值,然后让其与剩余元素挨个比较,若碰见小的就替换,碰见大的就继续下一个比较。
确定之后,再从剩余元素中指定一个最小值,依次类推。直至排序完成
3.2 实现分析
new_list = [5, 4, 3, 2, 1]
第一轮:
先指定一个最小值5
4和5比较,4小于5,假定最小值为4
3和4比较,3小于4,假定最小值为3
2和3比较,2小于3,假定最小值为2
1和2比较,1小于2,假定最小值为1
此时第一轮完成,最小值发生了变化,所以交换1和5的位置。即new_list = [1, 4, 3, 2, 5]
第二轮:
指定最小值为4
3和4比较,3小于4,假定最小值为3
2和3比较,2小于3,假定最小值为2
5和2比较。5大于2,此时最小值仍为2,第二轮完成,最小值发生了变化,所以交换2和4的位置。
即new_list = [1, 2, 3, 4, 5]
第三轮
指定最小值为3
4和3比较,4大于3,最小值为3
5和3比较,5大于3,最小值为3
第三轮结束,此时最小值没有发生变化。即new_list = [1, 2, 3, 4, 5]
第四轮
指定最小值为4
5和4比较,5大于4,最小值为4.排序完成,即new_list = [1, 2, 3, 4, 5]
3.3 代码实现
def my_select_sort(my_list, is_desc=None):
"""
选择排序
:param my_list: 需要进行排序的列表
:param is_desc: 是否从大到小,默认是否
:return:
"""
length = len(my_list)
for j in range(0, length - 1): # 控制轮数
temp_min_index = j # 假定的最小值的下标
for i in range(j + 1, length):
# 如果当前元素的值比下标小,就把当前元素的下标赋值给假定的最小值的下标
if my_list[i] < my_list[temp_min_index]:
temp_min_index = i
# 如果当前轮中,下标值发生了变化,则进行交换
if temp_min_index != j:
my_list[j], my_list[temp_min_index] = my_list[temp_min_index], my_list[j]
if is_desc:
my_list.reverse()
return my_list
new_list = [5, 4, 3, 2, 1]
print(my_select_sort(new_list))
3.4 总结
选择排序的最优最差的时间复杂度都是O(n^2),是不稳定算法。
4. 插入排序
4.1 基本思想
将一个数据插入到已经排好的有序数列中,从而得到一个新的且个数加一的有序数列,该算法适用于少量数据的排序。
4.2 实现分析
new_list = [6, 3, 4, 7, 2]
第一轮
假设6为有序数列,
3与6比较,3小于6,3和6交换位置,有序数列为3,6
第二轮
4与6比较,4小于6,4和6交换位置,然后4与3比较,4大于3,有序数列为3,4,6
第三轮
7与6比较,7大于6,有序数列为3,4,6,7
第四轮
2与7比较,2小于7,2与7交换位置,
然后2与6比较,2小于6,2与6交换位置。
然后2与4比较,2小于4,2与4交换位置。
然后2与3比较,2小于3,2与3交换位置。
此时,排序完成。
通过上述发现,每个元素都是与其前一个元素比较,直至找到合适的位置,或者是直到数列开始位置。
4.3 代码实现
def my_insert_sort(my_list, is_desc=None):
"""
插入排序
:param my_list: 需要进行排序的列表
:param is_desc: 是否从大到小,默认是否
:return:
"""
length = len(my_list)
# 外部循环,控制有多少待排序的元素
for i in range(1, length):
# 挨个比较
for j in range(i, 0, -1):
if my_list[j] < my_list[j-1]:
my_list[j], my_list[j-1] = my_list[j-1], my_list[j]
else:
break
if is_desc:
my_list.reverse()
return my_list
new_list = [6, 3, 4, 7, 2]
print(my_insert_sort(new_list))
4.4 总结
插入排序的最差时间复杂度为O(n^2),最优时间复杂度为O(n),是稳定算法。
5. 快速排序
5.1 基本思想
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小。然后再按照此方法对这两部分数据分别进行快速排序,依次类推,以此达到整个数据变成有序序列。
5.2 实现分析
首先定义两个左右游标,分别指向数列的开始和结尾。
其次定义一个界限值middle,默认为数列的第一个元素
然后分别移动左右游标遍历序列,将小于middle的值,归类到左边。
将大于middle的值,归类到右边。最后将界限值放入中间。至此,第一轮完成
然后对左右两边的数列分别进行递归快速排序。
5.3 代码实现
def my_quick_sort(my_list, start, end):
"""
快速排序
:param my_list: 需要进行排序的列表
:param start: 起始位置
:param end: 结束位置
:return:
"""
# 递归结束条件
if start >= end:
return
# 定义界限值
mid = my_list[start]
# 定义左右游标
left = start
right = end
while left < right:
# 从结尾开始找小于mid的值,归类到左边
while my_list[right] >= mid and left < right:
right -= 1
my_list[left] = my_list[right]
# 从开头开始找大于mid的值,归类到右边
while my_list[left] < mid and left < right:
left += 1
my_list[right] = my_list[left]
my_list[left] = mid
# 递归
my_quick_sort(my_list, start, left - 1)
my_quick_sort(my_list, right + 1, end)
return my_list
new_list = [5, 9, 2, 7, 10, 1, 6, 8, 4]
print(my_quick_sort(new_list, 0, len(new_list) - 1))
5.4 总结
快速排序的最差时间复杂度为O(n^2),最优时间复杂度为O(nlogn) 即2的多少次方为n。是不稳定算法。
6. 二分查找
二分查找又称折半查找,即将搜索范围不断缩小一半,以此找到需要查询的目标元素。
二分查找要求为有序数列,且为顺序存储结构。
实现代码
def my_binary_search(my_list, item):
mid = len(my_list) // 2
# 递归终止条件
if mid == 0:
return False
if my_list[mid] == item:
return True
if item > my_list[mid]:
return my_binary_search(my_list[mid:], item)
elif item < my_list[mid]:
return my_binary_search(my_list[:mid], item)
else:
return False