我正在尝试两个找到合并 n 文件数量的递归函数的时间复杂度。
我的解决方案是 T(n)= kc + T(n-(k + 1))其中 n > 0, T(n)= T(0)其中 n = 0。
这是正确的还是有其他方法可以找到时间复杂度?
这是伪代码,
//GLOBAL VARIABLES
int nRecords = 0...k; //assume there are k records
int numFiles = 0...n; //assume there are n files
String mainArray[0...nRecords]; //main array that stores the file records
void mergeFiles(numFiles) { //params numFiles
fstream file; //file variable
if (numFiles == 0) {
ofstream outfile; //file output variable
outfile.open(directory / mergedfile); // point variable to directory
for (int i = 0; i < sizeOf(mainArray); i++) {
oufile << mainArray[i]; // write content of mainArray to outfile
}
outfile.close(); //close once operation is done
} else {
int i = 0; //file index counter
file.open(directory / nextfile); //open file to be read
if (file.isOpen()) {
while (!file.eof() && i < sizeOf(mainArray)) {
file >> mainArray[i]; //copy contents of file to mainArray
i++; //increase array index
}
}
file.close(); //close once operation is done
mergeFiles(numFiles - 1); //recurse function
}
}
int main() {
mergeFiles(numFiles); //call mergeFile function to main
}
答案 0 :(得分:1)
Going by your formula.
T(n)= kc+T(n-(k+1)) = kc+kc+T(n-(k+1)-(k+1)) = kc+kc+...+T(0) = ...
= kc*(n/(k+1)) ~ nc = O(n).
答案 1 :(得分:1)
k 的定义在您的问题中有点含糊不清,因为您为 T(n)提供的公式似乎假设您处理 k 记录每个文件,而代码中mainArray
的定义表明 k 代表总记录数,而不是单个文件中的记录数。
我首先假设 k 的第二个定义是正确的,所以你有:
我认为你假设以下两个语句 - 读/写一条记录 - 在每个恒定时间运行:
file >> mainArray[i];
outfile << mainArray[i];
请注意,此类操作所需的时间通常取决于记录的大小。但是由于你没有提供这个大小作为考虑因素,我将假设记录具有恒定的大小,因此可以认为这些操作在 O(1)中运行,即恒定时间。
虽然您使用递归,但它确实关注tail-recursion,因此时间复杂度与迭代算法没有任何不同。无论哪种方式,else
块都会执行 n 次。
事实上,使用递归公式计算时间复杂度并不是那么简单,因为您不知道一个文件中有多少条记录,只知道所有文件中的记录。您可以解决这个问题,并且人为地假设每个文件中都有 k / n 记录,但我发现根据else
的绝对次数执行测量更加直观执行块,而不需要在递归公式中表达它。
内部while
循环的主体最多可以执行 k 次,并且假设您认为文件中有多少条记录,它将完全执行总计 k 次。
最后一部分(其中numfiles == 0
)有一个for
循环,也会执行 k 次。
因此决定时间复杂性的因素是:
所以时间复杂度是 O(n + k)
如果 k 应表示一个文件中的记录数,那么您的代码是错误的,因为数组的大小必须 nk < / em>,而不是 k 。假设您仍然打算这样做,那么通过类似的推理,时间复杂度为 O(n.k)
在实际情况中,您必须确保数组的大小与文件中的记录总数相对应,而不仅仅是假设是这种情况。如果阵列变小,则无法存储某些记录;另一方面,如果数组更大,则将数组转储到输出文件中的代码将包含从未初始化的数组元素。
因此,您最好使用具有动态大小(堆栈)的数组,因此其大小与实际读入的数据完全对应。