1.冒泡排序
冒泡排序
1.比较相邻的元素,如果第一个比第二个大(升序),就交换他们两个
2.对每一对相邻的元素做同样的工作,从开始到结尾的最后一对
这步做完后,最后的元素会是最大的数
3.针对所有的元素重复以上的步骤,除了最后一个
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
5.稳定性:数值相同的元素在排序中不交换位置为稳定反之为不稳定
6.最优复杂度:O(n) 最坏复杂度:O(n^2) 稳定性:稳定
代码实现:
def bubble_sort(alist):
"""冒泡排序"""
n = len(alist)
for j in range(n-1):
# range(5)的取值范围是从0~4此处要取到n-2(下标从0开始)所以
# 此处的值为n-1
count = 0
# 如果进行了交换count加一,如果内层循环中发现某次交换一次都没有发生
# 即count == 0,则说明列表已经是有序的了,直接退出外层循环,优化了程序
for i in range(n-1-j):
if alist[i] > alist[i+1]:
alist[i], alist[i+1] = alist[i+1], alist[i]
count += 1
if count == 0:
break
if __name__ == '__main__':
li = [56, 88, 12, 62, 54, 79, 32, 11, 96]
print(*li)
bubble_sort(li)
print(*li)
2.选择排序
选择排序
1.始终从未排序的序列中找到最小的放到最前面
2.将第一个元素先作为最小值,用第一个元素和后面的元素依次比较
3.首次碰见比第一个元素更小的元素就记录这个“较小元素”的位置
4.继续比较如果碰见比“较小元素”还更小的元素,就将记录的“较小元素”的位置信息,替换成“更小元素”的位置信息
5.直到比较完整个序列,最小的元素位置信息就被记录下来了
6.交换第一个元素和最小元素的位置,序列的头部就变成了最小的元素
7.再将第二个元素先作为序列剩余元素的最小元素,和剩下的元素重复上述步骤进行比较
8.将第二小的元素找到,并和第二个元素进行交换
9.多次重复上述步骤n-1次,即可得到升序序列
10.最优复杂度:O(n^2) 最坏复杂度:O(n^2) 稳定性:不稳定
代码实现:
def select_sort(alist):
"""选择排序"""
n = len(alist)
for j in range(n-1):
# 列表的长度为n,从0开始计算一共为n-1个数。
# 最后一趟只剩最后一个数,一定是最大的不用比较。
# 所以只需要比较n-2次。
min_index = j
for i in range(j+1, n):
if alist[min_index] > alist[i]:
min_index = i
alist[j], alist[min_index] = alist[min_index], alist[j]
if __name__ == '__main__':
li = [56, 26, 77, 6, 54, 38, 96, 43, 99]
print(*li)
select_sort(li)
print(*li)
3.插入排序
插入排序
⒈ 从第一个元素开始,该元素可以认为已经被排序
⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描
⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置
⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
⒌ 将新元素插入到下一位置中
⒍ 重复步骤2~5
7. 最优复杂度:O(n) 最坏复杂度:O(n^2) 稳定性:稳定
代码实现:
def insert_sort(alist):
"""插入排序"""
n = len(alist)
for j in range(1, n):
# 1~n-1
for i in range(j, 0, -1):
# range(start, stop[, step])
# stop的值要取前一个,所以此处取值为j~1,
if alist[i] < alist[i-1]:
alist[i], alist[i-1] = alist[i-1], alist[i]
# 此处为对代码的优化
# 因为序列的alist[i]之前的序列已经是有序的了
# 如果alist[i] >= alist[i-1]直接放入前面的有序部分的尾部就行
# 没有必要再和前面的元素依次比较了
# 此处的优化使代码的最优时间复杂度由O(n^2)变为了O(n)
else:
break
if __name__ == '__main__':
# li = [5, 3, 2, 4, 7, 1, 6]
li = [1, 2, 3, 4, 5, 4, 6, 7]
print(*li)
# start_time = time.time()
insert_sort(li)
# end_time = time.time()
print(*li)
# print(end_time-start_time)
4.希尔排序
希尔排序
1.希尔排序是按照不同步长对元素进行插入排序
2.当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快
3.当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。
4.最优复杂度:O(n^1.3) 最坏复杂度:O(n^2) 稳定性:不稳定
代码实现:
def shell_sort(alist):
"""希尔排序"""
n = len(alist)
step = n//2
while step > 0:
for j in range(step, n):
for i in range(j, 0, -step):
if alist[i] < alist[i-step]:
alist[i], alist[i-1] = alist[i-1], alist[i]
else:
break
step = step//2
if __name__ == '__main__':
li = [56, 26, 77, 6, 54, 38, 96, 43, 99]
print(*li)
shell_sort(li)
print(*li)
5.快速排序(划重点)
快速排序
通过一趟排序将要排序的数据分割成独立的两部分
其中一部分的所有数据都比另外一部分的所有数据都要小
然后再按此方法对这两部分数据分别进行快速排序
整个排序过程可以递归进行,以此达到整个数据变成有序序列
过程描述
1.定义一个标杆,将列表的第一个元素存入标杆,列表的第一个位置相当于空出来了
2.定义两个指针low,high,分别记录列表头和列表尾的位置
3.判断low是不是小于high,列表尾high位置的元素是不是大于等于标杆,如果是high向左移动一位
重复执行这步判断,当条件不成立时,让low位置存放当前high位置的元素
4.判断low是不是小于high,列表头low位置的元素是不是小于标杆,如果是low向右移动一位
重复执行这步判断,当条件不成立时,让high位置存放当前low位置的元素
5.让4、5两步交替执行,直到low >= high时退出循环。此时low = high
6.此时找到的low的位置就是标杆的位置,将记录的标杆元素,放置在这个位置。
7.递归执行上述步骤直到low >= high时退出。
8.最优时间复杂度计算:n拆分多少次能只剩一个元素,也就是n除以多少次2能等于1
即n/2^x = 1 --> 2^x = n --> x = logn (log以2为底,n的对数)
每次让列表中的值沿着初始值分为左右两半的过程的时间复杂度为n
所以最优时间复杂度为nlogn
9.最优复杂度:O(nlogn) 最坏复杂度:O(n^2) 稳定性:不稳定
代码实现:
def quick_sort(alist, first, last):
"""快速排序"""
if first >= last:
return
mid_value = alist[first]
low = first
high = last
while low < high:
# high左移
while low < high and alist[high] >= mid_value:
high -= 1
alist[low] = alist[high]
# low 右移
while low < high and alist[low] < mid_value:
low += 1
alist[high] = alist[low]
# 循环退出low = high
alist[low] = mid_value
# 对low左边的进行快速排序
quick_sort(alist, first, low-1)
# 对low右边的进行快速排序
quick_sort(alist, low+1, last)
if __name__ == '__main__':
li = [56, 45, 33, 22, 96, 79, 88, 64, 9, 16, 8, 21, 25, 28]
print(*li)
quick_sort(li, 0, len(li)-1)
print(*li)
6.归并排序
归并排序
归并排序的思想是先递归分解数组,再合并数组
将数组分解最小之后,然后合并两个有序数组。
基本思路就是比较两个数组最前面的数,谁小就取谁,
取了后相应的指针就往后移一位。
然后再比较,直至一个数组为空,最后把两一个数组的剩余部分复制过来即可。
最优复杂度:O(nlogn) 最坏复杂度:O(nlogn) 稳定性:稳定
代码实现:
import random
def merge_sort(alist):
"""归并排序"""
n = len(alist)
if n <= 1:
return alist
mid = n//2
# left 采用归并排序后形成的有序的新的列表
left_li = merge_sort(alist[:mid])
# right 采用归并排序后形成的有序的新的列表
right_li = merge_sort(alist[mid:])
# 将两个有序的子序列合并为一个新的整体
left, right = 0, 0
result = []
while left < len(left_li) and right < len(right_li):
# print(left_li[left], right_li[right])
if left_li[left] <= right_li[right]:
result.append(left_li[left])
left += 1
else:
# right_li[right] < left_li[left]
result.append(right_li[right])
right += 1
result += left_li[left:]
result += right_li[right:]
return result
if __name__ == '__main__':
li = []
for i in range(10):
li.append(random.randint(1, 100))
print(*li)
result = merge_sort(li)
print(*result)
7.二分查找
代码实现:
def binary_search(alist, item):
"""二分法查找_递归"""
n = len(alist)
if n > 0:
mid = (n-1) // 2
if alist[mid] == item:
return True
elif item < alist[mid]:
return binary_search(alist[:mid], item)
else:
return binary_search(alist[mid+1:], item)
else:
return False
def binary_search_2(alist, item):
"""二分法查找_非递归"""
n = len(alist)
last = n - 1
first = 0
while first <= last:
mid = (first + last) // 2
# 找到alist[i]要插入的位置
if alist[mid] == item:
return True
elif item < alist[mid]:
last = mid-1
else:
first = mid+1
return False
if __name__ == "__main__":
li = [i for i in range(20)]
print(li)
print(binary_search(li, 18))
print(binary_search_2(li, 16))
文章有不足之处或您有更好的方案想法,欢迎评论区留言。