JFLong  
实验目的
  • 掌握高级语言中的排序函数的使用
  • 加强对于二分搜索和插入排序的理解
  • 将查找和排序联系起来
  • 理解排序从一维(数的大小)到多维(属性组合)的延伸
  • 借助可视化工具,加深对于排序过程的印象
  • 了解课外和实际应用领域的排序算法

 

实验原理

bisect 模块的使用

利用二分法查找排序的模块,原理是插入排序

因为二分搜索具有左右边界的条件,对应的函数也有left right修饰

bisect.bisect(a, x, lo=0, hi=None)
bisect.bisect_left(a, x, lo=0, hi=None)
bisect.bisect_right(a, x, lo=0, hi=None)
bisect.insort(a, x, lo=0, hi=None)  # 执行插入排序操作
bisect.insort_left(a, x, lo=0, hi=None)
bisect.insort_right(a, x, lo=0, hi=None)


# 别名 默认情况 bisect从右边插入
bisect(a, x, lo=0, hi=None) = bisect_right(a, x, lo=0, hi=None)
insort(a, x, lo=0, hi=None) = insort_right(a, x, lo=0, hi=None)

 

 

实验内容

1.多属性排序

尽管排序在计算机中根本依据是数的大小

还是需要关注具有组合性质的数据的排序场景

I.同方向性比较

假设:某年高考成绩位次计算中,对相同分数考生依次比较其语文、数学、英语成绩,直到分出先后顺序。输出考生位次表。

sli = [("小明",120,140,120),("小刚",110,130,140),("小丽",130,120,130)]
ranking = []
def grade_sort(sli):


    sli.sort(key=lambda x:(-x[1],-x[2],-x[3]))
    for rank,score in enumerate(sli):
        # 严格意义上讲是学号 这里用名字短暂标识一下
        rank.append((rank,score[0]))
        print("名次:",rank+1,"------",score[0])


grade_sort(sli)

 

II.异方向性比较

假设:在旅游风景区选择上,距离与评分、门票价格多因子进行排序

不考虑综合加权指数的计算,在距离相同时为用户呈现评分从高到低、价格从低到高的景区列表。

 

/\

/ \

/ \

/ \

 

 

# 形式如下:关注排序因子key函数的灵活性
li = [(),(),(),(),]
li.sort(key=lambda(x[1],-x[2]))

 

2.学生成绩分级

ABCDEF 对应40 50 60 70 80 90

if -else switch 具有明显的限制 显然不是好的方法

仔细分析一下,类似的场景其实都包含了两个关键信息。一个是分界点,另外一个是等级。

比如学生成绩分级的分界点是[60, 70, 80, 90, 100],等级是'FEDCBA'

将成绩转换为分级的逻辑其实就是两步:

在分界点(breakpoints)中找到学生成绩对应的位置(index)返回等级(grades)对应位置(index)的结果

# codeing:utf-8


from bisect import bisect


def grade(score, breakpoints=[60, 70, 80, 90, 100], grades='FEDCBA'):
    i = bisect(breakpoints, score)
    return grades[i]


if __name__ == '__main__':
    scores = [59, 60, 65, 70, 78, 80, 89, 90, 95, 100]
    result = [grade(i) for i in scores]
    print(result)
    # ['F', 'E', 'E', 'D', 'D', 'C', 'C', 'B', 'B', 'A']

 

同样地,根据商城会员的积分来进行分级。

breakpoints = [1000, 2000, 3000]
grades = ['普通会员', '中级会员', '高级会员', 'VIP']
scores = [499, 1023, 2020, 3000, 4999]
print([grade(i, breakpoints=breakpoints, grades=grades) for i in scores])


# ['普通会员', '中级会员', '高级会员', 'VIP', 'VIP']

 

grades的元素应该比breakpoints多一个(可以想想原因)。

bisect模块提供了bisect_left和bisect_right两个方法,区别在于当元素相等时,返回的index是在breakpoint的左边还是右边。

例子中用的bisect.bisect就是bisect_right。

更详细的说明,请参看Python官方文档bisect — Array bisection algorithm

 

孤立地来看bisect,可能会觉得仅仅是二分查找而已。然而在工作中,根据场景使用bisect,往往会给你带来惊喜。这里其实还是一个应用算法的能力。上面学生成绩分级的例子就是Python官方文档提供的。

 

3.煎饼排序Pancake sorting

可以先找最大的饼也可以先找最小的饼

并执行一个区间翻转的操作来更新数组

def pancakeSort_max(arr):


    # 每一步都是在原数组水平上操作
    n = len(arr)
    while n :
        k = arr.index(max(arr[:n]))
        # step1 翻转区间
        arr = arr[:k+1][::-1]+arr[k+1:]
        # step2 翻转整体(未排序部分)
        arr = arr[:n][::-1]+arr[n:]
        n -= 1
    return arr


def pancakeSort_min(arr):
    i = 0
    while i < len(arr):
        k = arr.index(min(arr[i:]))
        #翻转区间合并已经排序好的部分
        arr = arr[:i]+ arr[i:k+1][::-1] + arr[k+1:]


        i+=1


    return arr


import random 
testArr = [random.randint(0,50) for _ in range(10)]
print("__________Before Sorted__________")
print(testArr)
print("__________After Sorted__________")
print(pancakeSort_max(testArr))
print(pancakeSort_min(testArr))

 

 

4.排序动画演示

下载手机App "算法动画详解"

在线平台https://visualgo.net/zh/sorting

 

 

实验总结

练习题:Leetcode 34

在排序数组中查找元素第一次和最后一次出现的位置
给定一个按照升序排列的整数数组nums,和一个目标值 target。
找出给定目标值在数组中的开始位置和结束位置。

链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array

真实的项目中,往往会采取综合建模的方式确立排序的权重因子

这种方式在各大电商平台应用广泛,可以看做是一种加权函数的模式

 

实验参考

https://docs.python.org/3/library/bisect.html

https://zhuanlan.zhihu.com/p/71895688

posted on 2025-04-24 17:35  鱼孜千  阅读(17)  评论(0)    收藏  举报