八大排序的关系及其性能比较
一、直接插入排序
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为 O(n^2)。
这是一个稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
#!-*- coding:utf-8 -*-
def insertSort(lists):
num_length = len(lists) # 记录列表的长度
for i in range(1, num_length): # 开始循环
temp = lists[i] # 记录待插入元素
j = i - 1
while j >= 0:
if lists[j] > temp: # 与其前一个数比大小
print("insert number is: ", temp) # 显示待插入元素
lists[j + 1] = lists[j] # 满足条件,改变列表中数的位置
lists[j] = temp
print("exchange number is:", lists[j + 1]) # 显示交换的元素
print(lists, "\n") # 显示排列结果
j -= 1
return lists # 返回结果
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
insertSort(list1) # 调用函数
print("\n", list1) # 显示最终结果
部分结果
其实就是将数组中的其中一个元素取出来跟前面的元素比较,如果前面的元素比较大就将两者交换(第一个元素不用比较,再前面没有元素)。比如第三个元素就跟第二第一的元素比较,以此类推。
二、希尔排序
希尔排序( Shell Sort )是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 DL.Shell 于 1959 年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
#-*- coding:utf-8 -*-
import math
def shellSort(lists):
num_length = len(lists) # 记录列表的长度
step = 2 # 设置步长
group = num_length // step # 将列表进行分组
while group > 0:
for i in range(0, group):
j = i + group
while j < num_length: # 设置循环条件
k = j - group
temp = lists[j] # 记录待插入元素
while k >= 0:
if lists[k] > temp:
print("Forward number:", temp) # 显示插入的元素
lists[k + group] = lists[k] # 满足条件,改变列表中数的位置
lists[k] = temp
print("Exchange number:", lists[k + group]) # 显示交换的元素
print(list1, "\n")
k -= group
j += group
group //= step
return lists # 返回结果
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
shellSort(list1) # 调用函数
print("\n",list1) # 显示最终结果
部分结果
先将待排序序列的数组元素分成多个子序列,使得每个子序列的元素个数相对较少,然后对各个子序列分别进行直接插入排序,待整个待排序序列“基本有序”后,再对所有元素进行一次直接插入排序。
三、简单选择排序
基本思想:第 1 趟,在待排序记录 r1 ~ r[n] 中选出最小的记录,将它与 r1 交换;第 2 趟,在待排序记录 r2 ~ r[n] 中选出最小的记录,将它与 r2 交换;以此类推,第 i 趟在待排序记录 r[i] ~ r[n] 中选出最小的记录,将它与 r[i] 交换,使有序序列不断增长直到全部排序完毕。
#-*- coding:utf-8 -*-
def selectSort(lists):
num_length = len(lists) # 记录列表的长度
for i in range(num_length):
min = i
for j in range(i + 1, num_length):
if lists[min] > lists[j]:
min = j
print("Select number:", lists[i]) # 显示选择的数字
lists[min], lists[i] = lists[i], lists[min] # 满足条件,改变列表中数的位置
print("Exchange number:", lists[i]) # 显示交换的数字
print(lists, "\n")
return lists
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
selectSort(list1) # 调用函数
print("\n",list1) # 显示最终结果
结果
对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换;接着对不包括第一个记录以外的其他记录进行第二轮比较,得到最小的记录并与第二个记录进行位置交换;重复该过程,直到进行比较的记录只有一个时为止。
四、堆排序
堆排序( Heapsort )是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。
- 堆的概念
堆是一棵顺序存储的完全二叉树。完全二叉树中所有非终端节点的值均不大于(或不小于)其左、右孩子节点的值。
其中每个节点的值小于等于其左、右孩子的值,这样的堆称为小根堆;
其中每个节点的值大于等于其左、右孩子的值,这样的堆称为大根堆;
#-*- coding:utf-8 -*-
# 调整堆
def adjustHeap(lists, i, size):
lchild = 2 * i + 1
rchild = 2 * i + 2
max = i
if i < size // 2:
if lchild < size and lists[lchild] > lists[max]:
max = lchild
if rchild < size and lists[rchild] > lists[max]:
max = rchild
if max != i:
lists[max], lists[i] = lists[i], lists[max]
adjustHeap(lists, max, size)
# 创建堆
def buildHeap(lists, size):
for i in range(0, (size//2))[::-1]:
adjustHeap(lists, i, size)
# 堆排序
def heapSort(lists):
size = len(lists)
buildHeap(lists, size)
for i in range(0, size)[::-1]:
lists[0], lists[i] = lists[i], lists[0]
adjustHeap(lists, 0, i)
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
heapSort(list1) # 调用函数
print(list1) # 显示最终结果
结果
将数组构造成初始堆(若想升序则建立大根堆,若想降序,则建立小根堆)。从最后一个节点开始调整,得到初始堆。交换堆顶的元素和最后一个元素,此时最后一个位置作为有序区(有序区显示为黄色),然后进行其他无序区的堆调整,重新得到大顶堆后,交换堆顶和倒数第二个元素的位置,重复此过程,最后,有序扩展完成即排序完成。
五、冒泡排序
它重复地走访过要排序的列表,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该列表已经排序完成。
#-*- coding:utf-8 -*-
def bubbleSort(lists):
num_length= len(lists) # 记录列表的长度
for i in range(num_length):
for j in range(i + 1, num_length):
if lists[i] > lists[j]:
lists[i], lists[j] = lists[j], lists[i] # 满足条件,改变列表中数的位置
print(lists) # 显示排序过程
return lists
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
bubbleSort(list1) # 调用函数
print("\n", list1) # 显示最终结果
结果
依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第 1 个和第 2 个数,将小数放前,大数放后。然后比较第 2 个数和第 3 个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。
六、快速排序
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
#-*- coding:utf-8 -*-
def quickSort(lists, left, right):
if left >= right:
return lists
temp= lists[left]
low = left
high = right
while left < right:
while left < right and lists[right] >= temp:
right -= 1
lists[left] = lists[right]
while left < right and lists[left] <= temp:
left += 1
lists[right] = lists[left]
lists[right] = temp
quickSort(lists, low, left - 1)
quickSort(lists, left + 1, high)
return lists
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
quickSort(list1, 0, len(list1)-1) # 调用函数
print("\n", list1) # 显示最终结果
结果
选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素。
一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引>从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了。接着分别比较左右两边的序列,重复上述的循环。
七、归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法( Divide and Conquer )的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
#-*- coding:utf-8 -*-
def merge(left, right):
i, j = 0, 0
result = []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
def mergeSort(lists):
# 归并排序
if len(lists) <= 1:
return lists
num = len(lists) // 2
left = mergeSort(lists[:num])
right = mergeSort(lists[num:])
return merge(left, right)
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
print( mergeSort(list1) ) # 调用函数并显示最终结果
总结
比较 a[i] 和 a[j] 的大小,若 a[i] ≤ a[j] ,则将第一个有序表中的元素 a[i] 复制到 r[k] 中,并令 i 和 k 分别加上 1 ;否则将第二个有序表中的元素 a[j] 复制到 r[k] 中,并令 j 和 k 分别加上 1 ,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到 r 中从下标 k 到下标 t 的单元。归并排序的算法我们通常用递归实现,先把待排序区间 [s,t] 以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间 [s,t] 。
八、基数排序
基数排序( radix sort )属于“分配式排序”( distribution sort ),又称“桶子法”( bucket sort )或 bin sort ,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O ( nlog ( r ) m ),其中r为所采取的基数,而 m 为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
#!-*- coding:utf-8 -*-
import math
def radixSort(lists, radix=10):
k = int(math.ceil(math.log(max(lists), radix)))
bucket = [[] for i in range(radix)]
for i in range(1, k+1):
for j in lists:
bucket[j // (radix**(i-1)) % (radix**i)].append(j)
del lists[:]
for z in bucket:
lists += z
print(lists) # 显示排序过程
del z[:]
return lists
list1 = [6,5,7,9,2,3,1,8,4] # 自定义一个列表
print("\n", radixSort(list1) ) # 调用函数并显示最终结果
结果
最高位优先(MostSignificantDigitfirst)法,简称MSD法,例如:135、242、192、93、> 345、11、24、19
我们将每个数值的个位,十位,百位分成三个关键字,如:135->k1(个位)=5,k2(十位)=3,k3(百位)=1。
然后从最低位个位开始(从最次关键字开始),对所有数据的k1关键字进行桶分配(因为,每个数字都是0-9的,因此桶大小为10),再依次输出桶中的数据得到下面的序列。
(11)、(242、192)、(93)、(24)、(135、345)、(19)(从最次关键字开始排序,忽略百位与十位,按照个位上的数字分配)
再对上面的序列接着进行针对k2的桶分配,输出序列为:
(11、19)、(24)、(135)、(242、345)、(192、93)(参考最次关键字来排序第二次关键字,忽略百位与个位,按照十位上的数字分配)
最后针对k3的桶分配,输出序列为:
(011、019、024、093)、(135、192)、(242)、(345)(参考第二次关键字来排序最高关键字,忽略十位与个位,按照百位上的数字分配)
排序完毕。
本文内容部分取自百度内容,如有雷同部分请见谅。