《编程珠玑》——第一章习题

来源:互联网 发布:科比安东尼西决数据 编辑:程序博客网 时间:2024/06/05 16:11

1.6习题

3. 程序如下

#!/usr/bin/env python# encoding: utf-8"""@version: ??@author: Dawei Gao@contact: david_gao@buaa.edu.cn@software: PyCharm@file: dataForSorting.py@time: 2017/10/17 下午9:04"""import timefrom random import *def dataGen(n):    """    产生包含 n个 小于10 000 000的 不重复 的 整数 的文件夹    :param n:    :return:    """    f = open('dataForSorting.txt', 'w')    a = [0] * 10000000    count = 0    while count < n:        m = randint(0,10000000-1)        if a[m] == 0:            f.write(str(m) + "\n")            count += 1            a[m] = 1    f.close()def bitSort():    a = [0] * 10000000    for line in open('dataForSorting.txt','r'):        a[int(line)] = 1    # output    res = open('res_dataForSorting_bitsort.txt','w')    for i in range(len(a)):        if a[i]==1:            res.write(str(i)+"\n")    res.close()def sysSort():    # read    a = []    for line in open('dataForSorting.txt', 'r'):        a.append(int(line))    a.sort()    # output    res = open('res_dataForSorting_syssort.txt', 'w')    for m in a:        res.write(str(m) + "\n")    res.close()if __name__ == '__main__':    # 产生数据    #dataGen(1000000)    # 位图排序    stime = time.clock()    bitSort()    etime = time.clock()    print("bitSort: "+str((etime-stime)) + "s")    # 快排    stime = time.clock()    sysSort()    etime = time.clock()    print("sysSort: " + str((etime - stime)) + "s")

注意这里位图排序方法并未采用真正意识上的“位”,仍是采用数组完成的。因为不清楚python如何直接在内存里写二进制数0/1(即0/1只占一个bit),现在还不清楚如何实现。

输出结果为

bitSort: 2.155071ssysSort: 1.945613sProcess finished with exit code 0

根据输出结果,在内存足够的情况下(且都采用32位整数的存储方式时),快排的效率是要比位图排序更高的

4. 程序如下

def dataGen(n, k):    """    产生包含 k个 小于 n 的 不重复 的 整数 的文件夹    :param n:    :param k:    :return:    """    f = open('dataForSorting.txt', 'w')    a = [0] * k    count = 0    while count < k:        m = randint(0,n-1)        if a[m] == 0:            f.write(str(m) + "\n")            count += 1            a[m] = 1    f.close()

5.

如果1M的空间是严格的化,即按照位图排序方法也无法创建容纳10 000 000个整数的数组。

方法一:可以先将1M能够容纳的数字统计下来,即

1M=10241024byte=1,048,576byte

所以实际上只有约8 000 000个位,存储的目标是0-(10 000 000-1)长度的数组。可以先统计文件中小于8 000 000的整数,扫描文件一遍,输出;之后再扫面磁盘文件一次,统计大于8 000 000的整数并输出。

总计需要扫面磁盘文件两次,输出两次,不需要中间工作文件。

Created with Raphaël 2.1.0input fileinput filesortsortoutput fileoutput file两次两次

6.

如果每个数字最多出现10次,最基础的想法是每个数字先存储出现与否,如果出现,则后面10bit用来记录出现了多少次;若未出现,则不需要存储。如数字0出现2次,数字1未出现,数字2出现9次,记录如下

0 0100000000 0 1 0000000010

分析所需要的空间情况:假设一共有k个数字,数字取值范围为[0,n),假设其中m(0<mmin{k,n})个数字出现过至少1次,则需要的空间大小为
(nm)1bit+m11bit=(n+10m)bit

所以最少需要(n+10min{k,n})bit,带入之前的n=k=10 000 000,则需要110 000 000个位空间,所需要的空间大小变成了之前的11倍。

对上述算法进行改进:其实没必要采用10个位来记录数字出现的次数,只需要碰到第一个1的时候就可以获得该数字出现次数,随后就对下一个数字进行记录,即对上面所举的例子来说,记录变为:

0 01 0 1 000000001

该种记录可以节省较多的空间,所需要的空间变为(n+k)bit,在给定的数据上空间变为20 000 000bit,相对需要的空间变小了很多。

8.

排序:
可以按照开头数字做分组排序,如先进行开头数字为0的排序,从而减小每次排序所需的空间大小,但是同时会增大排序次数和读写文件的次数。

存储(应该没指定1M空间吧):
可以存储成树的结构,树一共由七层组成,共有10棵树,其根节点分别是0,1,2,3,4,5,6…9,实际上根据电话号码的规则(如开头数字只会是8和6)减少树的数量,这里只考虑最坏的情况。

那么第一层共有10个节点,第二层有10*10个节点…第10层有1010个节点,节点的总数为1011109个几点,数量级在10 000 000 000,如果采用二进制位存储(即用0表示不存在,1表示存在),大约为1GB的空间。

在查找时只需要从上到下7层即可,查找时间是常数时间。

原创粉丝点击