开端
作为一个非科班出身的程序猿,算法始终是个软肋。之前倒也抽时间断断续续看了点算法的书,但基本过目即忘,可能每个算法都实际实现以下,编写下练习代码才能更好的学习。于是在github上创建了一个仓库,用来一个个实现算法。置于语言的选择,都说语言不过是工具,算法才是核心,那么就多用几种语言来实现吧。其实我会的语言也不多,c/c++可能还好,再就是个初学者阶段的Python,在实现算法的过程中,也能练习下这些语言的使用,一箭双雕呀,哈哈,有点小激动呢。
github上的仓库地址如下:
git@github.com:haoranzeus/algorithms_study.git
既然是在世界流行的github上创建仓库,上面我也尽量使用英文,虽然我这英文水平有点惨不忍睹。
好,让我们开始吧。
随机数生成
算法书上面开始介绍的算法必然是排序,要排序就要有数可排,那么就先写一个生成随机数的程序吧。
需求如下:
1. 生成随机数写入文件。
2. 制定生成整数还是浮点数。
3. 指定生成的数的大小范围。
4. 指定保存到文件的数之间的分隔符。
Python实现
这里我创建一个mypackage的路径,用于存放以后可能有复用价值的包,关于这种向文件里写数据的功能,就放到这里的myio.py里面。然后random_number_generator/random_number_generator.py用于实现生成随机数。
生成随机数的代码如下:
from random import uniform, randint
def randNumGenerator(numbType, numMin, numMax, numb):
"""
numbType: an "int" for initerator, and a "float" for float number.
numMin: The nimimum for the number generatored.
numMax: the maximum for the number generatored.
numb: the number of numbers generatored.
"""
if numbType == "int":
generator = randint
elif numbType == "float":
generator = uniform
else:
raise AttributeError("invalid value for type: %s" % numbType)
numMin = int(numMin)
numMax = int(numMax)
numb = int(numb)
while numb > 0:
yield generator(numMin, numMax);
numb -= 1
这段代码采用标准标准包random中的uniform和randint分别实现生成随机浮点数和随机整数。
参数分别表示要生成的数的类型、最小值、最大值以及要生成的 数据个数。
该函数返回生成器,每次生成一个随机数,直至生成了指定的个数。
然后是该函数的单元测试:
import unittest
class TestRandNumGenerator(unittest.TestCase):
def test_generatorInit(self):
i = 0
for n in randNumGenerator("int", 0, 10000, 20):
i += 1
self.assertTrue(n >= 0)
self.assertTrue(n <= 10000)
self.assertTrue(isinstance(n, int))
self.assertEqual(i, 20)
def test_generatorFloat(self):
i = 0
for n in randNumGenerator("float", 0, 10000, 20):
i += 1
self.assertTrue(n >= 0)
self.assertTrue(n <= 10000)
self.assertTrue(isinstance(n, float))
self.assertEqual(i, 20)
def test_typeError(self):
with self.assertRaises(AttributeError):
g = randNumGenerator("unknowType", 0, 10000, 20)
g.__next__()
使用unittest进行,方法是定义一个继承自unittest.TestCase的类,然后定义以test_开头的类方法,这种方法会自动运行。unittest.TestCase提供了很多断言,具体可以看帮助手册,这里我使用了assertTrue和assertEqual。值得注意的是错误的测试,使用with self.assertRases(),然后在里面引发错误,unittest会捕捉这个期待的错误。
unittest运行有两种方法,一种是添加代码:
if __name__ == '__main__':
unittest.main()
这样就默认运行单元测试了。但是我想让他默认运行的是写入文件的功能,所以采用另一种运行单元测试的方式:
python3 -m unittest random_number_generator
接着是写入文件的操作。我将其放到mypackage/myio.py中,代码如下:
class MyIo(object):
def __init__(self, path):
self.path = path
def writeSeperated(self, generator, separator = " "):
"""
generator: a generator to generate fragments to write in file
separator: separator between fragments.
"""
with open(self.path, "w") as f:
for frag in generator:
f.write(str(frag))
f.write(str(separator))
f.close()
所有文件操作都放到一个MyIo的类中,初始化时会接收一个参数,表示文件路径。
这种以分隔符分隔数据写入文件的方法定义为writeSeperated,第一个参数是一个迭代器,用于生成要写入的数据,第二个参数是分隔符,默认是空格。
最后就是用生成随机数的迭代器带入到写入文件的函数中,一个交互式的生成随机数文件的函数如下:
def writeToFile():
path = input("Please input the whole path of file:\n")
numType = input('You want to generate "int" or "float"?\ntype "int" or "float":\n')
minNum = input('the minimum value of the generated numbers:')
maxNum = input('the maximum value of the generated numbers:')
numb = input('the number you want to generate:')
separator = input('the separator:')
import sys
sys.path.append("..")
from mypackage.myio import MyIo
myio = MyIo(path)
myio.writeSeperated(randNumGenerator(numType, minNum, maxNum, numb))
这个函数会以交互式的形式获取文件的路径、数据的类型、最大最小值、要生成的随机数的个数,以及分隔符。调用这个函数:
if __name__ == '__main__':
writeToFile()
C语言实现
怕麻烦,C语言的实现直接一个文件搞定了,位于c/random_number_generator/main.c,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main()
{
char path[100];
char type[10];
int min;
int max;
int numb;
char separator[10];
printf("Please input the whole path of file:\n");
scanf("%s", path);
printf("You want to generate \"int\" or \"float\"?\ntype \"int\" or \"float\":\n");
scanf("%s", type);
if ( strncmp("int", type, 3) && strncmp("float", type, 5)) {
printf("ERROR: unknow type : %s\n", type);
return 0;
}
printf("the minimum value of the generated numbers:");
scanf("%d", &min);
printf("the maximum value of the generated numbers:");
scanf("%d", &max);
printf("the number you want to generate:");
scanf("%d", &numb);
printf("the separator:");
scanf("%s", separator);
FILE * f = fopen(path, "w");
srand((unsigned)time(NULL));
int range = max - min;
for (int i = 0; i < numb; i++) {
if ( !strncmp("int", type, 3) )
fprintf(f, "%d%s", rand() % range + min, separator);
else if ( !strncmp("float", type, 5) ) {
double rdnumb = (rand() % (range * 100) / 100.00) + min;
fprintf(f, "%f%s", rdnumb, separator);
}
}
fclose(f);
}
本文代码托管于:
https://github.com/haoranzeus/algorithms_study