邓公数据结构C++语言版学习笔记

1. 对于计算幂 2 n 2^n 的算法优化
在这里插入图片描述
暴力算法时间复杂度 O ( n ) O(n)

 __int64 power2BF_I(int n) //幂函数2^n算法(蛮力迭代版),n >= 0
 { 
	__int64 pow = 1; //O(1):累积器刜始化为2^0
	while (0 < n --) //O(n):迭代n轮,每轮都
		pow <<= 1; //O(1):将累积器翻倍
	return pow; //O(1):返回累积器
} //O(n) = O(2^r),r为输入指数n的比特位数

在这里插入图片描述
递归优化算法时间复杂度 O ( l o g n ) O(logn)

 //优化算法时间复杂度O(logn)
 inline __int64 sqr(__int64 a) 
{
  	 return a * a; 
}
__int64 power2(int n) //幂函数2^n算法(优化递归版),n >= 0
{ 
	if (0 == n) return 1; //递归基
	return (n & 1) ? sqr(power2(n >> 1)) << 1 : sqr(power2(n >> 1)); //视n的奇偶分别递归
} //O(logn) = O(r),r为输入指数n的比特位数

循环优化算法时间复杂度 O ( l o g n ) O(logn)

int quickpower(int a,int b)
{
	ans = 1,base = a;
	while (b > 0)
	{
		if (b & 1)
			ans *= base;  //记录当b为奇数时少乘的一个a
		base *= base;   
		b >>= 1;
	}
	return ans;
}

2. 对于Fibonacci数列的算法优化
简单递归算法时间复杂度 O ( 2 n ) O(2^n) ,空间复杂度 O ( n ) O(n)

__int64 fib(int n)
{
	return(2 > n) ? (__int64)n : fib(n - 1) + fib(n - 2);
}

线性递归版算法时间复杂度 O ( n ) O(n) ,空间复杂度 O ( n ) O(n)

__int64 fib(int n, __int64& prev)
{
	if (0 == n)
	{
		prev = 1;
		return 0;
	}
	else
	{
		__int64 prePrev;
		prev = fib(n - 1, prePrev);
		return prePrev + prev;
	}
}

基于动态规划优化时间复杂度 O ( n ) O(n) ,空间复杂度 O ( 1 ) O(1)

}*/
__int64 fib(int n)
{
	__int64 f = 0, g = 1;
	while (0 < n--)
	{
		g += f;      //第k+1项
		f = g - f;   //第k项
	}
	return f;
}

3. 对于二分法查找算法的进一步思考
<1>.A版本的二分法查找

int BinarySearch_A(int arr[], int num, int low, int high)
{
	while (low < high)
	{
		int mid = (low + high) >> 1;//右移运算符 相当于除以2
		if (num < arr[mid])
			high = mid;
		else if (num > arr[mid])
			low = mid;
		else
			return mid;   //成功查找提前终止
	}
	return -1;   //查找失败
}

缺点:①有三个分支(if elseif else)每个分支的比较运算占用一定的时间可以优化
②有多个命中元素时,不能保证返回秩最大者(即序号最大)
③失败时,简单地返回-1,而不能指示失败位置

<2>.B版本的二分法查找——从三分支到两分支

int BinarySearch_B(int arr[], int num, int low, int high)
{
	while (1 < high - low)//每次迭代仅需要一次比较判断,有两个分支;成功查找不能提前终止
	{
		int mid = (low + high) >> 1;
		(num < arr[mid]) ? high = mid : low = mid;//经比较后确定深入[low,mid)或[mid,high)
	}
	return(num == arr[low]) ? low : -1;
}

优点:相比于A版本的二分法由三分支到两分支,优化了时间
缺点:①有多个命中元素时,不能保证返回秩最大者(即序号最大)②失败时,简单地返回-1,而不能指示失败位置 ③成功查找不能提前终止

<3>.C版本的二分法查找——解决A版本的所有缺点

int BinarySearch_C(int arr[], int num, int low, int high)
{
	while (low < high)
	{
		int mid = (low + high) >> 1;
		(num < arr[mid]) ? high = mid : low = mid + 1; //比较后深入[low,mid)或(mid,high)
	}
	return --low;//返回low-1的目的对于[0,low)内的数不大于num而low可能大于num但是low-1一定为num(如果能够查找成功)而且保证返回秩最大者(即序号最大)
}

优点:①三分支到两分支优化了时间②有多个命中元素时,保证返回秩最大者(即序号最大)③查找失败时,能够返回失败位置
缺点:成功查找不能提前终止
在这里插入图片描述
对二分法进一步的优化可能引出了一个问题——我们为什么要求有多个命中元素时,保证返回秩最大者(即序号最大)?这到底能带给我们什么好处?
以有序向量的插入操作为例,若通过查找操作不仅能够确定可行的插入位置,而且能够在同时存在多个可行位置时保证返回其中的秩最大者,则不仅可以尽可能低减少需移动的后继元素,(插入元素的原理:①先保证数组空间不能够overflow②将插入位置的后继元素向后移动一个一个赋值③将元素插入)更可保证重复的元素按其插入的相对次序排列。对于向量的插入排序等算法的稳定性而言,这一性质更是至关重要。

4. Stack中的逆波兰表达式(RPN)
<1> RPN特点:既不必在事先做任何约定,更无需借助括号强制改变优先级
<2> 如何计算RPN?
简单总结一下:将所有操作数一一压入栈中,如果遇到操作符 x x 则就从栈中弹出运算符 x x 所需数目的操作数,然后实时对 x x 操作符的运算,最终将新结果重新压栈( 阶乘运算符需要一个操作数,其他 + × ÷ +-×÷ 运算符一般需要两个操作数)
在这里插入图片描述
<3> 如何手工将中缀表达式(infix)转化为RPN表达式亦称作后缀表达式(postfix)?
①用括号显示地表示优先级 ②将运算符移到对应右括号后(表示该运算符优先级的括号)③抹去所有括号 ④稍加整理
在这里插入图片描述
2020/2/20学习清华大学邓俊辉老师的《数据结构C++语言版》笔记,方便复习也供大家参考,如果有错误麻烦在评论指出,互相学习进步!本文代码全部来源于《数据结构C++语言版》

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/104390247
今日推荐