《漫画算法》--排序算法

154 阅读4分钟

根据时间复杂度,主流的排序算法可以分为三大类:

1. 时间复杂度为O(n2)的排序算法

  • 冒泡排序
  • 选择排序
  • 插入排序
  • 希尔排序(希尔排序比较特殊,它的性能略优于O(n2),但又比不上O(nlogn),姑且把它归为本类)

2. 时间复杂度为O(nlogn)的排序算法

  • 快速排序
  • 归并排序
  • 堆排序

3. 时间复杂度为线性的排序算法

  • 计数排序
  • 桶排序
  • 基数排序

排序算法还可以根据其稳定性,划分为 稳定排序不稳定排序。即如果值相同的元素在排序后仍然保持着排序前的顺序,则这样的排序算法是稳定排序;如果值相同的元素在排序后打乱了排序前的顺序,则这样的排序算法是不稳定排序。


一.冒泡排序

1.什么是冒泡算法

  • 冒泡排序的英文是bubble sort,它是一种基础的交换排序。
  • 冒泡排序之所以叫冒泡排序,正因为这种排序算法的每一个元素都可以像小气泡一样,根据自身大小,一点一点地往数组的一侧移动。
  • 冒泡排序是一种稳定排序,值相等的元素并不会打乱原本的顺序。
  • 冒泡排序每一轮都要遍历所有元素,总过遍历(元素数量-1)轮,所以平均时间复杂度是O(n2)
  • 排序原理:相邻的元素两两比较,当一个元素大于右侧相邻元素时,交换它们的位置;当一个元素小于或等于右侧元素时,位置不变。
  • 算法每一轮都是从左到右比较元素,并进行单项的位置交换
	def bubble_sort_v1(array = []):
    	for i in range(len(array) - 1):
        	for j in range(len(array) - i - 1):
            	if array[j] > array[j+1] :
            	    # temp = array[j]
                    # array[j] = array[j+1]
                    # array[j+1] = temp 
                    array[j], array[j+1] = array[j+1], array[j]
                    
    my_array = list ([3,4,14,1,5,6,7,8,1,-1,1,0,9,11])
    bubble_sort_v1(my_array)
    print(my_array)
            	

2.冒泡排序的优化

	def bubble_sort_v2(array = []):
    	for i in range(len(array) - 1):
        	# 有序标记,每一轮的初始是True
	    is_sorted = True
            for j in range(len(array) - i - 1):
            	if array[j] > array[j+1] :
            	    # temp = array[j]
                    # array[j] = array[j+1]
                    # array[j+1] = temp 
                    array[j], array[j+1] = array[j+1], array[j]
                    # 有元素交换,所有不是有序的,标记变为Fasle
                    is_sorted = False
            if is_sorted:
            	break
                    
    my_array = list ([3,4,14,1,5,6,7,8,1,-1,1,0,9,11])
    bubble_sort_v1(my_array)
    print(my_array)
            	

def bubble_sort_v3(array = []):
    # 记录最后一次交换的位置
    last_exchange_idnex = 0
    # 无序数列的边界, 每次比较只需要比到这里
    sort_border = len(array)-1
	for i in range(len(array) - 1):
            # 有序标记,每一轮的初始是True
	    is_sorted = True
            for j in range(sort_border):
            	if array[j] > array[j+1] :
            	    # temp = array[j]
                    # array[j] = array[j+1]
                    # array[j+1] = temp 
                    array[j], array[j+1] = array[j+1], array[j]
                    # 有元素交换,所有不是有序的,标记变为Fasle
                    is_sorted = False
                    # 把无序数列的边界更新为最后一次交换的位置
                    last_exchange_index = j
            sort_border = last_exchange_index
            if is_sorted:
            	break
                    
    my_array = list ([3,4,14,1,5,6,7,8,1,-1,1,0,9,11])
    bubble_sort_v1(my_array)
    print(my_array)
     
'''
	sort_border 就是无序数列的边界。在每一轮排序过程中,处于sort_border之后的元素就不需要再进行比较了
'''

3.鸡尾酒排序

  • 冒泡排序算法每一轮都是从左到右比较元素,并进行单项的位置交换
  • 鸡尾酒排序的元素比较和交换过程是双向的。排序过程如钟摆一样,第一轮从左到右,第二轮从右到左,第三轮...
def cock_tail_sort(array = []):
	for i in range(len(array) //2):
        # 有序标记,每一轮的初始是True
            is_sorted = True
            # 奇数轮,从左到右比较和交换
            for j in range(i,len(array-1) - i - 1):
                if array[j] > array[j+1]:
                    array[j], array[j+1] = array[j + 1], array[j]
                    # 有元素交换,所以不是有序的, 标记为False
                    is_sorted = False
            if is_sorted:
          	    break
            # 偶数轮之前,重新标记为True
            is_sorted = True
            # 偶数轮, 从右到左比较和交换
            for j in range(len(array) - i - 1, i , -1):
                if array[j] < array[j + 1]:
                    array[j], array[j + 1] = array[j + 1], array[j]
                    # 有元素交换, 所以不是有序的, 标记为False
                    is_sorted = False
            if is_sorted:
                break
     
my_array = list([3, 4, 14, 1, 5, 6, 7, 8, -1, 1, 0, 9, 11])
cock_tail_sort(my_array)
print(my_array)

'''
    这代码是鸡尾酒排序的实现。 代码外层的大循环控制着所有排序回合,大循环内包含2个小循环,第1个循环从左往右比较并交换元素,第2个循环从右到左比较并交换元素。每次钟摆为一次大循环。
'''
            
  • 鸡尾酒排序的优点是能在特定条件下,减少排序的回合数;而缺点也很明显,就是代码量几乎增加了1倍。
  • 适用于大部分元素已经有序的情况下。