简介

算法学习入门,从排序法开始总是合理的,既基础又重要。我们编写的程序,大部分时间还是跟各种数据打交道,当数据是有序的情况下,更容易处理。

准备工作

为了方便研究各种排序算法的效率,我们需要先编写一个随机数产生函数,参数是随机数个数,上下限和数组本身。在编写的过程中,发现随机数的产生,也是大有学问,出乎我意料。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2019-03-22 10:38:40
# @Author  : Promise (promise@mail.ustc.edu.cn)
# @Link    : ${link}
# @Version : $Id$

import random

# 如果一开始没定义数组大小,使用注释掉的append,产生100个随机数会特别慢,因此,最好预先定义好数组的长度!
def CreateRandomNumer(n, array, minimun, maximum):
    if n > (maximum - minimun + 1):
        print('随机数产生失败,没法产生不重复的随机数组')
        return False
    for i in range(n):
        flag = True  # 用于处理随机数重复的问题
        while flag:
            flag = False
            # array.append(random.randint(minimun, maximum))
            array[i] = random.randint(minimun, maximum)
            for j in range(i):
                if j == array[i]:
                    flag = True
                    break
    return True


n, a, b = eval(input('请输入要产生的随机数个数, 最小值,最大值:'))
myArray = [0]*n
isCreated = CreateRandomNumer(n, myArray, a, b)
if isCreated:
    print(myArray)

上面的程序,实现的功能是产生完全不重复的随机数。这个程序影响性能的有两个点:

  1. 数组是否预先确定好长度
  2. 确定数组是否重复的for循环

一开始使用

array = []
array.append(random.randint(minimun, maximum))

即使是产生100个1到1000之间的数,速度都快得感人(反话谢谢……)
于是,才有了上面的修改,预先确定数组大小,这样一改,数据的产生是瞬间的。

下一步,就是研究for循环的问题了。很显然,当产生的随机数很长的时候,浪费在比较上的时间就会很长,下面的思路,好像是在编程之美提到过,用空间换时间。预先定义一个与待产生数组同长度的布尔数组,每个数字产生了,就标记,之后每产生一个数,就检查该位置是不是已经有数字了,是不是就省去了遍历啊!

实现代码如下,果然速度有了极大的提升

def CreateRandomNumer(n, array, minimun, maximum):
    if n > (maximum - minimun + 1):
        print('随机数产生失败,没法产生不重复的随机数组')
        return False
    # 此处增加一个布尔数组
    posisionCheck = [False]*(maximum - minimun + 1)
    for i in range(n):
        flag = True  # 用于处理随机数重复的问题, true 表示接下来要继续产生随机数
        while flag:
            flag = False
            # array.append(random.randint(minimun, maximum))
            array[i] = random.randint(minimun, maximum)
            # 下面的代码是用循环判断不重复,如果变成了用数组来标记呢?
            # for j in range(i):
            #     if j == array[i]:
            #         flag = True
            #         break

            # 产生的的随机数,减去minimum,就映射到了长度为[0, n-1]的区间
            if not posisionCheck[array[i] - minimun]:
                posisionCheck[array[i] - minimun] = True
            else:
                flag = True
    # print(posisionCheck)
    return True

更改了两个地方,一个是增加布尔数组,

posisionCheck = [False]*(maximum - minimun + 1)

这个数组的长度,是我们要产生随机数的区间,不是要产生随机数的数量,思考下原因~

第二个变化,是关键变动

if not posisionCheck[array[i] - minimun]:
                posisionCheck[array[i] - minimun] = True
            else:
                flag = True

当一个数,第一次出现,肯定能进if语句,把这个数对应的布尔数组的位置,值改为 True,跳出while循环,然后继续产生下一个数;如果出现了重复,flag依然为True,重新产生一个随机数。

敲黑板:这里仅仅是一个查找,操作时间可以认为是常数,而非原始方案的循环。循环是大多数程序运行缓慢的重要原因,所以,大家慎重使用~