算法导论有趣题——第二章集合

本文探讨了二进制整数相加的算法实现,并通过改进插入排序使用二分查找提高效率。还详细介绍了如何利用排序解决特定问题,并分析了合并排序算法的改进版,用于计算数组中逆序对的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:2.1-4

有两个各存放在数组A和数组B中的n位二进制整数,考虑其相加问题。将所得结果以二进制形式存放在数组C中,C的维数为[n+1]。写出伪代码


解决:
func(A,B,C):

carry_bit = 0

for i = 1 ~ n:

v = A[i] + B[i] + carry_bit

C[i] = v % 2

carry_bit = v / 2

C[n + 1] = carry_bit



题目:2.3-6:

若将插入排序中查找位置的部分改用为二分查找,则最坏情况下算法的复杂度是否仅为 O(nlogn )


解决:

对第 i 个元素,此时查找到合适位置所需要的平均比较次数为 lg(i)。但是找到合适位置后,还需要将合适位置及之后的元素向后挪动,最坏情况下,最合适位置为第一个元素位置,此时仍然需要 i 次挪动。复杂度仍为 O(n^2)



题目:2.3-7

给定长度为 n 的整数集合S,再给一个整数 x,求其中是否有两个元素满足:两个元素的和为 x 。要求算法复杂度为 O(nlogn)


解决:

1. 将整数集合 S 进行排序,所花费时间为 O(nlogn) 

2. 然后用两个迭代器 i, j 分别指向排序后的集合S‘ 的第一个元素和最后一个元素:

若 *i + *j  > x   : j--   // j  挪到更小的位置

若 *i + *j < x    : ++i 


题目:2-1

对合并排序算法进行改进,将 n 个数组划分为大小为 k 的 n/k 个数组,对每个小数组使用插入排序。再对 n/k 个数组进行合并排序。


算法复杂度分析:

k 个数进行插入排序(O(n^2))最差情况下的复杂度为:n/k*O(k^2) = O(nk)

合并 n/k 个小数组(O(n))在最差情况下的复杂度为: lg(n/k)*O(n),解释:该分治算法一共要分的层数为lg(n/k)次,而每一层,合并算法的时间复杂度为Θ(n),所以总的时间复杂度为Θ(nlg(n/k))


所以:该算法的复杂度为Θ(nlg(n/k))


题目:2-4

逆序对——给出一个算法,在O(nlogn)的复杂度算出 n 个数组成的数组中存在的逆序对数量(适量修改合并排序)


解答:

在合并排序的基础上,每次合并子数组前先统计当前两个子数组之间存在多少个逆序对。统计时注意使用特性:两个子数组分别是排好序的。统计好后将这两个子数组排序合并。避免重复计算逆序对。源代码如下:

<span style="font-family:Microsoft YaHei;"><span style="font-size:18px;">int merge(vector<int> & v, vector<int>::iterator beg, vector<int>::iterator mid, vector<int>::iterator end)
{
	vector<int> left(beg, mid);
	vector<int> right(mid, end);
	vector<int>::iterator l = left.begin();
	vector<int>::iterator r = right.begin();

	/////////////////////////////////////// 主要计数功能在此实现
	int count = 0;
	int n = 0;
	int n_left(left.size()), n_right(right.size());
	int l_i(0), r_i(0);

	while (l_i != n_left)
	{
		n = 0;
		while (r_i != n_right && right[r_i] < left[l_i])
		{
			++n;
			++r_i;
		}
		count += (n_left - l_i) * n;
		
		if (r_i == n_right)
			break;
		++l_i;
	}

	////////////////////////////////////// 下面是普通的合并排序中合并的实现源码

	while (l != left.end() && r != right.end())
	{
		if (*l <= *r)
		{
			*beg = *l;
			++l;
		}
		else
		{
			*beg = *r;
			++r;
		}
		++beg;
	}

	if (l != left.end())
	{
		while (l != left.end())
			*beg++ = *l++;
	}
	else if (r != right.end())
	{
		while (r != right.end())
		{
			*beg++ = *r++;
		}
	}
	else;

	return count;

}


int merge_sort(vector<int>& v, vector<int>::iterator beg, vector<int>::iterator end)
{
	if (beg + 1 >= end)
		return 0;
	vector<int>::iterator mid = beg + (end - beg) / 2;
	int count = 0;
	count += merge_sort(v,beg, mid);
	count += merge_sort(v,mid, end);
	count += merge(v, beg, mid, end);
	return count;
}


int main()
{
	vector<int> v = { 4, 1, 6, 3, 2, 5, 8 };
	cout << merge_sort(v, v.begin(), v.end()) << endl;
}</span></span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值