python排序算法及优化学习笔记1

简介: python实现的简单的排序算法,以及算法优化,学习笔记1

1.排序算法

1.1冒泡排序

1.1.1算法描述(摘自网络)

原始算法:

1.        比较相邻的元素。如果第一个比第二个大,就交换它们两个;

2.        对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;

3.        针对所有的元素重复以上的步骤,除了最后一个;

4.        重复步骤1~3,直到排序完成。

算法优化:

每一轮步骤1~3排序结束后,如果没有进行排序操作,则表示整个数组已经满足了升序或者降序的顺序,不需要继续排序了,此时退出循环排序,节省时间。

1.1.2算法实现

输入:

Src:一个数组

Order0是降序,1是升序

Opt:默认为True,使用优化算法,False为原始排序算法

@time_count

def bubble(src: list, order=1, opt=True):    

   # src: list

   # order: 0 descend, 1 ascend

   # opt: True optimize, False not optimize

   # print(src)    

   dst = src.copy()

   step = 0

   for i in range(len(dst)-1, 0, -1):

       sorted = not opt

       for j in range(i):

           step += 1

           if (order and dst[j] > dst[j+1]) or (not order and dst[j] < dst[j+1]):

               temp = dst[j]

               dst[j] = dst[j+1]

               dst[j+1] = temp

               sorted = True

       if not sorted:

           print('no need to sort')

           break

   print('step', step)

   return dst

1.2选择排序

1.2.1算法描述(摘自网络)

原始算法:

1.        在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

2.        从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

3.        重复第二步,直到所有元素均排序完毕。

算法优化:

1.        步骤1同时找出最大和最小值,找出的最大和最小值分别存放在各自的序列中,排序完成后输出两个序列的组合。

2.        如果最大值和最小值是同一个值,说明剩下的所有数据都是相同的,可直接退出排序。

1.2.2算法实现

原始算法:

@time_count

def select_origin(src: list, order=1):

   # src: list

   # order: 0 descend, 1 ascend

   # print(src)

   dst_temp = src.copy()

   dst = []

   while len(dst_temp):

       max_id = 0

       for i in range(1, len(dst_temp)):

           if dst_temp[i] > dst_temp[max_id]:

               max_id = i

       if order == 0:

           dst.append(dst_temp[max_id])

       else:

           dst.insert(0, dst_temp[max_id])

       dst_temp.pop(max_id)

   return dst

优化算法:

@time_count

def select_opt(src: list, order=1):

   # src: list

   # order: 0 descend, 1 ascend

   # print(src)

   dst_temp = src.copy()

   dst_min = []

   dst_max = []

   while len(dst_temp):

       max_id = 0

       min_id = 0

       for i in range(1, len(dst_temp)):

           if dst_temp[i] > dst_temp[max_id]:

               max_id = i

           if dst_temp[i] < dst_temp[min_id]:

               min_id = i

       if max_id == min_id:

           if order == 0:

               dst_max += dst_temp

           else:

               dst_max = dst_temp + dst_max

           break

       if order == 0:

           dst_max.append(dst_temp[max_id])

           dst_min.insert(0,dst_temp[min_id])

       else:

           dst_max.insert(0, dst_temp[max_id])

           dst_min.append(dst_temp[min_id])

       if max_id > min_id:

           dst_temp.pop(max_id)

           dst_temp.pop(min_id)

       elif max_id < min_id:

           dst_temp.pop(min_id)

           dst_temp.pop(max_id)

       else:

           dst_temp.pop(min_id)

   if order == 0:

       return dst_max + dst_min

   else:

       return dst_min + dst_max

1.3插入排序

1.3.1算法描述(摘自网络)

原始算法:

1.        把待排序的数组分成已排序和未排序两部分,初始的时候把第一个元素认为是已排好序的。

2.        从第二个元素开始,在已排好序的子数组中寻找到该元素合适的位置并插入该位置。

3.        重复上述过程直到最后一个元素被插入有序子数组中。

算法优化1

在步骤2中,计算待插入的值靠近序列的开头还是末尾,靠近哪一侧,就从该侧寻找位置插入,减少循环查找的次数。

算法优化2

在步骤2中,计算待插入的值靠近序列的开头、中间还是末尾,,靠近哪一侧,就从该侧寻找位置插入,进一步减少循环查找的次数。

1.3.2算法实现

原始算法:

@time_count

def insert_origin(src: list, order=1):

   # src: list

   # order: 0 descend, 1 ascend

   # print(src)

   dst = src[0:1]

   for i in range(1, len(src)):

       inserted = False

       for j in range(len(dst)):

           if (order and src[i] < dst[j]) or (not order and src[i] > dst[j]):

               dst.insert(j, src[i])

               inserted = True

               break

       if not inserted:

           dst.append(src[i])

   return dst

优化算法1

@time_count

def insert_opt1(src: list, order=1):

   # src: list

   # order: 0 descend, 1 ascend

   # print(src)

   dst = src[0:1]

   for i in range(1, len(src)):

       inserted = False

       if abs(src[i]-dst[0]) <= abs(src[i]-dst[-1]):

           for j in range(len(dst)):

               if (order and src[i] < dst[j]) or (not order and src[i] > dst[j]):

                   dst.insert(j, src[i])

                   inserted = True

                   break

           if not inserted:

               dst.append(src[i])

       else:

           for j in range(len(dst)-1,-1,-1):

               if (order and src[i] > dst[j]) or (not order and src[i] < dst[j]):

                   dst.insert(j+1, src[i])

                   inserted = True

                   break

           if not inserted:

               dst.insert(0,src[i])

   return dst

优化算法2

@time_count

def insert_opt2(src: list, order=1):

   # src: list

   # order: 0 descend, 1 ascend

   # print(src)

   dst = src[0:1]

   def insert_left(src_vlaue, from_mid=False):

       inserted = False

       start = 0 if not from_mid else int(len(dst)/2)

       for j in range(start, len(dst)):

           if (order and src_vlaue < dst[j]) or (not order and src_vlaue > dst[j]):

               dst.insert(j, src_vlaue)

               inserted = True

               break

       if not inserted:

           dst.append(src_vlaue)

   def insert_right(src_vlaue, from_mid=False):

       inserted = False

       start = len(dst)-1 if not from_mid else int(len(dst)/2)

       for j in range(start,-1,-1):

           if (order and src_vlaue > dst[j]) or (not order and src_vlaue < dst[j]):

               dst.insert(j+1, src_vlaue)

               inserted = True

               break

       if not inserted:

           dst.insert(0, src_vlaue)

   for i in range(1, len(src)):            

       l = abs(src[i]-dst[0])

       r = abs(src[i]-dst[-1])      

       m = src[i]-dst[int(len(dst)/2)]            

       if l <= abs(m) and l <= r:

           insert_left(src[i])

       elif r <= abs(m) and r <= l:

           insert_right(src[i])

       else:

           if m >= 0:

               insert_left(src[i], True)

           else:

               insert_right(src[i], True)

   return dst

2.算法比较

2.1算法有效性

为证明算法能有效进行排序,使用的数组为:

data0 = [0, 7, 7, -2, 1, -7, 7, 7, 6, -2, 0, 10, 9, 9, 4, 2, 6, 5, 1, 8, 3, 1, 10, 7, -1]

分别使用各个算法进行升序和降序。

1)冒泡排序:

>>> bubble(data0)

no need to sort

step 297

cost 1

[-7, -2, -2, -1, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 9, 9, 10, 10]

>>> bubble(data0, 0)

no need to sort

step 297

cost 1

[10, 10, 9, 9, 8, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1, 1, 1, 0, 0, -1, -2, -2, -7]

>>> bubble(data0,opt=False)

step 300

cost 2

[-7, -2, -2, -1, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 9, 9, 10, 10]

>>> bubble(data0, 0, opt=False)

step 300

cost 2

[10, 10, 9, 9, 8, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1, 1, 1, 0, 0, -1, -2, -2, -7]

2)选择排序

>>> select_opt(data0)

cost 0

[-7, -2, -2, -1, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 9, 9, 10, 10]

>>> select_opt(data0,0)

cost 0

[10, 10, 9, 9, 8, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1, 1, 1, 0, 0, -1, -2, -2, -7]

>>> select_origin(data0)

cost 0

[-7, -2, -2, -1, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 9, 9, 10, 10]

>>> select_origin(data0,0)

cost 0

[10, 10, 9, 9, 8, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1, 1, 1, 0, 0, -1, -2, -2, -7]

>>>

3)插入排序

>>> insert_opt1(data0)

cost 0

[-7, -2, -2, -1, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 9, 9, 10, 10]

>>> insert_opt1(data0, 0)

cost 0

[10, 10, 9, 9, 8, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1, 1, 1, 0, 0, -1, -2, -2, -7]

>>> insert_origin(data0)

cost 0

[-7, -2, -2, -1, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 9, 9, 10, 10]

>>> insert_origin(data0, 0)

cost 0

[10, 10, 9, 9, 8, 7, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1, 1, 1, 0, 0, -1, -2, -2, -7]

>>> insert_opt2(data0)

cost 0

[-7, -2, -2, -1, 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 9, 9, 10, 10]

>>> insert_opt2(data0, 0)

cost 0

[10, 10, 9, 9, 8, 7, 7, 7, 7, 6, 6, 7, 5, 1, 3, 1, 2, 4, 1, 0, 0, -1, -2, -2, -7]

>>>

2.2算法比较

使用三组数据比较各个算法的计算时长。

数组1长度为1万,其数值为0~100的随机数。

数组2长度为10万,其数值为0~100的随机数。

数组3长度为1万,其数值前50000~100的随机数,后5000为升序的值。

import random

import datetime

 

data1 = [random.randint(-100,100) for i in range(10000)]

data2 = [random.randint(-100,100) for i in range(100000)]

data3 = [random.randint(-100,100) for i in range(5000)] + [i for i in range(5000)]

使用datetime计算算法执行的时长。

def time_count(func):

   def wrapper(*args, **kwargs):

       start = datetime.datetime.now()

       result = func(*args, **kwargs)

       print('cost', int((datetime.datetime.now() - start).total_seconds()*1000))

       return result

   return wrapper

每个算法,对同一组数据,计算5次升序,取平均值,单位是ms,结果如下:

算法

冒泡排序

选择排序

插入排序

原始

优化

提升

原始

优化

提升

原始

优化1

优化2

提升1

提升2

数据11w

降序

11998

11976

0.19%

3498

3146

10.08%

2323

1178

281

49.28%

87.89%

升序

11760

11765

-0.05%

3517

3143

10.63%

2278

1169

527

48.66%

76.84%

数据210w

降序

1263493

1263487

0.00%

351886

316437

10.07%

230149

119339

28089

48.15%

87.80%

升序

1251652

1251670

0.00%

354900

315789

11.02%

234406

118856

53412

49.29%

77.21%

数据31w

降序

15113

15112

0.01%

3671

3209

12.58%

593

324

91

45.38%

84.65%

升序

8693

6665

23.32%

3688

3203

13.14%

3917

308

145

92.15%

96.30%

备注:提升=(原始-优化)/原始*100%

1.png

1 数据1降序排序各算法耗时

2.png

2 数据1升序排序各算法耗时

结论:

1、原始算法排序效率:插入排序>选择排序>冒泡排序。

2、冒泡排序,对于乱序的数据1和数据2,优化算法与原始算法用时接近,无优化效果,对特殊顺序的数组3,升序的优化算法有明显的提升,降序也无优化效果。

3、选择排序和插入排序的优化算法对各组数据均能生效。

4、选择排序的优化算法对各组数据的均提升约10%

5、插入排序的优化效果相比于其他两个算法的优化效果提升最大。

6、插入排序的效率:优化算法2>优化算法1>原始算法。

说明:以上实验并未严格控制测试环境,数据仅供参考。

 

目录
相关文章
|
4天前
|
机器学习/深度学习 搜索推荐 TensorFlow
使用Python实现深度学习模型:个性化推荐与广告优化
【7月更文挑战第22天】 使用Python实现深度学习模型:个性化推荐与广告优化
133 70
|
4天前
|
存储 算法 搜索推荐
深度剖析 Python 算法:时间复杂度与空间复杂度的爱恨情仇,你站哪边?
【7月更文挑战第23天】在Python算法设计中,时间复杂度与空间复杂度如影随形,反映算法效率与资源消耗。时间复杂度揭示算法随输入规模增长的计算趋势,空间复杂度关注额外存储需求。找最大值示例中,两种实现均具O(n)时间与O(1)空间复杂度,但在排序等复杂场景下,如冒泡排序与快速排序,或哈希表与二叉树查找,权衡变得关键。实时系统偏好低时间复杂度算法,存储受限环境则需关注空间效率。最佳选择依应用场景而定,掌握二者平衡,方能编写高效代码。
|
3天前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
【7月更文挑战第23天】在Python编程中,掌握算法复杂度—时间与空间消耗,是提升程序效能的关键。算法如冒泡排序($O(n^2)$时间/$O(1)$空间),或使用Python内置函数找最大值($O(n)$时间),需精确诊断与优化。数据结构如哈希表可将查找从$O(n)$降至$O(1)$。运用`timeit`模块评估性能,深入理解数据结构和算法,使Python代码更高效。持续实践与学习,精通复杂度管理。
22 9
|
4天前
|
机器学习/深度学习 缓存 并行计算
操作系统调度算法的演变与优化
【7月更文挑战第23天】本文深入探讨了操作系统中调度算法的发展历程,从简单的先来先服务到复杂的多级反馈队列调度算法。通过分析不同算法的特点和性能表现,文章揭示了调度算法在提升系统响应速度、公平性以及资源利用率方面的重要性。同时,文章也讨论了现代操作系统如何通过优化调度算法来适应多核处理器架构,以及未来可能的研究方向。
|
4天前
|
存储 缓存 算法
时间&空间复杂度,Python 算法的双重考验!如何优雅地平衡两者,打造极致性能?
【7月更文挑战第23天】在Python算法设计中,时间与空间复杂度是关键考量,需精妙平衡以优化程序性能。时间复杂度反映算法随输入规模增长的执行时间趋势,空间复杂度关注额外存储需求。线性搜索O(n)时间,O(1)空间;二分搜索O(log n)时间,O(1)空间,提升效率;动态规划如斐波那契数列O(n)时间与空间,利用存储减小计算。实际应用需按场景需求调整,如实时数据偏重时间,资源受限环境优先考虑空间。平衡两者,理解算法本质,结合实践,创造高性能程序。
21 7
|
4天前
|
算法 Python
震惊!Python 算法设计背后,时间复杂度与空间复杂度的惊天秘密大起底!
【7月更文挑战第23天】在Python算法设计中,时间与空间复杂度是幕后操控程序效率的双雄。时间复杂度反映算法执行时间随输入规模增长的速度,空间复杂度则计量算法运行时额外内存的使用。如顺序查找的时间复杂度O(n)与固定空间O(1),对比冒泡排序的O(n^2)时间和快速排序的O(n log n)时间优势,后者虽递归消耗空间,但在多数情况下提供更佳性能。根据需求,可权衡选择,如利用哈希表在充足内存下实现O(1)查找,或在空间受限时,偏好空间效率更高的算法,实现Python代码的高性能与优雅。
20 6
|
2天前
|
存储 算法 搜索推荐
揭秘!Python算法设计的隐形杀手:忽视时间复杂度与空间复杂度的后果有多严重?
【7月更文挑战第24天】在 Python 编程中, 算法设计是性能与效率的基石。忽视时间复杂度 (如使用 O(2^n) 的斐波那契数列递归算法而非 O(n) 的动态规划版本) 和空间复杂度 (如在插入排序中每次迭代都复制整个已排序数组, 导致 O(n^2) 的空间复杂度) 可能严重拖累程序。性能优化至关重要, 合理的算法设计保证程序高效稳定, 是攀登技术高峰的坚实阶梯。
|
1天前
|
算法 Python
|
2天前
|
算法 搜索推荐 数据处理
震惊!Python算法设计背后,时间复杂度与空间复杂度的惊天秘密大起底!
【7月更文挑战第24天】在编程世界里, Python以简洁强大备受欢迎, 但算法设计与复杂度分析对程序性能至关重要。算法是程序的灵魂, 其效率直接影响数据处理能力。时间复杂度衡量算法执行速度, 如冒泡排序O(n²)与快速排序O(n log n)的显著差异; 空间复杂度关注内存占用, 递归算法需警惕栈溢出风险。优秀算法需平衡时间和空间效率, 深入理解问题本质, 迭代优化实现高效可靠。
9 2
|
2天前
|
算法 Python
算法小白秒变高手?一文读懂Python时间复杂度与空间复杂度,效率翻倍不是梦!
【7月更文挑战第24天】在编程中,算法效率由时间复杂度(执行速度)与空间复杂度(内存消耗)决定。时间复杂度如O(n), O(n^2), O(log n),反映算法随输入增长的耗时变化;空间复杂度则衡量算法所需额外内存。案例对比线性搜索(O(n))与二分搜索(O(log n)),后者利用有序列表显著提高效率。斐波那契数列计算示例中,递归(O(n))虽简洁,但迭代(O(1))更节省空间。掌握这些,让代码性能飞跃,从小白到高手不再是梦想。
8 1