首页 > 编程语言 >归并排序、快速排序——左神数据结构与算法Day2学习笔记C++版本(持续更新)

归并排序、快速排序——左神数据结构与算法Day2学习笔记C++版本(持续更新)

时间:2024-03-14 21:33:25浏览次数:27  
标签:std arr int 复杂度 Day2 mid C++ 数组 排序

递归行为

        利用递归求整个数组的最大值,代码如下。

int find_Max(int a[], int L, int R)
{
    if (L == R)
    {
        return a[L];
    }
    int mid = L + ((R - L) >> 1);//mid是数组的中点
    int leftMax = find_Max(a, L, mid);
    int rightMax = find_Max(a, mid+1, R);
    return std::max(leftMax, rightMax);
}

        类似一个二叉树,不知道的结果压栈继续算,已经知道的结果从栈里弹出。

递归行为的时间复杂度估计:

        只要是满足子问题等规模的递归,都可以用master公式计算时间复杂度。

master公式:T(N)=a*T(N/b)+O(N^d),T(N)指的是母问题的数据量是N级别的,a是子问题的调用次数,b是子问题的规模(这个问题中每个子问题的规模都一样),O(N^d)是除去子问题的调用之外,剩下的过程的时间复杂度。find_Max就满足master公式,find_Max 的T (N)=2*T(N/2)+O(1)。

        知道master公式的a、b、d三个参数后,时间复杂度如何求呢?

时间复杂度=

O(N^d),若logb(a) < d;

O(N^(logb(a))) ,若logb(a) > d;

O(N^d*logN), 若logb(a) = d;

归并排序:

        先把待排序数组分成等大的左右两个子数组,然后分别将左右数组排序(递归调用),最后将左右两个数组按序合在一起后拷贝给原数组,完成排序。以下程序中的mergeSort()为归并排序,merge()的功能为将分开的左右两个数组按序合在一起后拷贝给原数组。代码如下:

#include<iostream>
#include<vector>
void merge(std::vector<int>& arr, int L, int mid, int R);
void mergeSort(std::vector<int>& arr, int L, int R) 
{
    if (L == R) {
        return;
    }
    int mid = L + ((R - L) >> 1);

    mergeSort(arr, L, mid);
    mergeSort(arr, mid + 1, R);
    merge(arr, L, mid, R);
}
void merge(std::vector<int>& arr, int L, int mid, int R)
{
    std::vector<int> help(R - L + 1);
    int n1 = L;
    int n2 = mid + 1;
    int i = 0;

    while (n1 <= mid && n2 <= R)
    {
        help[i++] = arr[n1] < arr[n2] ? arr[n1++] : arr[n2++];
    }
    while (n1 <= mid)
    {
        help[i++] = arr[n1++];
    }
    while (n2 <= R)
    {
        help[i++] = arr[n2++];
    }
    for (i = L; i <= R; i++)
    {
        arr[i] = help[i - L];
    }

}
int main() {
    std::vector<int> arr = { 12, 11, 13, 5, 6, 7,5,1,2,3,8,2,35,3 };
    int n = (int)arr.size();

    mergeSort(arr, 0, n - 1);

    std::cout << "排序后的数组:";
    for (int i = 0; i < n; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

归并排序的时间复杂度:应用master公式:T (N)=2*T(N/2)+O(N),a=2,b=2,d=1,logb(a)=d,时间复杂度为O(N*logN)。

归并排序的额外空间复杂度:O(N)。

归并排序时间复杂度较好的原因:没有浪费比较行为,每次比较都产生了有序。

归并排序的扩展问题:

1.小和问题:在一个数组中,每一个数左边比当前的数小的数累加起来,叫做这个数组的小和。求一个数组的小和。代码如下:

#include<iostream>
#include<vector>
int merge(std::vector<int>& arr, int L, int mid, int R);
int mergeSort(std::vector<int>& arr, int L, int R)
{
	if (L == R) {
		return 0;
	}
	int mid = L + ((R - L) >> 1);

	return     mergeSort(arr, L, mid) + mergeSort(arr, mid + 1, R) + merge(arr, L, mid, R);
}
int merge(std::vector<int>& arr, int L, int mid, int R)
{
	int small_sum = 0;
	std::vector<int> help(R - L + 1);
	int n1 = L;
	int n2 = mid + 1;
	int i = 0;

	while (n1 <= mid && n2 <= R)
	{
		small_sum += arr[n1] < arr[n2] ? (R - n2 + 1) * arr[n1] : 0;
		help[i++] = arr[n1] < arr[n2] ? arr[n1++] : arr[n2++];
	}
	while (n1 <= mid)
	{
		help[i++] = arr[n1++];
		
	}
	while (n2 <= R)
	{
		help[i++] = arr[n2++];
	}
	for (i = L; i <= R; i++)
	{
		arr[i] = help[i - L];
	}
	return small_sum;
}
int main() {
	std::vector<int> arr = {1, 4, 5};
	int n = (int)arr.size();
	int small_sum = mergeSort(arr, 0, n - 1);

	std::cout << "排序后的数组:";
	for (int i = 0; i < n; i++) {
		std::cout << arr[i] << " ";
	}
	std::cout << std::endl;
	std::cout << "小和等于:" << small_sum << std::endl;
	return 0;
}

2.逆序对问题:在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对,求逆序对的数量。

逆序对问题和上面的小和问题是等效的。只不过小和问题是左边比右边的数小,而逆序对问题则相反。

快速排序

        先解决荷兰国旗问题,再递归。时间复杂度为O(N*logN)。 
        荷兰国旗问题:给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。额外空间复杂度0(1),时间复杂度O(N)。

快速排序的代码如下:

int* partition(int* arr, int L, int R)
{
	int less = L - 1;
	int more = R;
	int* a = new int[2];
	while (L < more){
		if (arr[L] < arr[R]){
			std::swap(arr[++less], arr[L++]);
		}
		else if (arr[L] > arr[R]){
			std::swap(arr[--more], arr[L]);
		}
		else{
			L++;
		}
	}
	std::swap(arr[more], arr[R]);
	a[0] = less + 1;
	a[1] = more;
	return a;
}
void quickSort(int* arr, int L, int R)
{
	if (L < R) {
		std::swap(arr[rand() % (R - L + 1) + L], arr[R]);
		int* a = partition(arr, L, R);
		quickSort(arr, L, a[0] - 1);
		quickSort(arr, a[1] + 1, R);
	}
}

标签:std,arr,int,复杂度,Day2,mid,C++,数组,排序
From: https://blog.csdn.net/2301_79931971/article/details/136690345

相关文章

  • C++并发编程:线程池学习
    文章目录一、线程池的概念二、线程池的设计三、线程池的实现1、ThreadPool声明2、线程创建3、添加任务4、ThreadPool析构四、相关知识点1、emplace_back和push_back2、typenamestd::result_of<F(Args...)>::type3、std::packaged_task<return_type()>4、函数模板和......
  • LeetCode题练习与总结:搜索旋转排序数组
    一、题目整数数组nums按升序排列,数组中的值互不相同。在传递给函数之前,nums在预先未知的某个下标k(0<=k<nums.length)上进行了旋转,使数组变为[nums[k],nums[k+1],...,nums[n-1],nums[0],nums[1],...,nums[k-1]](下标从0开始计数)。例如,[0,1,2,4,5,6,7]......
  • C/C++ vscode 配置
    一、由于vscode本身不带有编译器,需要下载MinGW编译器 打开网站:MinGW-w64-for32and64bitWindows-Browse/mingw-w64/mingw-w64-releaseatSourceForge.net下载x86_64-win32-seh版本下载后,解压缩,把解压缩后的文件剪切奥C:\ProgramFiles把路径C:\ProgramFiles......
  • LeetCode题练习与总结:在排序数组中查找元素的第一个和最后一个位置
    一、题目给你一个按照非递减顺序排列的整数数组nums,和一个目标值target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target,返回 [-1,-1]。你必须设计并实现时间复杂度为 O(logn) 的算法解决此问题。二、解题思路1.查找起始位置:使......
  • C++函数模板的重载
    C++模板当需要对不同的类型使用同一种算法(同一个函数体)时,为了避免定义多个功能重复的函数,可以使用模板。然而,并非所有的类型都使用同一种算法,有些特定的类型需要单独处理,为了满足这种需求,C++允许对函数模板进行重载,程序员可以像重载常规函数那样重载模板定义。我们定义了Swap(......
  • C++ error C2143: 语法错误: 缺少“;”(在“*”的前面)
    errorC2143编译错误但是,我在官网的例子上没有找到我所遇见的问题!在此记录一下,问题代码如下:1classtestA1;2classworkclass3{4public:5explicitworkclass();6virtual~workclass();7private:8intM_INT;9......
  • c++面试必问20题
    引用为什么不能修改引用关系?什么是重载this指针如何在类中出现的?类中的函数存放在代码区,所有对象访问的成员函数都是同一份代码,当不同对象调用同一个成员函数时,通过this区分在成员函数内修改的是哪个对象的成员变量this指针是否可以修改?不可以,如果修改了this就无法在函数......
  • C++动态数组
    #include<iostream>usingnamespacestd;intmain(){ intt,i=0,j=0; cin>>t; char*pc=nullptr;//初始化 int*pi=nullptr;//初始化 float*pf=nullptr;//初始化 intsum=0; intFLAG=0; while(FLAG<t) { charch; cin>>......
  • Java中的Map集合如何根据key值排序?
    Java中的Map集合如何根据key值排序(HashMap<String,Object>)?Map集合的键(key)默认是按照它们的hashCode排序的,这在有时间不符合业务排序。如果你想要根据Map的key值进行排序,一般以下有几种方法可以实现。方法一:使用TreeMap使用TreeMap类,它会自动根据key的自然顺序或自定义比较器......
  • 经典排序算法回顾:
    排序算法有非常多,应用也非常多,在各种笔试面试中也常常出现,所以现在就来复习一下相关的排序算法吧!下面会介绍多种排序算法,在此之前先说一下,排序算法的评价主要有以下几个方面:排序算法的时间复杂度;排序算法的空间复杂度;排序算法的稳定性其中前两个是老生常谈了,基本提到算法都会考虑......