一、在常见的四种排序中(插入选择冒泡快速),很多时候由于对其适用的环境不够了解,我们可以尝试将其包装成一个类,并提供几个可以直接调用的类方法,便于日后的测试与深入理解。
由于要进行效率测试,所以需要一个装饰器作包装类内部方法,但在设计上,若将其封装与类内部,相比外部会使程序更加紧凑,而方法调用方面,由于排序方法可能很多,故不应该直接赋值于类,因为这样的赋值以后可能会导致使得类内部的数据混乱,所以应该为其提供一些类方法供直接调用,在编写思想上也将更加灵活。
由于列表的内存与赋值机制,使用deepcopy方法深拷贝测试,以防止被其他方法篡改数据,失去测试意义。
二、四种排序思想上的实现:
冒泡:左右两两相比,一遍找出一个极值。
选择:一遍比一值,随着运行后期比冒泡少比较很多值,理论效率高于冒泡。
插入:数据只与前面进行对比,目的只是找到自己的合适位置后,将其数据插入
快速:将数据两两分之,找出一个基准值作为界限,随后再次将其递归,重复直到low与high相等。
代码实现:
# Sort class
import time
import random
import sys
import copy
#解锁最大递归数,防止快速排序溢出
sys.setrecursionlimit(1000000)
"""
使用生成器实现可迭代的任意范围任意数量的数字
并给出get_list()方法可供调用生成列表
"""
class Rand_Iter(object):
def __init__(self, start, stop, num):
self.start = start
self.stop = stop
self.num = num
self.list = []
def get_iter(self):
while self.num > 0:
rand = random.randint(self.start, self.stop)
yield rand
self.num -= 1
def get_list(self):
self.list = []
self.iter = self.get_iter()
if iter is not None:
for val in self.iter:
self.list.append(val)
print("list created :", self.list)
return self.list
"""
目的:实现sort()四种排序类
调用方法:直接调用,并打印出运行时间
"""
class Sort():
def __init__(self, data=None):
self.data = data
def __call__(self):
return "My name is sort, my data: "
#封装并将其包装为内置调用
def time_test(func):
def wrapper(self, *args, **kwargs):
time_start = time.time()
loading = func(self, *args, **kwargs)
time_cost = time.time() - time_start
print(func.__name__ + " cost time : " + str((time_cost)))
return loading
return wrapper
@classmethod
@time_test
def bubble_sort(self, data): #冒泡排序
for i in range(len(data) - 1):
for j in range(len(data) - 1 - i):
if data[j] > data[j + 1]:
data[j], data[j + 1] = data[j + 1], data[j]
return data
@classmethod
@time_test
def insert_sort(self, data): #插入排序
for i in range(1, len(data)):
insert_value = data[i]
j = i
while j > 0 and data[j - 1] > insert_value:
data[j] = data[j - 1]
j -= 1
data[j] = insert_value
return data
@classmethod
@time_test
def selection_sort(self, data): #选择排序
for i in range(0, len(data)):
for j in range(i, len(data)):
if data[i] > data[j]:
data[i], data[j] = data[j], data[i]
return data
@classmethod
def sub_sort(cls, low, high, data): #快速排序分部一
key = data[low]
while low < high:
while low < high and data[high] >= key:
high -= 1
data[low] = data[high]
while low < high and data[low] < key:
low += 1
data[high] = data[low]
data[low] = key
return low
@classmethod
def quick_sort_step(cls, low, high, data): # #快排分部二
# low: the first element index
# high: the end element index
if low < high:
key = cls.sub_sort(low, high, data)
cls.quick_sort_step(low, key - 1, data)
cls.quick_sort_step(key + 1, high, data)
return data
@classmethod
@time_test
def quick_sort(cls, low, high, data): #供调用的方法,防止装饰器重复打印
list = cls.quick_sort_step(low, high, data)
return list
if __name__ == "__main__":
list = Rand_Iter(0, 160000, 30000).get_list() #生成30000个数字进行测试
print('\n')
print(Sort.selection_sort(copy.deepcopy(list)))
print(Sort.bubble_sort(copy.deepcopy(list)))
print(Sort.insert_sort(copy.deepcopy(list)))
print(Sort.quick_sort(0, len(copy.deepcopy(list)) - 1, copy.deepcopy(list)))
三、效率与稳定性测试
在生成3万个数据,且重复率低的情况下,测试结果(排序功能均正常,由于篇幅不展示)
selection_sort cost time : 39.127073764801025
bubble_sort cost time : 62.77434682846069
insert_sort cost time : 29.311200857162476
quick_sort cost time : 0.06635117530822754
由此可见,在数据较为庞大且重复率不高的情况下,冒泡排序效率最低,选择排序比冒泡排序提升37%,插入排序比选择提升25%,快速排序速度最快,并且远远超过前面三种排序方法。
将生成器改生成10个数据进行测试,其中重复率很低的情况下
list = Rand_Iter(0, 100, 10).get_list()
测试结果为插入排序速度最快, 冒泡次之,而快速排序竟然是速度最慢的。
selection_sort cost time : 1.0251998901367188e-05
[8, 40, 47, 64, 80, 81, 82, 84, 91, 96]
bubble_sort cost time : 9.298324584960938e-06
[8, 40, 47, 64, 80, 81, 82, 84, 91, 96]
insert_sort cost time : 5.0067901611328125e-06
[8, 40, 47, 64, 80, 81, 82, 84, 91, 96]
quick_sort cost time : 1.239776611328125e-05
[8, 40, 47, 64, 80, 81, 82, 84, 91, 96]
Process finished with exit code 0
将生成器改生成30个数字进行测试,且其中重复率很高的情况下
list = Rand_Iter(0, 10, 30).get_list()
结果却不一样了,插入排序速度最快,选择次之,快速排第三,最慢的是冒泡排序
list created : [8, 3, 10, 6, 10, 4, 3, 6, 9, 3, 8, 2, 7, 8, 8, 7, 2, 8, 3, 7, 4, 10, 8, 10, 7, 10, 6, 6, 2, 5]
selection_sort cost time : 3.314018249511719e-05
[2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 10, 10, 10, 10, 10]
bubble_sort cost time : 4.673004150390625e-05
[2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 10, 10, 10, 10, 10]
insert_sort cost time : 2.5033950805664062e-05
[2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 10, 10, 10, 10, 10]
quick_sort cost time : 3.337860107421875e-05
[2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 10, 10, 10, 10, 10]
Process finished with exit code 0
由此可见,在数据量不庞大的情况下,四种排序差别不大,冒泡/选择适合数据量小或重复率高的数据,而当数据量巨大时,插入排序上与两种排序比有效率优势,而数据量巨大的情况下最快的方法仍然是快速排序,但由于快速排序是递归实现的,如果数据量真的特别庞大时,其递归深度将会很变得很深,这可能导致与python本身限制产生冲突。