唯有的两次面试考察了排序,每次都想写个时间复杂度在O(nlogn)。第一次面试一看到排序想都没想直接开撕快速排序,写到一半快速排序的逻辑忘了,尴尬之余速度整了个冒泡排序替代。第二次面试也有一道排序题,当时想都没想直接开撕归并排序,结果在处理辅助数组的时候把自己给绕晕了,越写越慢,临时整了个冒泡排序替代。( ̄_, ̄ )"。冒泡排序还真是好用,呵呵。平常工作的时候遇到排序问题基本上整个冒泡排序就过去了,最近准备面试刷题复习算法的时候,觉得只会写冒泡排序的水平太low了,深深鄙视。仔细想想,无论是快速排序还是归并排序,不管是逻辑还是代码都是相当简单的,但一到笔试的时候写不上来,归根结底还是平时自己要求不高,没有彻底掌握理解,此外就是没有做好准备就直接笔试。我们接着谈归并排序。
归并排序思想就是把两个有序数组合并成一个数组,基本操作是俩有序数组各设一个起始指针i,j,比较arr[ i ], arr[ j ],小的先插入到辅助数组,然后移动i指针。像这样一步步比较插入移动指针,直到一方到了末尾,这时候把另一端剩余的元素全部插入进去即可。这里可以看到,归并操作是需要额外辅助空间的。当我们得到一个无序的数组的时候,需要使用二分法分割该数组,1分2,2分4,直到分割得到的数组子集元素个数为1,这时候两两比较排序归并,自下往上,最终得到有序数组。过程中使用到了递归,即每当数组元素大于1的时候,调用递归继续分割。这里仅有的难点是辅助数组的处理,因为归并不能直接在原始数组上运算,需要借助额外的数组来帮忙,递归返回的是有序数组。可以在递归程序里使用一个额外数组,归并的数据先放在辅助数组里,返回前在将辅助数组里的数据复制到原始数组即可。
c代码:
void MergeSort(int *arr, int left, int right)
{
//辅助数组
int arr2[MAXSIZE] = {0};
int i, j, k;
int mid = (right + left) / 2;
//只有一个元素则返回
if (left >= right || !arr)
return;
//递归分割
MergeSort2(arr, left, mid);
MergeSort2(arr, mid+1, right);
//归并处理
k = i = left;
j = mid + 1;
while(i <= mid && j <= right)
{
if (arr[i] < arr[j])
arr2[k++] = arr[i++];
else
arr2[k++] = arr[j++];
}
if (i>mid)
while (j<=right)
arr2[k++] = arr[j++];
else
while (i<=mid)
arr2[k++] = arr[i++];
//返回有序数据
for (i = left; i <= right; i++)
arr[i] = arr2[i];
return;
}
参考资料:
1. 数据结构 : C语言版/ 严蔚敏,吴伟民编著
=============================================================================================
Linux应用程序、内核、驱动、后台开发交流讨论群(745510310),感兴趣的同学可以加群讨论、交流、资料查找等,前进的道路上,你不是一个人奥^_^。