第九章 排序
标签(空格分隔): 数据结构
一、排序的问题和定义
对于同一集实际数据,完全可能存在很多种不同的但都有意义的序。
排序算法
内排序:在一个排序工作的执行过程中,待排序的记录全部保存在内存,这种工作就成为内排序;
外排序:针对外存(磁盘)数据的排序工作称为外排序。
排序工作要求数据集合存在一种可用的序。数据本身有自然的序,也可以给它造出一种序,最典型的方法就是设计一种hash函数,把数据集的元素映射到某个有序集,如整数集合的子集。
基于关键码比较,数据记录排序,比较之后调整数据记录的位置,可以确定两种最重要的基本操作:
①比较关键码的操作,通过这种操作确定数据的顺序关系。
②移动数据记录的操作,用于调整记录的位置和顺序。
n为数据长度,讨论在完成整个排序过程中执行上述两种操作的次数,以此作为评价算法效率的度量(时间复杂度)
理论研究的明确结论:基于关键码比较的排序问题,时间复杂度是O(n log(n))。也就是说,实现这一过程的任何算法都不可能优于O(n log(n))
- 执行算法所需要的空间:对已有的序列排序,算法完成后被排序的序列依然存在。临时性辅助空间用过之后就释放了,但其大小需要考量。
- 内存排序算法的空间需求,特别关注其空间复杂度是否常量。常量的空间开销意味着排序工作可以在原序列里完成,只需要用几个简单变量作为操作中的临时存储。原地排序算法。
稳定性:稳定的算法能够维持序列中所有排序码相同记录的相对位置。
适应性:如果一个排序算法对接近有序的序列工作更快,那么就有适应性。
常见的分类方法:插入、选择、交换、分配、归并、外部排序
简单排序算法
共同特点是简答并且最坏情况的复杂度高
插入排序
# 插入排序
def insert_sort(lst):
for i in range(1, len(lst)):
x = lst[i]
j = i
while j > 0 and lst[j - 1].key > x.key:
lst[j] = lst[j - 1]
j -= 1
lst[j] = x
简单的插入排序:最坏情况下O(n^2),算法稳定。
经常被用于高级排序算法,作为其中一部分。希尔排序,shell排序,采用一种变动间隔的排序技术,其中用简单插入排序作为基础算法,可以得到更高的操作效率。
采用切分待排序序列(例如快速和归并排序),切分得到的序列很短时,就转到简单的插入排序算法。python语言的内置排序算法就是如此—–切分待排序!
选择排序
def select_sort(lst):
for i in range(len(lst) - 1): # 确定范围,至倒数2
k = i
for j in range(i, len(lst)):
if lst[j].key < lst[k].key: # 取i位置后的min
k = j
if i != k: # 最小值不是首元素时
lst[i], lst[k] = lst[k], lst[i]
冒泡排序
def bubble_sort(lst):
for i in range(len(lst)):
found = False
for j in range(1, len(lst) - i):
if lst[j - 1].key > lst[j].key:
lst[j - 1], lst[j] = lst[j], lst[j - 1]
found = True
if not found:
break
归并排序
def merge(from_lst, to_lst, low, m, high):
i, j, k = low, m, low
while i < m and j < high: # 反复复制两段首记录中较小的
if from_lst[i].key <= from_lst[j].key:
to_lst[k] = from_lst[i]
i += 1
else:
to_lst[k] = from_lst[j]
j += 1
k += 1
while i < m: # 复制第一段剩余记录
to_lst[k] = from_lst[i]
i += 1
k += 1
while j < high: # 复制第二段剩余记录
to_lst[k] = from_lst[j]
j += 1
k += 1
def merge_pass(from_lst, to_lst, llen, slen):
i = 0
while i + 2 * slen < llen: # 归并长len的两段
merge(from_lst, to_lst, i, i + slen, i + 2 * slen)
i += 2 * slen
if i + slen < llen: # 剩下两段,后段长度小于 slen
merge(from_lst, to_lst, i, i + slen, llen)
else: # 只剩下一段,复制到数组to
for j in range(i, llen):
to_lst[j] = from_lst[j]
def merge_sort(lst):
slen, llen = 1, len(lst)
templst = [None] * llen
while slen < llen:
merge_pass(lst, templst, llen, slen)
slen *= 2
merge_pass(templst, lst, llen, slen) # 结果存回原位
slen *= 2