常见的时间复杂度(包含例子二分查找算法C/C++)

本人加入程序猿行列已近七年,平日工作虽繁忙,但感觉实际浑浑噩噩,提升十分有限,所以打算开始业余时间提升自己,学习算法相关知识,借此也想与各位共同成长,发表一些自己的学习所得。

学习算法之前,我们首先要知道一个知识点就是,我们该如何判断一个算法的好坏呢?

说起来很简单,好的算法无非是运行时间短、空间占用小。

不过,在没有实际运行之前,我们无法得知程序确切的运行时间,所以便需要在程序执行前,估算它的执行次数。

那么,我们应该如何去估算这个执行的次数呢?

我们先来看一道很简单的题目,给你一个不重复的有序的整型数组,要求查找某个数字在这个数组中的索引。

曾经的我:“这还不简单?瞧不起谁呢!!!看我的大力出奇迹!!!”

根据题意,我们不难得出第一个思路(算法1):

int BruteFind(int* a, int n, int nVal)
{
    for (int i = 0; i < n; ++i)
    {
        if (nVal == a[i])
            return i;
    }

    return -1;
}

面试官:“Emmmmmmm……如此确实可以解决我提出的需求,但你这个算法的效率可不高啊……”

曾经的我:“怕啥?现在的计算机性能越来越高,再慢也就几毫秒,权当是误差了,哈哈!”

面试官:“好吧,那你回去等十万亿毫秒的通知吧……”

我:“啊?不要啊!!!”

……

咳咳,友情提示,大家可不要学曾经的老蛋一样噢。

好,那么言归正传,面试官是如何看出我这个算法的效率不高的?

这就涉及到了我们今天的知识点,时间复杂度。

在这个算法当中,我们不难看出,如果在最坏的情况下,需要循环整个数组,才可以找出正确的数。

我们将这个,记为O(n),表示其时间复杂度。

那么有没有什么更快速的算法能够实现这个需求的呢?

当然有,这就涉及到了第二个算法,二分查找算法。

在实现算法之前,你们可以回忆一下自己有玩过这样的游戏吗?

你在心里默默想一个1000以内数字(比如是420),我来说一些数字,你只要根据你想的数字说大了还是小了,我很快就能猜出你想的那个数字。

这当然可以用我们的算法一去解决,但那并不是最优解,最优的方法应该如下:

(1)我:“500。”

    你:“大了。”

(2)我:“250。”

    你:“小了。”

(3)我:“375。”

    你:“小了。”

(4)我:“437。”

    你:“大了。”

(5)我:“406。”

    你:“小了。”

(6)我:“421。”

    你:“大了。”

(7)我:“413。”

    你:“小了。”

(8)我:“417。”

    你:“小了。”

(9)我:“419。”

    你:“小了。”

(10)我:“420。”

     你:“答对了。”

可以看出,这种解法,10次就已经猜出了你想的数字,那么聪明的你应该也发现了它的规律了吧?

没错,因为序列有序,所以我们可以先猜0和1000的平均值500,如果大了,我们就知道数字所处的位置应该是0-499之间,进而猜测0和499的平均值,如果小了,我们就知道数字所处的位置应该是501-1000之间,进而猜测501和1000的平均值……按照这个规律猜测下去,直到找出正确答案。

而我们的二分查找算法所用到的,就是这个原理。

事不宜迟,上代码:

int binary_search(int key, int* a, int n)
{
	int low = 0, high = n - 1;
	while (low <= high)
	{
		int mid = low + (high - low) / 2;    // 防止溢出

		if (key < a[mid])
			high = mid - 1;
		else if (key > a[mid])
			low = mid + 1;
		else
		    return mid;
	}

	return -1;
}

由于这个算法每次能将数组折半(逻辑折半,并不是物理折半),最坏的情况下折半到最后一个元素才完成查找,因此不难得知时间复杂度应为O(㏒₂n)(n以2为底的对数)。

㏒₂n < n,因此我们可以认为二分查找的效率优于暴力算法,这个是理论上的,实际上并不一定,但普遍是满足这个规律。

那么我们常见的时间复杂度有哪些呢?

(1)O(1),可以认为是没有时间开销,基本是只有基础运算,并未有循环、递归。

(2)O(n),如刚刚暴力查找算法,最坏情况基本是遍历整个数组。

(3)O(㏒₂n),如二分查找算法,每次循环会对数组折半(只是逻辑上的,不是物理上的折半)。

(4)O(n²),如冒泡排序、选择排序、插入排序,基本都是二层循环。

(5)O(n㏒₂n),如快速排序、堆排序、归并排序。

还有更复杂的就暂时不赘述了,这些是我们学习过程中经常遇到的,大致了解即可。

祝大家在算法路上越走越远,越走越顺!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值