这题出自2013年谷歌的校招笔试。题目是这样的:
长度为N的数组乱序放着0至N-1,现在只能进行0与其他元素的swap,请设计并实现排序。
读完题目,立马就有了一个简单的思路。既然是0至N-1存放在这个数组中,那么排序后的数组是0 1 2 3 .... ,也就是每个元素的值和它的下标是一致的。这给了我们一个投机取巧的机会。每个元素归为可以分为两步来归位。对于位置X,第一步 将此处的值 和 0进行交换。 第二步 将此处的值(此时为0) 和 值X进行交换。顺着这么一个简单的思路,我们可以先写出如下蠢爆了的代码(你可以直接跳过这段代码进行阅读,毕竟这种low代码没啥可读的,我写下只是为了记录自己思考的整个过程,写这种Low代码的好处大约是,这种代码low到不假思索,可以边写边思考,写的同时就可以考虑更优的方案了。而此代码稍加改进可能就会成为更优的方案,也不算浪费体力吧)
inline void swap(int *_arr,int _index1,int _index2)
{
_arr[_index1] = (_arr[_index1] ^ _arr[_index2]);
_arr[_index2] = (_arr[_index1] ^ _arr[_index2]);
_arr[_index1] = (_arr[_index1] ^ _arr[_index2]);
}
int find(int *_arr,int _num)
{
int ix = 0;
while(_arr[ix] != _num)
ix++;
return ix;
}
void swap_sort(int *_arr,int _len)
{
for(int ix=0;ix<_len;ix++)
{
int zero_index = find(_arr ,0);
swap(_arr,ix,zero_index);
int ix_index = find(_arr ,ix);
swap(_arr,ix,ix_index);
}
}
这样一份代码也就初步将我们的想法实现了,其实不用写完,写一半时 '写出高效代码' 的觉悟就让我们敲不下去键盘了。这样的代码效率低到令人发指,最主要就是find这个函数似乎是没有必要的,我们要去记住每个元素的位置,而不是每次都要去寻找。于是我们在 swap_sort函数的开头添加如下三行代码
int *index_arr = new int[_len];
for(int ix=0;ix<_len;ix++)
index_arr[_arr[ix]] = ix;
index_arr数组就是记录了每个数在_arr数组中所处的位置。
这样我们就不必每次找寻了。代码变成了下面的样子
int *index_arr = new int[_len];
for(int ix=0;ix<_len;ix++)
index_arr[_arr[ix]] = ix;
for(int ix=0;ix<_len;ix++)
{
swap(_arr,ix,index_arr[0]);
swap(_arr,ix,index_arr[ix]);
}
感觉哪里不对,我们不能犯了刻舟求剑的错误 水是流动的 我们的数组也是在变动的,自然记录元素位置的数组也要跟着变动。继续添加两行
int *index_arr = new int[_len];
for(int ix=0;ix<_len;ix++)
index_arr[_arr[ix]] = ix;
for(int ix=0;ix<_len;ix++)
{
swap(_arr,ix,index_arr[0]);
swap(index_arr,0,_arr[index_arr[0]]);
swap(_arr,ix,index_arr[ix]);
swap(index_arr,0,ix);
}
这里需要注意 swap(index_arr,0,_arr[index_arr[0]]); 这句代码是我们交换了原数组中0和位于ix处值的位置(记为val_ix),那么我们自然要在记录位置的数组中反映。记录位置数组的变化是这样的:位置0记录了原数组中0所处的位置。位置val_ix记录了val_ix在原数组中的位置。我们也交换它们的内容。swap(index_arr,0,val_ix)即可。可是val_ix的值已经被我们交换了位置,所以我们要去它新的位置找它,也就是0原来所处的位置。
完整代码如下:
inline void swap(int *_arr,int _index1,int _index2)
{
_arr[_index1] = (_arr[_index1] ^ _arr[_index2]);
_arr[_index2] = (_arr[_index1] ^ _arr[_index2]);
_arr[_index1] = (_arr[_index1] ^ _arr[_index2]);
}
void swap_sort(int *_arr,int _len)
{
int *index_arr = new int[_len];
for(int ix=0;ix<_len;ix++)
index_arr[_arr[ix]] = ix;
for(int ix=0;ix<_len;ix++)
{
swap(_arr,ix,index_arr[0]);
swap(index_arr,0,_arr[index_arr[0]]);
swap(_arr,ix,index_arr[ix]);
swap(index_arr,0,ix);
}
}
int main(int argc, const char * argv[]) {
int test_arr[10] = {1,0,4,3,2,8,5,9,6,7};
swap_sort(test_arr, 10);
for_each(test_arr,test_arr+10,[](int num){cout << num << " ";});
cout << endl;
std::cout << "Hello, World!\n";
return 0;
}