冒泡排序
排序核心思想
冒泡排序的核心思想在于将数组分为无序区和有序区,通过遍历数组将数组中最大的数移动到数组末尾,每完成一次遍历,无序区元素数量减一,有序区数量加一,值得注意的是,遍历只需遍历n-1次,其中n是数组长度,即可完成排序。
优化
当给定的数组已经排序好时,此时该算法仍需遍历次,大大降低了算法的运行效率。那么如何解决这个情况呢?我们可以定义一个变量exhange,通过遍历完成后exchange的值是否变化来决定遍历的是否进行,从而优化算法,提高效率。
代码实现
def bubble_sort(list):
right = len(list) - 2
exchange = False
while right >= 0:
for left in range(0, right + 1):
if list[left] > list[left + 1]:
list[left], list[left + 1] = list[left + 1], list[left]
exchange = True
right -= 1
if exchange == False:
break
return list
首先定义两个指针left和right,其中left是遍历指针,而right决定了left的终止位置,当一次遍历完成后,right指针左移,当right指针指向数组的0号索引时代码结束运行。若给定的数组已经排好序时,则第一次遍历完成后exchange的值不会变化,仍为False,后加上判断跳出循环即可。
复杂度分析
时间复杂度:1.最好情况:
2.最坏情况:
空间复杂度:
选择排序
排序核心思想
选择排序的核心思想在于将数组分为无序区和有序区两部分,初始时有序区内的元素个数为0,后通过循环遍历无序区内的元素找到最小值,将最小值与无序区内的第一个元素交换,有序区内元素个数加一,直至无序区内元素个数为0结束。
代码实现
def select_sort(list):
left = 0
while left <= len(list) - 2:
min_val_index = left
for right in range(left, len(list)):
if list[right] < list[min_val_index]:
min_val_index = right
if min_val_index != left: # 若遍历完一次,min_val_index的值仍为left,这说明left所在的值就是无序区的最小值,不需要进行交换
list[min_val_index], list[left] = list[left], list[min_val_index]
left += 1
return list
首先初始化left指针指向0,left指针的作用为确定无序区第一个元素的位置,以便于遍历完成后交换的实现。left的范围是从0到数组的倒数第二号索引,因为当有序区元素个数为n-1时(其中n是数组长度),该数组就已经完成了有序化。后循环遍历无序区元素,并记录最小值索引的位置,循环完成后交换该索引和left所指的元素。需要注意的是,若完成一次遍历,最小值索引的值仍为left,则说明left所指的元素就是无序区的最小值,不需要进行交换。
复杂度分析
时间复杂度:
空间复杂度:
插入排序
排序核心思想
插入排序的核心思想也是将数组分为有序区和无序区两部分,初始时有序区的元素个数为1,后循环不断选取无序区的第一个元素并将其插入到有序区的正确位置,有序区元素个数加一,直至有序区元素个数为n(其中n是数组长度),不是n-1的原因是无法保证末尾元素是该数组中的最大元素或最小元素。
代码实现
def insert_sort(list):
if len(list) <= 1:
return list
for i in range(1, len(list)):
j = i - 1
while j >= 0 and list[j + 1] < list[j]:
list[j + 1], list[j] = list[j], list[j + 1]
j -= 1
return list
首先判断输入数组的长度,若小于1则直接返回列表,该操作的目的在于防止后续索引溢出报错。后定义指针i,i指向的是无序区的第一个元素,接下来就是插入操作的实现,插入操作的本质是元素的交换,通过定义指针j,不断比较j和j+1所指向的元素,若list[j + 1] < list[j]则进行交换,后j左移继续进行比较,直至元素无序区第一个元素到达正确位置。其中为了保证j不超出索引而导致报错,需要加上j >= 0这一条件。
复杂度分析
时间复杂度:
空间复杂度: