首先,O,Omega,Theta这三个符号并不一定和算法分析有关,这三个符号只是用来刻画函数的增长速度的(比如,微积分里那些什么什么余项也用到了小o记号)。假设有函数f(n)=3n^2+100n+1000,那么我们就可以说f(n)=O(n^2)=O(n^3),f(n)=Omega(n^2)=Omega(n), f(n)=Theta(n^2)。这里可以不涉及任何算法的什么最好最坏情况。
然后,具体到算法复杂度分析上。比如插入排序,在最坏情况下(原序列是倒序时),如果我们仔细计算此时需要的比较和交换次数,会发现它是一个f(n)=An^2+...的形式。于是我们就可以说,插入排序在*最坏情况*下的时间复杂度是Theta(n^2),也是O(n^2),也是Omega(n^2)。另一方面,在最好情况下(原序列已有序时),需要的比较次数是大约n次,于是我们说,在*最好情况*下的时间复杂度是Theta(n),也是O(n),也是Omega(n)。
如果我们笼统地问:插入排序(在*所有情况*下)的时间复杂度是多少?这个问题就不能用Theta回答了,因为最好情况和最坏情况的Theta是不一样的。我们只能回答,在所有情况下都是O(n^2),也可以回答,在所有情况下都是Omega(n)
回到你原帖的前两句话,O(f(n))不一定非要表示最坏情况下的时间复杂度,它表示的只是一个函数的增长速度的上界,至于这个函数是算法的最好情况还是最坏情况,随你的便。当然,一般情况下我们用到O时,一般想要表示的还是最坏情况,但这并不是必须。如我上面所述,最好情况下的时间复杂度也可以用O(n)来表示,只是没什么意义而已。
关于你后面的几个疑问,O(f(n))当然不是确界,对于f(n)=n^2+n+1,我们可以说f(n)=O(n^2),也可以说f(n)=O(n^100)。在分析算法时我们是希望这个界越紧越好,太松的界虽然是正确的但是意义不大。有很多时候,一个算法一眼看过去会有一个粗略的上界,但通过仔细分析可以得出一个紧很多的上界出来,典型的例子就是网络流的各种算法的复杂度分析。
一般讲时间复杂度多用O记号,原因已经说了,主要是算法在不同情况下的增长速度未必是一致的,但如果能够确定是一致的(比如只考虑最坏情况),并且能证明那个也是下界的话,就可以用Theta。我觉得算法导论上对此处理是比较严谨的,一般来讲能用Theta的地方它就会用Theta,不能的地方就用O。