文章出处:http://blog.csdn.net/hongyuan19/archive/2007/11/16/1887656.aspx
在网上逛某论坛时,发现一所谓的高手贴了这样一道题,说是华为的面试题,如下:
有N个大小不等的自然数(1--N),请将它们由小到大排序。
要求程序算法:时间复杂度为O(n),空间复杂度为O(1)。
高手经过一番分析后,说该题其实很简单,给出了答案如下:
void sort(int e[], int n)
...{
int i;
int t; /**//*临时变量:空间复杂度O(1)*/
for (i=1; i <n+1; i++) /**//*时间复杂度O(n)*/
...{
t = e[e[i]]; /**//*下标为e[i]的元素,排序后其值就是e[i]*/
e[e[i]] = e[i];
e[i] = t;
}
}
看了看总觉得不大妙,用他这个算法写了个程序试了下,数组{5,4,3,1,2}排序完之后是{2,1,3,4,5},根本没有达到效果,一时有些迷茫.仔细想了想,虽然该高手的分析没有问题,但在实现上忽略了一些东西,以上算法中每次赋值只是保证了e[e[i]]的正确,却无法保证e[i]的正确,之后i值变为i+1,该次赋值就结束了,所以才会出现问题。
思考良久,没有想出正确的来,看来华为还是有些难度的。
网上查了下,结果让我很郁闷,许多人都是把上面的解法直接转贴过来,根本不在乎其中内容的正确性,估计连脑子也没过就直接贴上去了,最让我无法忍受的是某些装B的高手。
煞有介事地冠之以题目“从华为一道面试题浅谈计算机专业在校大学生该如何学习专业课程”,然后从就业形势严峻谈起,引出该题目,还来了一句很自信的话“简单一道排序题,考倒多少读书人!”,然后分析该题,最后说通过这个题谈谈如何学习专业课程,还建议多在基础知识方面下工夫,有条件的多做习题、多上机、勤思考,多看看同一个问题其他人是怎么解决的,等等站在高手角度教育人的一番话。
于是期待成为编程高手的我耐心看完了这裹脚布一般的大论,再看他给出的解法如下:
void sort(int e[], int n)
...{
int i;
int t; /**//*临时变量:空间复杂度O(1)*/
for (i=1; i<n+1; i++) /**//*时间复杂度O(n)*/
...{
t = e[e[i>; /**//*下标为e[i]的元素,排序后其值就是e[i]*/
e[e[i> = e[i];
e[i] = t;
}
}
void main()
...{
#define MAX 10
int i, a[MAX+1];
printf("Input the number from 1 to %d: ",MAX);
for (i=1; i<MAX+1; i++)
...{
scanf("%d",&a[i]);
}
sort(a,MAX);
printf(" ====sort over==== ");
for (i=1; i<MAX+1; i++)
...{
printf("%d ",a[i]);
}
printf(" ");
system("pause");
}
靠,怎么和最上面的算法一样?上面的算法根本不对啊!我本来懒得说什么,但还是忍不住。
不知该高手在建议“多上机”的同时是否上机亲自验证了一下自己的算法?不知该高手在建议“勤思考”的同时是否把这个题看得很简单但还是认真思考了?以自己的这种不负责态度还如此这样教育新人,是自以为是,更是误人子弟!要是我没仔细想就按这个记下来了,以后岂不是……
闲话不扯了,接着说这道题,我这个菜鸟虽然知道上面的算法不对,可自己也想不出什么好的改进方法来,幸好我又百度到了一个论坛,该论坛中有人给出的解答如下:
int cnt = 0;//辅助变量,不是算法组成部分
void sort(int arr[], int n)
...{
int t; /**//*临时变量:空间复杂度O(1)*/
//可以证明这个算法每次交换必然将一个数字正确安排到位,而且最多只有N次交换。
//具体体现在cnt的值上,所以虽然是二重循环仍然是时间复杂度O(n)
for (int i = 1; i <= n; i++)
...{
while(arr[i] != i)
...{
t = arr[arr[i]];
arr[arr[i]] = arr[i];
arr[i] = t;
++cnt;
}
}
}
又来到CSDN上面发帖问,也有人如此为我解答,算出来的结果没有问题,根据给出的解释,复杂度也应该符合要求,该问题应该就是如此答案了吧。如果您有什么新的见解,请不吝赐教。
最后再BS一下自以为是的所谓高手,还有那些只顾埋头转贴的人…