栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C语言实现-左神算法课p3习题】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【C语言实现-左神算法课p3习题】

左神算法课p3
    • 1.master公式分析递归函数的时间复杂度
    • 2.递归求解数组最大值
    • 3.归并排序
      • 1.补充--new和delete的用法
      • 2.归并排序
    • 4.归并排序扩展--小和问题
      • 1.补充--vector使用详解
      • 2.小和问题
        • 1.使用new动态开辟数组版本
        • 2.使用vector动态开辟数组版本
    • 5.归并排序扩展--逆序对问题
    • 6.快速排序引例--荷兰国旗问题
      • 1.问题1
      • 2.问题2
      • 3.完整代码及测试
    • 7.快速排序

1.master公式分析递归函数的时间复杂度

2.递归求解数组最大值

使用master公式分析以下程序时间复杂度为O(n)

#include
using namespace std;
int Max(int a, int b) {
	return a > b ? a : b;
}
int ArrMax(int *arr, int left, int right) {
	if (left == right) //递归出口
		return arr[left];
	int mid = (left + right) / 2;
	int left_part_max = ArrMax(arr, left, mid);
	int right_part_max = ArrMax(arr, mid + 1, right);
	return Max(left_part_max, right_part_max);
}
int main() {
	int test[] = { 3,4,1,8,6,4,2,6,9,4,1 };
	int len = (sizeof(test) / sizeof(test[0]));
	cout << ArrMax(test, 0, len - 1);
}
3.归并排序 1.补充–new和delete的用法

2.归并排序
#include
using namespace std;
void Print(int *arr, int len) {
	for (int i = 0; i < len; i++)
		cout << arr[i] << ' ';
	cout << endl;
}
void Merge(int *arr, int left, int mid, int right) {
	int *res = new int[right - left + 1];
	if (res == NULL) {
		cout << "内存不足" << endl;
		return;
	}
	int i = left, j = mid + 1, k = 0;
	while (i <= mid && j <= right)
		res[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
	while (i <= mid)
		res[k++] = arr[i++];
	while (j <= right)
		res[k++] = arr[j++];
	//将排好序的res覆盖arr,注意下标不同,但一一对应
	for (int m = left, n = 0; m <= right; m++, n++)
		arr[m] = res[n];
	//释放res
	delete []res;
	res = NULL;
}
void MergeSort(int *arr, int left, int right) {
	if (left == right) //递归出口
		return;
	int mid = (left + right) / 2;
	//分解
	MergeSort(arr, left, mid);
	MergeSort(arr, mid + 1, right);
	//有序合并
	Merge(arr, left, mid, right);
}
int main() {
	int test[] = { 2,4,1,6,5,8,9,0 };
	Print(test, 8);
	MergeSort(test, 0, 7);
	Print(test, 8);
}
4.归并排序扩展–小和问题 1.补充–vector使用详解
#include
#include
using namespace std;
int main() {
	//构造及初始化
	
	vector test1{ 1,2,3,4,5 };
	vector test2(5, 0);

	//迭代器及遍历容器元素
	//注意 auto自动推断数据类型,但使用时必须初始化
	// auto b = v.begin(), c = v.end(); b表示v的第一个元素 c表示v尾元素的下一个位置
	//v.cbegin()和v.cend()是C++11新增的,它们返回一个const的迭代器,不能用于修改元素,建议使用
	for (auto it = test1.cbegin(); it != test1.cend(); it++)
		cout << *it << " ";
	cout << endl;

	//添加元素,不能用下标形式添加元素,比如v[len]=3
	//v.push_back负责把一个值当成vector对象的尾元素"压到(push)"vector对象的"尾端(back)"
	int add;
	while (cin >> add)  //输入ctrl+z结束输入
		test1.push_back(add);
		//v.emplace_back():在容器尾部添加一个元素,调用构造函数原地构造,不触发拷贝构造和移动构造,比push_back()更加高效
		//test1.emplace_back(add);
	//显示
	for (auto it = test1.cbegin(); it != test1.cend(); it++)
		cout << *it << " ";
	cout << endl;
	
	//与添加对应的--删除操作
	//v.pop_back();//删除最后一个元素

	//获取元素
	//v.at(int idx);//返回索引idx所指的数据
	//v.front();//返回容器中第一个数据元素
	//v.back();//返回容器中最后一个数据元素

	//其它常用函数
	//v.size();//返回容器中的元素个数
	//v.resize(int num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置;如果容器变短,则末尾超出容器长度的元素被删除
	//v.clear();//删除容器中所有元素
}
2.小和问题

解题思路:递归+归并

1.使用new动态开辟数组版本
//使用new动态开辟数组版本
#include
using namespace std;
int MergeSum(int *arr, int left, int mid, int right) {
	int *temp = new int[right - left + 1]; //动态开辟和arr等规模的数组
	int i = left, j = mid + 1, k = 0, res = 0;
	//以下操作,在计算merge小和同时,保证了让arr有序
	while (i <= mid && j <= right) {
		res += (arr[i] < arr[j] ? arr[i] * (right - j + 1) : 0);
		temp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
	}
	while (i <= mid)
		temp[k++] = arr[i++];
	while(j <= right)
		temp[k++] = arr[j++];
	//用temp更新arr
	for (int t = 0; t < (right - left + 1); t++)
		arr[t + left] = temp[t];
	return res;
}
int SmallSum(int *arr, int left, int right) {
	if (left == right)
		return 0;  //递归出口,只有一个元素,没有小和
	int mid = left + ((right - left) >> 1);
	return SmallSum(arr, left, mid) + SmallSum(arr, mid + 1, right) + MergeSum(arr, left, mid, right);
}
int main() {
	int test[] = { 4,7,2,5,1 };
	cout << SmallSum(test, 0, 4);
}
2.使用vector动态开辟数组版本
//使用vector动态开辟数组版本
#include
#include
using namespace std;
int MergeSum(vector &v, int left, int mid, int right) {
	vector temp(right - left + 1); //动态开辟和arr等规模的数组
	int i = left, j = mid + 1, k = 0, res = 0;
	//以下操作,在计算merge小和同时,保证了让arr有序
	while (i <= mid && j <= right) {
		res += (v[i] < v[j] ? v[i] * (right - j + 1) : 0);
		temp[k++] = v[i] < v[j] ? v[i++] : v[j++];
	}
	while (i <= mid)
		temp[k++] = v[i++];
	while(j <= right)
		temp[k++] = v[j++];
	//用temp更新arr
	for (int t = 0; t < (right - left + 1); t++)
		v[t + left] = temp[t];
	return res;
}
int SmallSum(vector &v, int left, int right) {
	if (left == right)
		return 0;  //递归出口,只有一个元素,没有小和
	int mid = left + ((right - left) >> 1);
	return SmallSum(v, left, mid) + SmallSum(v, mid + 1, right) + MergeSum(v, left, mid, right);
}
int main() {
	vector test{ 4,7,2,5,1 };
	cout << SmallSum(test, 0, 4);
}
5.归并排序扩展–逆序对问题

#include
using namespace std;
int MergeCount(int *arr, int left, int mid, int right) {
	int *temp = new int[right - left + 1]; //动态开辟和arr等规模的数组
	int i = left, j = mid + 1, k = 0, res = 0;
	//和小和问题的一些操作区别:保证temp逆序而不是升序;计算的是个数,不是值
	while (i <= mid && j <= right) {
		res += (arr[i] > arr[j] ? (right - j + 1) : 0);
		temp[k++] = (arr[i] > arr[j] ? arr[i++] : arr[j++]);
	}
	while (i <= mid)
		temp[k++] = arr[i++];
	while(j <= right)
		temp[k++] = arr[j++];
	//用temp更新arr
	for (int t = 0; t < (right - left + 1); t++)
		arr[t + left] = temp[t];
	return res;
}
int ReverseCP(int *arr, int left, int right) {
	if (left == right)
		return 0;  //递归出口,只有一个元素,没有逆序对
	int mid = left + ((right - left) >> 1);
	return ReverseCP(arr, left, mid) + ReverseCP(arr, mid + 1, right) + MergeCount(arr, left, mid, right);
}
int main() {
	int test[] = { 4,7,2,5,1 };
	cout << ReverseCP(test, 0, 4);
}
6.快速排序引例–荷兰国旗问题

1.问题1
//问题1:分成 <=num, >num 的两部分
void SplitTwoPart(int *arr, int len, int num) {
	int left = -1; //记录左区
	int i = 0; //用于记录当前下标
	while (i < len) {
		if (arr[i] > num)
			i++;
		else {
			if (left + 1 != i)
				Swap(arr[left + 1], arr[i]);
			left++; //扩左区
			i++;
		}
	}
}
2.问题2
//问题2:分成 num 的三部分
void SplitThreePart(int *arr, int len, int num) {
	int left = -1, right = len; //记录左区和右区
	int i = 0; //记录当前下标
	while (i < right) { //进入右区内则已经达到要求
		if (arr[i] == num)
			i++;
		else if (arr[i] > num) { //和右区前一个交换,扩右区
			if (i != right - 1)
				Swap(arr[i], arr[right - 1]);
			right--;  //扩右区
		}
		else { //和左区后一个交换,扩左区,i++
			if (i != left + 1)
				Swap(arr[i], arr[left + 1]);
			left++;
			i++;
		}
	}
}
3.完整代码及测试
//荷兰国旗问题
#include
using namespace std;
//数组打印函数
void Print(int *arr, int len) {
	for (int i = 0; i < len; i++)
		cout << arr[i] << ' ';
	cout << endl;
}
//两数交换函数
void Swap(int &a, int &b) {
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
}
//问题1:分成 <=num, >num 的两部分
void SplitTwoPart(int *arr, int len, int num) {
	int left = -1; //记录左区
	int i = 0; //用于记录当前下标
	while (i < len) {
		if (arr[i] > num)
			i++;
		else {
			if (left + 1 != i)
				Swap(arr[left + 1], arr[i]);
			left++; //扩左区
			i++;
		}
	}
}
//问题2:分成 num 的三部分
void SplitThreePart(int *arr, int len, int num) {
	int left = -1, right = len; //记录左区和右区
	int i = 0; //记录当前下标
	while (i < right) { //进入右区内则已经达到要求
		if (arr[i] == num)
			i++;
		else if (arr[i] > num) { //和右区前一个交换,扩右区
			if (i != right - 1)
				Swap(arr[i], arr[right - 1]);
			right--;  //扩右区
		}
		else { //和左区后一个交换,扩左区,i++
			if (i != left + 1)
				Swap(arr[i], arr[left + 1]);
			left++;
			i++;
		}
	}
}
//测试
int main() {
	int test1[] = { 8,5,4,2,7,2,6,4,1 };
	int test2[] = { 8,5,4,2,7,2,6,4,1 };
	int len = (sizeof(test1) / sizeof(test1[0]));
	Print(test1, len);

	cout << "问题1--分成两区--结果:" << endl;
	SplitTwoPart(test1, len, 4);
	Print(test1, len);

	cout << "问题2--分成三区--结果:" << endl;
	SplitThreePart(test2, len, 4);
	Print(test2, len);
}
7.快速排序

#include
using namespace std;
//数组打印函数
void Print(int *arr, int len) {
	for (int i = 0; i < len; i++)
		cout << arr[i] << ' ';
	cout << endl;
}
//快速排序
void QuickSort(int *arr, int left, int right) {
	if (left >= right)
		return;
	int temp = arr[left]; //选择第一个数作为基准值
	int i = left, j = right;
	while (i < j) {
		while (itemp)
			j--;
		if(i
	int test[] = { 8,5,4,2,7,2,6,4,1 };
	Print(test, 9);
	QuickSort(test, 0, 8);
	Print(test, 9);
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/862655.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号