排序算法大致可以分为两类:
算法的复杂度可以参考下图:
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端
。
# -*- coding: UTF-8 -*-
import random
def random_int_list(start, stop, length):
start, stop = (int(start), int(stop)) if start <= stop else (int(stop),
int(start))
length = int(abs(length)) if length else 0
random_list = []
for i in range(length):
random_list.append(random.randint(start, stop))
return random_list
def bubble_sort(alist):
"""
冒泡排序
最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束)
最坏时间复杂度:O(n^2)
稳定性:稳定
"""
n = len(alist)
# 结算列表的长度
n = len(alist)
# 外层循环控制从头走到尾的次数
for i in range(n - 1):
# 用一个count记录一共交换的次数,可以排除已经是排好的序列
count = 0
# 内层循环控制走一次的过程
for j in range(0, n - 1 - i):
# 如果前一个元素大于后一个元素,则交换两个元素(升序)
if alist[j] > alist[j + 1]:
# 交换元素
alist[j], alist[j + 1] = alist[j + 1], alist[j]
# 记录交换的次数
count += 1
# count == 0 代表没有交换,序列已经有序
if 0 == count:
break
return alist
if __name__ == "__main__":
for i in range(random.randint(10, 20)):
_list = random_int_list(-100, 100, random.randint(1, 20))
sorted_list = bubble_sort(_list)
print(sorted_list == sorted(_list), sorted_list)
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:
# -*- coding: UTF-8 -*-
import random
def random_int_list(start, stop, length):
start, stop = (int(start), int(stop)) if start <= stop else (int(stop),
int(start))
length = int(abs(length)) if length else 0
random_list = []
for i in range(length):
random_list.append(random.randint(start, stop))
return random_list
def selection_sort(alist):
"""
选择排序
最优与最坏时间复杂度都是:O(n^2)
稳定性:稳定
"""
# 结算列表的长度
n = len(alist)
# 外层循环控制从头走到尾的次数
for i in range(n - 1):
# 假定最小的数的下标是i
min_index = i
for j in range(i + 1, n):
# 如果后面的数比假定的最小数还大,就更新这个index值
if alist[min_index] > alist[j]:
min_index = j
# 如果min_index更新了,就把最小值放到前面
if i != min_index:
alist[i], alist[min_index] = alist[min_index], alist[i]
return alist
if __name__ == "__main__":
for i in range(random.randint(10, 20)):
_list = random_int_list(-100, 100, random.randint(1, 20))
# sorted_list = bubble_sort(_list)
sorted_list = selection_sort(_list)
print(sorted_list == sorted(_list), sorted_list)
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
# -*- coding: UTF-8 -*-
import random
def random_int_list(start, stop, length):
start, stop = (int(start), int(stop)) if start <= stop else (int(stop),
int(start))
length = int(abs(length)) if length else 0
random_list = []
for i in range(length):
random_list.append(random.randint(start, stop))
return random_list
def insert_sort(alist):
"""
插入排序:假定左边都是有序的,将右边的数一个一个插入到左边有序数列中
"""
# 结算列表的长度
n = len(alist)
# 外层循环控制从头走到尾的次数
for i in range(n - 1):
preIndex = i - 1
# 将要比较的数
current = alist[i]
# 在左边有序数列总找到所有比当前数更大的数
while preIndex >= 0 and alist[preIndex] > current:
# 元素后移
alist[preIndex + 1] = alist[preIndex]
# 往前遍历
preIndex -= 1
# 找到插入位置后,插入
alist[preIndex + 1] = current
return alist
if __name__ == "__main__":
for i in range(random.randint(10, 20)):
_list = random_int_list(-100, 100, random.randint(1, 20))
# sorted_list = bubble_sort(_list)
# sorted_list = selection_sort(_list)
sorted_list = insert_sort(_list)
print(sorted_list == sorted(_list), sorted_list)
1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
def shell_sort(alist):
"""
希尔排序:类似于分组的插入排序
"""
# 结算列表的长度
n = len(alist)
gap = n >> 1 # 这里用 n//2(整除2)也可以
while gap > 0:
# 从第gap个元素,逐个对其所在组进行直接插入排序操作
for i in range(gap, n):
temp = i
while (temp - gap) >= 0 and alist[temp] < alist[temp - gap]:
alist[temp], alist[temp - gap] = alist[temp - gap], alist[temp]
temp -= gap
gap >>= 1
return alist
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
def merge_sort(alist):
n = len(alist)
if n <= 1:
return alist
mid = n >> 2
left = merge_sort(:mid)
right = merge_sort(mid:)
merge(left, right)
def merge(left, right):
i,j = 0, 0
res = []
while i < len(left) and j < len(right):
if left[i] <= left[right]:
res.append(left[i])
left += 1
else:
res.append(right[j])
right += 1
res.append(left[i:])
res.append(right[j:])
return res
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
1.在待排序的元素任取一个元素作为基准(通常选第一个元素,但最的选择方法是从待排序元素中随机选取一个作为基准),称为基准元素;
2.将待排序的元素进行分区,比基准元素大的元素放在它的右边,比其小的放在它的左边;
3.对左右两个分区重复以上步骤直到所有元素都是有序的。
基准数为8,以基准数为8划分成左右两部分,这里右边部分没有,只有左边部分
基准数为5,以基准数为5划分成左右两部分
def quick_sort(array, left, right):
if left == right:
return array
if left > right:
return
low = left
high = right
key = array[low]
while left < right:
# 找到右边第一个小于于key的数值下标
while left < right and array[right] > key:
right -= 1
# 左拆右补
array[left] = array[right]
# 找到左边第一个大于等于于key的数值下标
while left < right and array[left] <= key:
left += 1
# 右拆左补
array[right] = array[left]
array[right] = key
quick_sort(array, low, left - 1)
quick_sort(array, left + 1, high)
return array
if __name__ == "__main__":
for i in range(random.randint(10, 20)):
_list = random_int_list(-100, 100, random.randint(1, 20))
sorted_list = quick_sort(_list, 0, len(_list) - 1)
print(sorted_list == sorted(_list), sorted_list)
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn)。
堆(heap)也被称为优先队列(priority queue)。队列中允许的操作是先进先出(FIFO),在队尾插入元素,在队头取出元素。而堆也是一样,在堆底插入元素,在堆顶取出元素,但是堆中元素的排列不是按照到来的先后顺序,而是按照一定的优先顺序排列的。这个优先顺序可以是元素的大小或者其他规则。如图一所示就是一个堆,堆优先顺序就是大的元素排在前面,小的元素排在后面,这样得到的堆称为最大堆。最大堆中堆顶的元素是整个堆中最大的,并且每一个分支也可以看成一个最大堆。同样的,我们可以定义最小堆。如图所示
https://www.cnblogs.com/chengxiao/p/6129630.html
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
步骤一、 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。
假设给定无序序列结构如下图示
.调整后得到一个大顶堆,如下图所示
步骤二、 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。
1、将堆顶元素9和末尾元素4进行交换
2、重新调整结构,使其继续满足堆定义
3、再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.
4、后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序
再简单总结下堆排序的基本思路:
a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。