我是算法的新手,并且在if语句存在时如何计算时间复杂度有疑问。我有一个在堆中实现的优先级队列。这是出列方法:
int[] pQueue;
int length;
int dequeue()
{
int node = 1;
int value = pQueue[--length];
int maxValue = pQueue[node];
int location = sift(node * 2, value);
pQueue[location] = value;
return maxValue;
}
int sift(int node, int value){
if (node <= length){
if (node < length && pQueue[node] < pQueue[node + 1])
node++;
if (value < pQueue[node]){
pQueue[node / 2] = pQueue[node];
return sift(node * 2, value);
}
}
return node / 2;
}
在sift方法中,有两行代码:
if (node < length && pQueue[node] < pQueue[node + 1])
node++;
由于n ++是根据上述条件执行的,在推导递推方程时我是否应该计算?我知道它确实会渐进地产生任何差异,但有没有任何标准的方法呢?非常感谢。
答案 0 :(得分:2)
标准方法是在取决于所考虑的变量时考虑该条件。例如,考虑一个简单的递归函数,它在if
语句中调用它自己:
double factorial(int n) {
double result = n;
if (n > 0) {
result *= factorial(n - 1);
}
return result;
}
如果我们假装总是满足if
- 条件,那么递归是无界的,复杂性是无限的(无论 n )。如果我们假装永远不会满足if
- 条件,那么递归调用永远不会发生,并且复杂性是不变的。显然,这些都不是可以接受的假装;复杂性实际上是O( n )。
当条件不依赖于所考虑的变量时,标准方法通常是给出最坏情况的复杂性(并指示我们这样做)。例如,对于排序算法,我们通常根据被排序的序列的长度给出复杂性,但是许多排序算法根据元素的初始排序执行不同。因此,我们假设我们对序列的性能感兴趣,并且 有利于它们的长度排序,并相应地进行计算。
(通常也可以提供平均情况复杂度,但是,通过平均所有可能的输入,有时甚至是典型案例复杂性。)
答案 1 :(得分:0)
找出最坏情况的上限。 sift()之前的每一行调用1次。除了递归调用之外,sift()内的所有指令都需要恒定的时间:
return sift(node * 2,value);
该特定行具有由n确定的最大递归调用量。具体地说,它将调用自身直到节点超过n-1(节点&lt; = length,回想起该长度减1)。请记住,每次递归调用时节点都会加倍。因此,节点加倍多次,直到它超过n,因此它调用lg(n)次。这代表了最糟糕的情况,其中value是pQueue堆子树中最少的元素。现在,到了你的观点。
由于递归调用常数Θ(1)指令O(lg(n))次,你真的不应该关注递归方程中的常数,因为所有这些都在Θ(1)下总和:
T(n)= O(lg(n))+Θ(1)