这篇博客,主要是来记录一下作业调度问题这一算法。完整代码会放在本文最后。
作业调度问题总的来说还是贪心算法,给定某一贪心策略,处理机处理的时间最少自然最好。本次算法中,我所选用的贪心策略是处理时间高的作业优先。
1.问题的已知:
已知m台机器,n个作业以及各作业的处理时间ti(i=1,2,…,n)。
2.所求目标:
每台处理机处理的作业的序列。
3.算法步骤
输入:1.处理机个数m。2.作业个数n。3.依次按序号输入作业的处理时间。
输出:一个列表里面嵌套列表的数据结构,嵌套的列表分别为这m台处理机对应的处理作业的序列。
步骤1:初始化一个列表ISHTAR,并用for循环跟据处理机的个数往ISHTAR里面添加空列表(有几个处理机就添加几个空列表),ISHTAR列表存的就是各个处理机处理的作业的序列。
步骤2:初始化一个变量rin,用python内置函数sorted()将字典dict1按照作业运行时间(值)的大小从大到小排序,最后将排序完的数据赋值给rin。
步骤3:由于是按照最长处理时间优先的策略,所以排序完的字典rin在机器刚开始工作时可以直接按照机器的个数m将前m个作业放进去处理。即用for循环将排序后的前m个作业的各自的处理时间赋值给dict2里m个机器键值对里面的值里面。
步骤4:使用for循环用来循环遍历字典rin,将第m+1个作业放入当前处理时间最少的处理机中。(这个处理时间最少的处理机是先用内置函数min()找出当前处理时间最小的值minnum,然后再用for循环遍历dict2的项,当值等于minnum时,就返回该值对应的处理机序号。)之后再进行dict2里面对应序号的处理机对应的值的加操作(当前处理时间+分配的作业对应的处理时间)。
步骤5:输出列表ISHTAR,里面的每个嵌套的列表就是该m个处理机对应的处理作业的序列。
4.具体实现:
1.m和n为用户输入,分别用于指定处理机和作业的个数。初始化两个字典dict1和dict2,用for循环循环输入两个字典中每个键值对的值,dict1的值都默认赋值为0(赋值为0是表示每台处理机的初始处理作业的时间都为0),dict2的值为用户自己输入。字典的键就跟据两个字典的长度从1开始赋值。dict1的键表示处理机的编号,dict2的键表示作业的序号。
m = int(input('请输入处理机的台数:'))
n = int(input('请输入作业的个数:'))
dict1 = {}
dict2 = {}
for i in range(1, m + 1):
dict2[i] = 0
for j in range(1, n + 1):
dict1[j] = int(input('请输入'+str(j)+'号作业的处理时间:'))
2.初始化一个列表ISHTAR,然后跟据dict2的长度(处理机个数)用for循环给ISHTAR嵌套相应数量的列表,ISHTAR的作用就是为了后边结果的输出,ISHTAR里面嵌套的每个子列表就代表着每台处理机的处理作业的序列。
注意这里面list1=[],这句代码一定要放在for循环里面,如果放外面的话ISHTAR里面的所有子列表都会共用一个内存空间,即一个子列表改变,其他的子列表也会相应的改变。
ISHTAR = []
for i in range(0, len(dict2)):
list1 = []
ISHTAR.append(list1)
3.用sorted()函数将作业按照处理时间从大到小排序。(按照值将字典dict1里面的项按照从大到小排序)
rin = sorted(dict1.items(), key=lambda x: x[1], reverse=True)
将排序完的数据结构赋值给自定义变量rin。注意:此时rin的数据结构并不是字典,而是列表,且里面的数据,也是一个个元组。
4.因为rin为把所有作业按照处理时间从大到小排序的结果,所以在第一次放置作业到处理机上时,直接按照处理机的个数将相同数量的作业放入处理机即可。
所以这一步做的就是把rin中前m(m为处理机个数)个作业对应的时间赋值给字典dict2(处理机)的每一项的值。
同时,将rin前m项对应的作业序号添加到列表ISHTAR中的各个子列表中(表示每台处理机处理的作业序列)。
for i in range(1, len(dict2) + 1):
dict2[i] = rin[i - 1][1]
ISHTAR[i - 1].append(str(rin[i - 1][0]))
5.用循环将剩下的作业依次判断处理,将作业序号添加到对应的处理机上。
for i in range(len(dict2), len(dict1)):
listmin=[]
for j in range(1, m+1):
listmin.append(dict2[j])
minnum = min(listmin)
for key, value in dict2.items():
if value == minnum:
dict2[key] = dict2[key] + rin[i][1]
ISHTAR[key - 1].append(str(rin[i][0]))
break
上述代码中,listmin为我初始化的一个列表,它的作用是和min()函数搭配,找出每分配作业后处理作业总时间最小的处理机,这样才能保证每次的将作业分配给处理机这一过程最优。minnum即为找到的处理总时间最小的处理机的处理时间,之后再用循环遍历字典dict2,跟据最小值找到对应的处理机序号(如果多个处理机有相同的最小处理时间,则只找第一个处理机),将作业的处理时间加到该处理机的总时间上,再将作业序号添加到对应的处理机处理作业序列中。
最后输出结果。
例:
最后输出的这个就是结果,表示:
处理机1的处理的作业序号有:6
处理机2的处理的作业序号有:8
处理机3的处理的作业序号有:5,3,4
处理机4的处理的作业序号有:7,1,2
这个算法其实并不复杂,虽然并不简洁,但我认为我写的这个应该是比较好理解的。如果代码有问题,还是希望能够指出来。
完整代码如下:
m = int(input('请输入处理机的台数:'))
n = int(input('请输入作业的个数:'))
dict1 = {}
dict2 = {}
for i in range(1, m + 1):
dict2[i] = 0
for j in range(1, n + 1):
dict1[j] = int(input('请输入'+str(j)+'号作业的处理时间:'))
ISHTAR = []
for i in range(0, len(dict2)):
list1 = []
ISHTAR.append(list1)
rin = sorted(dict1.items(), key=lambda x: x[1], reverse=True)
for i in range(1, len(dict2) + 1):
dict2[i] = rin[i - 1][1]
ISHTAR[i - 1].append(str(rin[i - 1][0]))
for i in range(len(dict2), len(dict1)):
listmin=[]
for j in range(1, m+1):
listmin.append(dict2[j])
minnum = min(listmin)
for key, value in dict2.items():
if value == minnum:
dict2[key] = dict2[key] + rin[i][1]
ISHTAR[key - 1].append(str(rin[i][0]))
break
print(ISHTAR)