关于冒泡排序和二分查找的一些个人看法
1. 冒泡排序
冒牌排序为什么叫冒泡排序呢?是因为每次都会有一个较小的数不断往数组前方走(小到大排序),如同一个泡泡上升的过程,因此我们称之为冒泡排序。先贴一下代码:
void Bubble_sort()
{
for(int i = 1;i < n;i ++ )
{
for(int j = 1;j < n;j ++ )
{
if(a[j] > a[j + 1])
{
swap(a[j],a[j + 1]);
}
}
}
}
我们每次都选取数列中的第一个元素(a[j])往后比较,若(a[j+1])大于(a[j]),则交换两个数,每进行一次这样的过程,都会使得数组中的一个较大的数处于数组后方。一共进行(n)次这样的过程,所以会使(n)个数处于有序的状态,于是就可以在(O(n^2))的时间内排好这一列数。由于在(a[j])与(a[j+1])相同时,不发生交换,所以冒泡排序还是一种稳定排序算法。
2. 二分查找((a)数组为单调递增数列)
二分查找是确定一个元素在数列中的位置的算法。什么样子的数组能使用二分查找呢?不如来看看二分查找的代码:
int equal_dict(int x)
{
while(l < r)
{
int mid = (l + r) >> 1;
if(a[mid] >= x) r = mid;
else l = mid + 1;
}
return a[l];
}
先说结论:具有单调性的数组才可以进行二分查找。每次我们都有一个(l)和(r),来表示我们要查找的范围,(mid)为(l),(r)的中间值。如果以mid为下标的数大于了目标值(x),则下标为(mid)的数以后都是大于(x)的,所以(x)不可能位于(mid)右侧,所以我们就选择(mid)的左侧,这个区间一定是(x)所在的区间。小于同理。如果数列不是有序的,则不能进行缩小区间的操作,无法找到(x)的位置。
二分算法充分利用了元素间的次序关系,采用分治策略。由于每次区间长度折半,所以时间复杂度为(O(log_{2}{n}))。发明二分算法的大佬Knuth说,思路很简单,细节是魔鬼。二分的细节很是重要,据说只有10%的程序员能写对二分。所以二分要掌握自己的一套写法,练熟练会即可。
写在后面
排序算法有很多种,大致可以分为以下三类:
- 冒泡排序、插入排序、选择排序
- 堆排序、归并排序、快速排序
- 计数排序、基数排序、桶排序
前两类都是基于比较的排序算法,第一类排序时间复杂度为(O(n^2)),第二类排序时间复杂度为(O(nlog_n)),信息论以证明,基于比较的排序算法的时间复杂度下界为(O(nlog_n)),第二类算法已经是最优的基于比较的排序算法了
第三类算法换了一种思路,它们不直接比较大小,而是对被排序的数值采取按位划分,分类映射等处理方式,其时间复杂度不仅与(n)有关,还与数值的大小范围(m)有关。