思路
python的特性支持快速开发实用小程序的能力,能让你做事效率大幅度提高。特别是在c++数据测试中,检验一个程序的可靠性需要大量数据进行测试可靠性。虽然c++也有随机函数等方法但是不方便移植更改,用Python编写数据生成器是再合适不过的了。接下来进行举例说明:下面的代码直接在python3终端中运行,生成一个长度在4 ~9之间, 恰好包含一个大写字母, 其他字符为小写字母的特殊串。
>>> from random import*
>>> from string import*
>>> L = randint(4, 9)
>>> s =''.join([choice(ascii_lowercase) for i in range(L)])
>>> p = randint(0, len(s))
>>> s[:p] + choice(ascii_uppercase) + s[p:]
' bdsqVgke'
列表解析Clist comprehension) 是一种构造列表的简单方法。range(5) 生成列表[0,1,2,3,4]。这条语句就是 “对于列表[0,1,2,3,4]中的每个数i调用一次 choice(lowercase),把结果拼成一个列表” 。接下来用join函数把列表里的字符串连接起来。 .join(L)的作用是把字符串列表L中的各个字符串拼接起来。 最后随机出小写字符出现的位置p, 然后插入到大写字母串中。s[a:b]代表列表或者字符串的第a个元素到第b-1 个元素。a和b都可以省略,a默认为0, b默认为列表长度。L2 = L[:]的作用是创建一个和L 一样的数组。 由于Python 的所有值都是引用类型的, 因此L2=L只是把L中保存的引用拷贝(浅拷贝)到了L2,这点需要小心。例如下面的代码,求其地址id可以分析出来。
>>> a,b=1,2
>>> a= [1,3,7]
>>> b=[1,3,7]
>>> c,d=a,a[:]
>>> id (a), id (b), id (c), id (d)
(12598008, 12517288, 12598008, 12517208)
计算 30!可以采用如下写法:
>>> from functools import*
>>> reduce(lambda x,y: x*y, range(1,31))
265252859812191058636308480000000L
简单实现
类似的东西还有很多。 使用Python后, 能大大缩短编写数据生成器、对拍器、 “猜想验证器” 等小程序的时间,这里我打算把python生成的数据全部转为字符数据存入文本中(转字符数据就不用考虑int位数 浮点数精度等问题)。c++再读数据存入容器进行原本函数的测试。
python生成数据代码
接下来的代码为进行测试写入文件的代码,作为参考:
# !/usr/bin/env python3
# coding: utf-8
from random import *
from string import *
def create_element0(lines, a = 4, b = 7):
elements = []
for i in range(lines):
# ascii_lowercase在string中定义,为所有小写字符的列表
# choice(seq): 返回列表、元组或字符串seq的随机项str。(可重复)
L = randint(a, b)
s =''.join([choice(ascii_lowercase) for i in range(L)])
p = randint(0, len(s))
element = s[:p] + choice(ascii_uppercase) + s[p:] + '\n'
elements.append(element)
return elements
def create_element1(lines):
elements = []
for i in range(lines):
# sample: 不重复的取列表中i个元素,并返回这些元素组成的列表
# 不可像choice中列表添加for in,因为其返回的是列表
# 要生成m个不重复i元素列表得在外面加循环
username = ''.join(sample(ascii_letters + digits, 5))
password = randint(10000,99999)
element= str(username) + "," + str(password) + '\n'
elements.append(element)
return elements
def create_element2(lines):
elements = []
allNum = list(range(-10000, 10000))
NumLen = len(allNum)
#在allNum中抽取Len个不重复数字,最后依照题意排序,旋转。共lines组
for i in range(lines):
s = []
num = randint(1, 256)
for j in range(num) :
index = randint(j, NumLen - 1)
s.append(allNum[index])
# 把用过的元素到前面,以防再次选中
allNum[index], allNum[i] = allNum[i], allNum[index]
# 模拟target是否存在,有1/36的几率必定不存在
suiji = randint(0,35)
if suiji == 35:
target = 10001
else :
target = s[randint(0, num-1)]
#排序取出的不重复数组并旋转
s.sort()
k = randint(0, num-1)
if k != 0 :
s = list(reversed(s[0:k])) + list(reversed(s[k:num]))
s.reverse()
element = ' '.join([str(s[i]) for i in range(num)]) + '\n'
elements.append(element)
elements.append(str(target) + '\n')
print(f"i = {i},\t k = {k}, \ttarget = {target}")
return elements
C++读取文件代码
C++中各种流头文件说明 iostream处理控制台IO; fstream处理命名文件IO; stringstream完成内存string的IO。 类fstream和stringstream都是继承在类iostream的。 输入类都继承自istream,输出类都继承自ostream。 string流:sstream头文件定义了三个类型来支持内存IO, 这些类型可以向string写入数据,从string读取数据,就像string是一个IO流一样。 将所有行数据打印出: 该代码仅为读取数据并载入容器中作为模板使用,若要加入判断正确等功能可以根据实际情况添加
// 导入文本至容器,将每一行的数据以空格为间隔输入一个字符容器,将所有行的数据输入
int main()
{
string temp;
ifstream myfile("./date.txt");
if( !myfile ) {
cout << "open file fail!" << endl;
return -1;
}
vector<string> res;
while (getline(myfile, temp)) { //默认停止符\n
stringstream slices(temp);
string slice;
while (slices >> slice) { // 类似cin输入,将每行排除不可显字符 空格等字符输入容器,直到接收回车为止
res.push_back(slice);
// stoi(int), stol(long), stof(float), stod(double)
}
// for( auto r : res)
// cout << r << endl;
res.clear();
}
myfile.close();
return 0;
}
实际测试案例
上述测试确定无问题后,开始实际做python数据导入c++中做测试: 其中c++代码为leetcode题目搜索旋转排序数组 python生成数据函数即为上述代码的create_element2用于测试判断c++代码是否正确 接下来是c++的读取文件并进行调用。
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
// 自己写的跟官方的思路差不多,官方答案不用先找到最大临界值再二分 直接进行判断二分
// 下面为官方答案,注意 边界 等于 问题
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = (int)nums.size();
if (!n)
return -1;
else if (n == 1)
return nums[0] == target ? 0 : -1;
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid; // target判断是否为mid
if (nums[0] <= nums[mid]) { // 说明0到mid是升序
if (nums[0] <= target && target < nums[mid]) // target在该升序中
r = mid - 1;
else
l = mid + 1;
}
else { // 说明mid到n-1是升序
if (nums[mid] < target && target <= nums[n - 1]) // target在该升序中
l = mid + 1;
else
r = mid - 1;
}
}
return -1;
}
};
// 导入文本至容器测试,将每一行的数据以空格为间隔输入一个字符容器,将所有行的数据输入
int main()
{
string temp;
ifstream myfile("./date.txt");
if( !myfile ) {
cout << "open file fail!" << endl;
return -1;
}
vector<vector<int>> ress;
vector<int> res;
vector<int> targets;
while (getline(myfile, temp)) { //默认停止符\n
stringstream slices(temp);
string slice;
while (slices >> slice) { // 类似cin输入,将每行排除不可显字符 空格等字符输入容器,直到接收回车为止
res.push_back(stoi(slice));
// stoi(int), stol(long), stof(float), stod(double)
}
getline(myfile, temp);
targets.push_back(stoi(temp));
// for( auto rio : res)
// cout << rio << endl;
ress.push_back(res);
res.clear();
}
myfile.close();
Solution su;
for (int i = 0; i < ress.size(); i++) {
int ans = su.search(ress[i], targets[i]);
cout << targets[i] << ' ' << ans <<endl;
}
return 0;
}