排序(4)——快速排序

news2024/11/28 4:37:22

五、快速排序

1.简介

        快速排序是Hoare于1962年提出的,主要采取了分治的思想。快速排序首先确定一个基准值,然后以这个选出的基准值为标准,将整个数组进行按大小进行区分,使得小于该基准值的位于其一侧,大于基准值的位于另一侧。这样就将整个数组分为了小于标准和大于标准两部分,再对每一部分进行同样的处理方法由此完成排序。

        快速排序在每一趟的执行中,因为基准值左侧均是小于,右侧都是大于,所以一定会确定基准值的位置,从而使得分治的下一步会分别处理左侧右侧两部分而不再包含该基准值,所以递归可以顺利进行下去。

        快速排序之所以能命名为快速排序,就说明其排序就是主打个快速。快速排序在处理完当前基准值后再处理左右部分,可以看出其实际上就是链式二叉树中所介绍的前序遍历的过程,大家可以慢慢领悟。

2.思路与代码

        快速排序一般常用的有三种版本,分别是最初的Hoare版本,以及后世改进的挖坑法和前后指法。除此之外,针对快排中可能出现的影响效率的特殊情况,我们会做出一些小优化。以及最后我们会使用非递归完成快排的实现。

(1)快速排序基本形式(递归Hoare版本)

        假设a数组区间[begin,end]需要排序,要求begin<end(否则无需排序),我们首先需要确定基准值,一般会选择首元素即下标为begin的元素为基准值,然后开始对数组进行数据比较与处理,右找小左找大,相遇后与基准值交换。具体流程与分析如下:

        ①首先定义keyi=begin。这是确定基准值,我们使用下标来标识基准值而不采用key=a[begin],这是因为我们在最后涉及到交换,需要将基准值与另一位置的值进行交换。如果采取key=a[begin],相当于引入了一个变量key,在最后交换的时候我们仍需要找到基准值在数组的位置进行交换,而不是和key进行交换(因为key只是个变量,改变key的值并不会影响到数组中选定为基准值位置的值)。

        ②给定两个指针(实际是两个下标)left,right,分别从左侧begin和右侧end开始遍历处理数组数据,即left=begin,right=end。这里会有想法,既然基准值是begin处的值,那么能不能让left从begin+1开始处理,即left=begin+1?这是不可以的,因为left不只有找大与right交换的作用,left还担任着最后和基准值交换的作用。这就意味着left不可以随便指示,因为left最后需要基准值交换,left所指示的值交换后必然位于基准值位置或左侧,所以要求left所指示的值必须清楚可控地小于等于基准值,否则就会出现错误。而令left=begin+1明显将left拱手让给了一个未知值,如果left在一次遍历中不移动,那么这就会把这个位置值换到基准值左侧,这很明显是不允许的。

        ③右找小左找大。在前置工作都完成了之后,可以真正开始处理数组了,此时就采取右找小左找大的策略。让right指针从右开始自减,直到找到比基准值小的元素或者与left相遇;在right完成寻找后,left再动身从左开始自增,直到找到比基准值大的元素后者与right相遇。在二者都完成一次寻找之后,就将二者指向的元素进行交换,这个交换只右两种情况:a.较大值与较小值进行换位;b.left与right相遇,不发生交换(自己和自己交换)。当left与right相遇后我们便不再进行下一次寻找换位的处理,否则继续寻找再完成一组交换。

        ④将left位置的值与keyi位置的基准值交换。我们之所以现在能够无所顾虑的将二者交换,在前几步的处心积虑功不可没。[1]让left从begin开始进行寻找大数,使得left可以在不移动的情况下一定指向基准值自身。[2]处理数组的过程中是先让右找小,在让左找大,并且加入left<right的判断。这样的安排使得有如下几种情况:a.右找到小,左找到大——顺利交换;b.右找到小,左找不到大——左右重合与右指针找到的小数,与基准值发生合理的交换;c.右找不到小——右与左相遇在左指针,由于左还没有移动,所以左指针所指数据为上次与右指针交换的小数或基准值,与基准值的交换是合理的。

        有了这些限制,我们才可以保证left所指示的数一定可以与基准值产生的交换是合理的。

        ⑤在left与right自增自减的过程中,应该限制其只能在找到大数和小数时停止,换言之就是当遇见相等值时不停止,即a[right]>=a[keyi],a[left]<=a[keyi]下自减自增,这样是为了防止left与right同时找到两个与基准值相等的值而陷入死循环。

        明确思路后,于是我们终于可以写出递归形式Hoare版本的代码。

//快速排序(hoare版本)
void QuickSort_Hoare(int* a, int begin, int end)
{
	//需要对[begin,end]进行排序
	if (begin >= end)
	{
		return;
	}
	int keyi = begin; //如果设置key=a[begin],在后续交换时穿参需要变化,不可以是&key
	int left = begin, right = end; //如果left从begin+1开始,对于如1 2 3 4 5序列,途中left不移动,但是keyi和left的交换依旧会发生
	while (left < right)
	{
		while (left < right && a[right] >= a[keyi]) //判断条件需要left<right,防止越界访问
		{
			right--;
		}
		while (left < right && a[left] <= a[keyi]) //判断时需要<=或>=,防止对于如6 1 2 6 5 6 9 8有重复数字序列陷入死循环
		{
			left++;
		}
		swap(&a[left], &a[right]);
	}
	swap(&a[left], &a[keyi]);
	keyi = left;
	//[begin,keyi-1] keyi [keyi+1,end]
	QuickSort_Hoare(a, begin, keyi - 1);
	QuickSort_Hoare(a, keyi + 1, end);
}

(2) 快速排序优化

[1]小区间优化

        快排的分治递归思想,使得处理排序问题实际上是一个二叉树形式的问题。对于一颗二叉树,我们知道其最后一层结点数量要占到整棵树的结点数量的50%还要多,倒数第二层则是占到了所有结点的25%以上,倒数第三层则是12.5%左右。于是我们发现倒数三层的总和占到了接近90%的数量,而每个结点背后都是一次递归调用。为了减少递归调用的开销,完全可以让结点靠下的部分排序使用其他类型的排序,这样相当于将树最后几层的结点砍去,这样处理递归出的小区间排序可以大大减小递归开销。

        但是当下编译器对于递归性能的优化是很棒的,几乎无需考虑递归的效率开销,所以这个优化了解到就好啦。

[2]三数取中

        在排序中,我们最理想的状态应该是每一次分治分开的两部分都是均分,这样可以使得效率最高,这种情况下结点数量我们可以在忽略拿出去的基准值的情况下进行估算。不考虑在递归分治中排除基准值所造成的结点数减少一个的变化,整个快排就是标准的二分,每次调用快排都需要遍历,而每一层恰好是整个数组所分割而成的不同组别,所以每一层的开销看成一个整体,每一层调用就是遍历整个数组,所以一层树的开销就是n。

        所以整体的开销就是层数*n,所以当下计算有多少层即可。因为是标准的二分,所以层数很明显的是log_2n,因此我们可以算出最佳情况的开销,也即时间复杂度为O(n*logn)

        但是在实际中很难有这么理想的情况。一旦我们选择了最小的或最大的极端数据,就会导致我们处理结束后基准值一侧元素很少甚至没有,而另一侧元素数量仅仅是整个数组减去几个元素,这种情况快排就不再“快乐”。顺序序列或者逆序序列正是这种很极端的序列,我们可以以同样的方法估计一下这种情况下的开销。

        每次调用后由于基准值一侧无数据,所以交给下次调用的数据量只能是本次处理的数据量减一。每次调用数据量减一,那么要处理完整个数组,意味着调用次数等于数据量。由此我们可以发现端倪,这种情况下开销就是n+(n-1)+(n-2)+\cdots +2+1的一个标准等差数列,这也就意味着其时间复杂度变为了O(n^2)

        铺垫了这么多,这都是基准值key取得不合理所导致的。为了一定程度避免这种极端情况(无法避免),我们采取三数取中的方案来更合理的选择基准值key。所谓三数取中就是对于一个区间 [begin,end]选择begin、end和(begin+end)/2三个位置的值进行比较,找到三者的中间数,让其作为key值。这样的话更有希望对整个区间进行二分,事实也证明这种方法是有效果的。

此处给出两种优化下的快排代码:

//快速排序--优化方案
int GetMidi(int* a, int begin, int end)
{
	int midi = (begin + end) / 2;
	//取begin,end,midi三者的中位数
	return a[begin] > a[end] ? (a[end] > a[midi] ? end : (a[begin] > a[midi] ? midi : begin)) : a[begin] > a[midi] ? begin : (a[end] > a[midi] ? midi : end);
}

void QuickSort_Hoare_Opt(int* a, int begin, int end)
{
	//需要对[begin,end]进行排序
	if (begin >= end)
	{
		return;
	}

//快速排序--优化1--小区间优化
//小区间优化:当所处理数据长度足够小时,使用其他更合适的排序方式处理,因为快排实际上类似于二叉树,小区间优化可以对树的最后几层进行剪枝,大大减小递归开销(因为编译器对递归优化很好,所以效果不明显)
	//*******************************************
	if (end - begin + 1 <= 3)
	{
		InsertSort(a + begin, end - begin + 1);
		return;
	}
	//*******************************************
	else
	{
//快速排序--优化2--三数取中
//三数取中:区间第一个,最后一个,中间三个位置数字相比,将三者的中位数作为key,这样使得每一次的递归分治尽量均分,提高处理效率
		//*******************************************
		int midi = GetMidi(a, begin, end);
		swap(&a[begin], &a[midi]);
		int keyi = begin;
		//*******************************************
		int left = begin, right = end;
		while (left < right)
		{
			while (left < right && a[right] >= a[keyi])
			{
				right--;
			}
			while (left < right && a[left] <= a[keyi])
			{
				left++;
			}
			swap(&a[left], &a[right]);
		}
		swap(&a[left], &a[keyi]);
		keyi = left;
		QuickSort_Hoare_Opt(a, begin, keyi - 1);
		QuickSort_Hoare_Opt(a, keyi + 1, end);
	}
}

(3)快速排序三种方法(递归)

        在写这三种方法前,我们可以将快排的核心部分封装成函数独立出去,这样我们写出方法的核心代码,再使用另一个我们的快排套壳(只有代码框架)即可。

//快速排序递归版
void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	//int keyi = Sort1_Hoare(a, begin, end);
	//int keyi = Sort2_Hole(a, begin, end);
	//int keyi = Sort3_Pointer(a, begin, end);
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}
 [1]Hoare版本

        Hoare版本我们在上面已经详细讲过,这里就不再赘述了。

//1.Hoare版本
//right找小,left找大,相遇后放入key
int Sort1_Hoare(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	swap(&a[begin], &a[midi]);
	int keyi = begin;

	int left = begin, right = end;
	while (left < right)
	{
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		swap(&a[left], &a[right]);
	}
	swap(&a[left], &a[keyi]);
	keyi = left;
	return keyi;
}
[2]挖坑法

         挖坑法是Hoare版本的小改造,Hoare版本在左右指针均完成寻找后直接交换左右指针位置的值。挖坑法则是引入了一个“坑位”,实际上就是中间变量,当右指针完成寻找后就用其值“填充”坑位,左指针完成寻找后也如此。在寻找过程整个完成后,将之前存储的key值放入最后挖出的坑即可。本质就是引入了中间变量hole来记录交换位置,从而可以使左右指针完成寻找后即时交换,想必Hoare减少了一些处理的细节。

//2.挖坑法
//right找小,left找大,每次找到后即刻将key填入
int PartSort2(int* a, int left, int right)
{
	int keyi = GetMidi(a, left, right);
	swap(&a[left], &a[keyi]);
	int hole = left;
	int key = a[left];
	while (left < right)
	{
		while (left < right && a[right] >= key)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;
		while (left < right && a[left] <= key)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[hole] = key;
	return hole;
}
[3]前后指针法

        

         前后指针的方法改变了以往右指针向左左指针向右的遍历方式,而是同时从头开始向后遍历。靠前的指针cur标识着正在判断和基准值关系的元素,而prev则是指向左侧边界区间。可以将prev当做数组到cur为止基准值key位置的标识,而区间(prev,cur)则是所有应该放在基准值右侧的元素。

        通过cur的判断从而改变prev的大小,当cur所示位置值大于等于基准值key时,说明key当前位置(prev)满足左小右大的原则,因此prev无需变动,cur自增指向下一个待判断。另一种理解方式,当a[cur]>=key证明cur当前位置的值能够存在于区间(prev,cur)中,于是只需要cur自增即可。

        当cur所示位置小于基准值key时,说明cur位置的值应该位于key左侧,prev指向的是key所在位置,因为要将cur位置的值置于key左侧,所以要首先腾个位置出来,于是prev自增向右移动一位,因为右移了一位所以prev指向的值一定是右侧只,于是可以放心将prev和cur位置的值进行交换,完成后cur自增即可。另一种理解方式则是cur当前位置的值不应该在区间(prev,cur)中,于是需要prev自增后和prev换位,相当于区间边界后移为其腾空间,cur自增调整。

        完成所有元素调整后,将prev与key值(a[begin])交换即可完成单趟排序。

//3.前后指针法
//利用cur指针遍历整个数组,cur指向正在辨别的元素,prev指向左侧区间边界(也是key应该处在的位置),两个指针之间(prev,cur)是右侧分治的元素
//所以当cur遇到小于key的数据,需要将其放在prev的下一个位置,再挪动cur;遇到大于key的数据,则不必移动prev,只需要挪动cur即可
int Sort3_Pointer(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	swap(&a[midi], &a[begin]);

	int key = a[begin];
	int prev = begin, cur = begin + 1;
	while (cur <= end)
	{
		//if (a[cur] < key)
		//{
		//	prev++;
		//	swap(&a[prev], &a[cur]);
		//}
		if (a[cur] < key && ++prev != cur)
		{
			swap(&a[prev], &a[cur]);
		}
		cur++;
	}
	swap(&a[prev], &a[begin]);
	return prev;
}

(4)快速排序非递归方案

        递归虽然用的爽,但是耐不住它具有致命弱点,即有可能会栈溢出。因为递归是在栈中不断开辟空间,而栈空间是有限的,所以也就注定递归排序没有办法处理一些很大规模的数据,于是我们需要创造快排的非递归版本。

        递归改非递归一般会用两种方法:循环和栈。此处我们处理快排这种前序遍历递归改非递归,一般会使用栈的方法。

        递归也是通过调用函数,开辟栈帧实现同一段代码的不同参数实现,于是我们完全可以将所需要的参数放在我们自己开的栈数据结构中,循环同样的代码来实现递归的效果。因为快排处理需要指明边界的参数,所以我们约定存数据先右后左,那么取数据就刚刚相反。这样利用栈的数据结构进行同一段代码不同参数,即可成功取代递归方案。

void QuickSort1(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int mid = PartSort1(a, left, right);
	//[left,mid-1] mid [mid+1,right]
	QuickSort1(a, left, mid - 1);
	QuickSort1(a, mid + 1, right);
}
void QuickSort2(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int mid = PartSort2(a, left, right);
	//[left,mid-1] mid [mid+1,right]
	QuickSort2(a, left, mid - 1);
	QuickSort2(a, mid + 1, right);
}
void QuickSort3(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int mid = PartSort3(a, left, right);
	//[left,mid-1] mid [mid+1,right]
	QuickSort3(a, left, mid - 1);
	QuickSort3(a, mid + 1, right);
}
//快速排序非递归版
void QuickSortNonR(int* a, int begin, int end)
{
	ST s;
	STInit(&s);

	//将待处理区间左右端点存入栈中,以两个为一组。存:先右后左;取:先左后右
	STPush(&s, end);
	STPush(&s, begin);
	while (!STEmpty(&s))
	{
		int begin = STTop(&s);
		STPop(&s);
		int end = STTop(&s);
		STPop(&s);
		//int keyi = PartSort1(a, begin, end);
		//int keyi = PartSort2(a, begin, end);
		//int keyi = PartSort3(a, begin, end);
		if (keyi - 1 > begin)
		{
			STPush(&s, keyi - 1);
			STPush(&s, begin);
		}
		if (keyi + 1 < end)
		{
			STPush(&s, end);
			STPush(&s, keyi + 1);
		}
	}
	STDestroy(&s);
}

3.复杂度与稳定性分析

(1)时间复杂度

        快排我们在三数取中部分已经分析过了其时间复杂度,完美的二分结构是最佳序列,时间复杂度为O(n*logn)。顺序逆序是最坏序列,时间复杂度退化为O(n^2)

        所以一般认为快排的时间复杂度为O(n*logn)

(2)空间复杂度

        快排涉及到递归,所以要看其递归深度。同理,完美的二分结构是最佳序列,空间复杂度为O(logn)。顺序逆序是最坏序列,空间复杂度为O(n)

        一般认为快排的空间复杂度为O(logn)

(3)稳定性

       快速排序是不稳定的。

       快速排序中数据存在大量相互交换,无论怎样限制其相对位置总是不可控的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1425580.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超越GPT4 Turbo?科大讯飞发布星火认知大模型3.5版本

简介 1月30日&#xff0c;科大讯飞举行星火认知大模型V3.5升级发布会。科大讯飞董事长刘庆峰、研究院院长刘聪正式发布基于首个全国产算力训练的讯飞星火V3.5&#xff0c;七大核心能力全面提升。 功能展示多模交互 多模理解&#xff1a;上传图片素材&#xff0c;大模型完成识…

C++/数据结构:二叉搜索树的实现与应用

目录 一、二叉搜索树简介 二、二叉搜索树的结构与实现 2.1二叉树的查找与插入 2.2二叉树的删除 2.3二叉搜索树的实现 2.3.1非递归实现 2.3.2递归实现 三、二叉搜索树的k模型和kv模型 一、二叉搜索树简介 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0…

vue——实现多行粘贴到table事件——技能提升

最近在写后台管理系统时&#xff0c;遇到一个需求&#xff0c;就是要从excel表格中复制多行内容&#xff0c;然后粘贴到后台系统中的table表格中。 如下图所示&#xff1a;一次性复制三行内容&#xff0c;光标放在红框中的第一个框中&#xff0c;然后按ctrlv粘贴事件&#xff0…

路由备份聚合排错

目录 实验拓扑图 实验要求 实验排错 故障一 故障现象 故障分析 故障解决 故障二 故障现象 故障分析 故障解决 故障三 故障现象 故障分析 故障解决 故障四 故障现象 故障分析 故障解决 故障五 故障现象 故障分析 故障解决 实验拓扑图 实验要求 按照图示配…

Typora导出html文件图片自动转换成base64

Typora导出html文件图片自动转换成base64 一、出现问题二、解决方案三、编码实现3.1.创建Java项目3.2.代码3.3.打包成Jar包 四、如何使用endl 一、出现问题 typora 导出 html 的时候必须带有原图片&#xff0c;不方便交流学习&#xff0c;文件太多显得冗余&#xff0c;只有将图…

Docker中安装MySql的遇到的问题

目录 一、mysql查询中文乱码问题 1. 进入mysql中进行查看数据库字符集 2. 修改 my.cnf 中的配置 3. 重启mysql容器&#xff0c;使得容器重新加载配置文件 4. 测试结果 二、主从同步中遇到的问题 2.1 Slave_IO_Running:Connecting 的解决方案 1. 确定宿主机防火墙开放my…

node.js与express.js创建项目以及连接数据库

搭建项目 一、技术准备 node版本&#xff1a;16.16.0 二、安装node成功后&#xff0c;安装express,命令如下&#xff1a; npm install -g express 或者&#xff1a; npm install --locationglobal express 再安装express的命令工具&#xff1a; npm install --location…

PVE安装后报错:NO IOMMU Detected解决办法

&#xff11;、首先在BIOS中确定图形界面卡&#xff0c;打开了VT-D功能。 &#xff12;、修改grub vim /etc/default/grub 找到&#xff1a;GRUB_CMDLINE_LINUX_DEFAULT"quiet" 然后修改为 GRUB_CMDLINE_LINUX_DEFAULT"quiet intel_iommuon" 3、使用命…

巨人踏步,港口自动驾驶提速向前打开行业新空间

按照吞吐量排名&#xff0c;全世界最大的50个港口&#xff0c;中国占了29个。在中国的港口和码头上&#xff0c;一场进化正在发生&#xff1a;人在这个生态中占的比重越来越少&#xff0c;技术接管的要素正在越来越多。像是最具代表性的全球综合自动化程度最高的码头——上海洋…

笔记本电脑Win11重装系统教程

在笔记本电脑Win11操作过程中&#xff0c;用户如果遇到很严重的系统问题&#xff0c;就可以重新正常的Win11系统&#xff0c;快速解决Win11系统问题。但是&#xff0c;部分新手用户不知道不知道如何操作才能给Win11笔记本电脑重装系统&#xff1f;以下小编分享笔记本电脑Win11重…

深入理解TCP网络协议(2)

目录 1.TCP的状态转换 1.1 LISTEN状态和ETABLISHED状态 ​编辑2.TIME_WAIT 和 CLOSE_WAIT 2.滑动窗口 1.TCP的状态转换 我们通过上图可以看到TCP状态转换的详细过程.在实际开发的过程中,我们不需要了解的这么细致.为了方便大家的理解,我挑几个主要的状态来给大家聊一下 1.…

易语言系列学习1

通过本文章你会学习到 如果 如果真 获取编辑框内容 关闭本程序 监听按键让它等价于点击某个按钮 运算&#xff1a;或 且 非&#xff08;注意中间要有一个空格&#xff0c;否则会报错&#xff09; 效果 .版本 2.程序集 窗口程序集_启动窗口.子程序 _按钮2_被单击. 如果真 (编…

docker-学习-4

docker学习第四天 docker学习第四天1. 回顾1.1. 容器的网络类型1.2. 容器的本质1.3. 数据的持久化1.4. 看有哪些卷1.5. 看卷的详细信息 2. 如何做多台宿主机里的多个容器之间的数据共享2.1. 概念2.2. 搭NFS服务器实现多个容器之间的数据共享的详细步骤2.3. 如果是多台机器&…

Vue学习笔记(一)JS导入导出

Vue学习笔记&#xff08;一&#xff09;JS导入导出 js文件-导出、批量导出、默认导出 showMessage.js export function simpleMessage(msg){console.log(msg); }export function complexMessage(msg){console.log(new Date()": "msg); }// 批量导出 // export {si…

[工具探索]Safari 和 Google Chrome 浏览器内核差异

最近有些Vue3的项目&#xff0c;使用了safari进行测试环境搞开发&#xff0c;发现页面存在不同程序的页面乱码情况&#xff0c;反而google浏览器没问题&#xff0c;下面我们就对比下他们之间的差异点&#xff1a; 日常开发google chrome占多数&#xff1b;现在主流浏览器 Goog…

stm32--simulink开发之--timer的学习,硬件输入中断,触发事件,STM32通用定时器之输出比较模式与PWM模式(重要理解)

下面三个模块&#xff0c;一个比一个高级&#xff0c;当然使用是越来越简单 STM32F4xx系列控制器有2个高级控制定时器、10个通用定时器和2个基本定时器(推荐学习) 1&#xff0c;第一个模块&#xff1a;Timer 浅层理解&#xff1a;计数&#xff0c;不停的触发 Starts timer co…

Nginx简单阐述及安装配置

目录 一.什么是Nginx 二.Nginx优缺点 1.优点 2.缺点 三.正向代理与反向代理 1.正向代理 2.反向代理 四.安装配置 1.添加Nginx官方yum源 2.使用yum安装Nginx 3.配置防火墙 4.启动后效果 一.什么是Nginx Nginx&#xff08;“engine x”&#xff09;是一个高性能的HTTP…

【百度Apollo】探索创新之路:深入了解Apollo开放平台

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

vue3页面跳转产生白屏,刷新后能正常展示的解决方案

可以依次检查以下问题&#xff1a; 1.是否在根组件标签最外层包含了个最大的div盒子包裹内容。 2.看看是否在template标签下面直接有注释&#xff0c;如果有需要把注释写到div里面。&#xff08;即根标签下不要直接有注释&#xff09; 3.在router-view 中给路由添加key标识。 …

通过Netbackup恢复Oracle备份实操手册

1、系统环境描述 1 2、恢复前数据备份 2 2.1 在NBU上执行一次完整的备份 2 2.2 查看ORACLE的备份集 3 2.2.1在备份客户端上查看备份集 3 2.2.2在备份服务器netbackup上查看客户端备份集 4 3、本机恢复方法 5 3.1丢失SPFILE文件恢复方法 5 3.2丢失CONTROLFILE文件恢复方…