【C++版】排序算法详解

news2024/11/15 21:47:20

目录

直接插入排序

希尔排序

选择排序

冒泡排序

堆排序 

快速排序

hoare法

挖坑法

 前后指针法

 非递归版本

 快速排序中的优化

归并排序

递归版本

非递归版本

计数排序

 总结


直接插入排序

直接插入排序的思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

其实我们在打牌的时候就是运用了这种插入的思想


 

动图演示

步骤

  1.  从第一个元素开始,可以认为这个元素是有序的序列
  2. 遍历下一个元素,往这个有序的序列进行插入
  3. 从后往前扫描这个有序序列,如果待插入的元素小于这个有序序列中的元素,就将这个有序序列的元素移到下一位,直到遇到比这个待插入元素小的数据就停下来,将这个元素插入到这个数据的下一个位置。

代码实现: 

//直接插入排序—时间复杂度O(N^2)
void InsertSort(vector<int> &v, int n)
{
	//end只用到n-2位置即可
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int tmp = v[end + 1];
		while (end >= 0)
		{
			if (tmp < v[end])
			{
				v[end + 1] = v[end];
				end--;
			}
			else
			{
				break;
			}
		}
		v[end + 1] = tmp;
	}
}

希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数(gap),把待排序文件中所有记录分成多个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,取重复上述分组和排序的工作。当gap == 1时,所有记录在同一组内的数已经排好序,最后再来个直接插入排序,那么排序就完成了。

说白了希尔排序其实就是在直接插入排序的基础之上先给这组数分组做预排序,让这组数据接近有序,最好再用直接插入排序的思想,将排序完成。因为直接插入排序在一组数接近有序的情况下效率是非常高的。

在进行预排序的时候gap的选择很关键,太大了使数据接近有序的效果不行,太小了又浪费效率。所以可以参考下面的方法。

《数据结构-用面相对象方法与C++描述》--- 殷人昆

但是我这里还是用了gap = gap / 3 + 1这种方法,预排序完成的更快。

代码实现: 

//希尔排序
void ShellSort(vector<int>& v, int n)
{
	//gap > 1时是预排序
	//gap == 1时直接插入排序
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = v[end + gap];
			while (end >= 0)
			{
				if (tmp < v[end])
				{
					v[end + gap] = v[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			v[end + gap] = tmp;
		}
	}
}

选择排序

选择排序的思想是:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
选择排序在众多排序算法中,效率并不算好,时间复杂度为O(N^2)无论在最好还是最坏的情况下都是一样的,所以在实际情况下,很少人会使用它。

动图演示

代码实现: 

代码上小优化,可以同时找最大和最小的数,使得排序更快

//选择排序—时间复杂度O(N^2)
void SelectSort(vector<int>& v, int n)
{
	int begin = 0, end = n - 1;
	int mini = begin, maxi = begin;
	while (begin < end)
	{
		for (int i = begin + 1; i < end; i++)
		{
			//找小的数
			if (v[i] < v[mini])
				mini = i;

			//找大的数
			if (v[i] > v[maxi])
				maxi = i;
		}
		Swap(v[begin], v[mini]);

		//如果begin和maxi重叠,那么需要修正maxi
		if (begin == maxi)
		{
			maxi = mini;
		}

		Swap(v[end], v[maxi]);
		begin++;
		end--;
	}
}

 冒泡排序

冒泡排序的基本思想是:每次比较两个相邻的元素,如果他们的顺序错误就把它们交换过来,就好像水底下的气泡一样逐渐向上冒。 

 动图演示

代码实现: 

//冒泡排序—时间复杂度O(N^2)
void BubbleSort(vector<int>& v, int n)
{
	for (int i = 0; i < n; i++)
	{
		int exchange = 0;
		for (int j = 1; j < n - i; j++)
		{
			if (v[j - 1] > v[j])
			{
				Swap(v[j - 1], v[j]);
				exchange = 1;
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

堆排序 

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据,是一个二叉树,在排序之前需要建堆,建堆的方法有两种,①建大堆,即根节点的元素要比孩子结点的元素要大。②建小堆,即根节点的元素比孩子结点的元素要小需要注意的是排升序要建大堆,排降序建小堆。

堆的性质

  1. 堆中某个节点的值总是不大于或不小于其父节点的值;
  2. 堆总是一棵完全二叉树。

 

 代码实现: 

//堆排序—建大根堆
void AdjustDown(vector<int> &v, int n, int root)
{
	int child = root * 2 + 1;
	while (child < n)
	{
		//选出左右孩子中大的那个
		if (child + 1 < n && v[child + 1] > v[child])//防止数组越界
		{
			child++;
		}
		//孩子和父亲比较
		if (v[child] > v[root])
		{
			Swap(v[child], v[root]);
			root = child;
			child = root * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(vector<int>& v, int n)
{
	for (int i = (n - 1 - 1 ) / 2; i >= 0; i--)
	{
		AdjustDown(v, n, i);//向下调整前提:左右子树必须是大/小堆
	}
	// o(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(v[0], v[end]);
		AdjustDown(v, end, 0);
		end--;
	}
}

 快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想是:任取待排序元素序列中的某元素作为基准数,按照该基准数将待排序集合分割成两子序列,左子序列中所有元素均小于基准数,右子序列中所有元素均大于基准数,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

要实现快速排序可以有以下几种方法:

hoare法

需要注意的是选择左边的数作为key值,那必须右边先开始走,右边作为key值,那必须左边先开始走。因为这样做才能保证左边和右边相遇的时候是比key值要小的。

下面的挖坑法也是这样。 

代码实现: 

void QuickSort(vector<int>& v, int begin, int end)
{
	//如果只剩一个值或者区间不存在直接返回
	if (begin >= end)
	{
		return;
	}

	int left = begin, right = end;
	int keyi = left;
	while (left < right)
	{
		//右边先走,找到比key小的就停下来
		while (left < right && v[right] >= v[keyi])
		{
			right--;
		}

		//左边走,找到比key大的就停下来
		while (left < right && v[left] <= v[keyi])
		{
			left++;
		}

		Swap(v[left], v[right]);
	}
	Swap(v[keyi], v[left]);
	keyi = left;
	//左区间
	QuickSort(v, begin, keyi - 1);
	//右区间
	QuickSort(v, keyi + 1, end);
}

挖坑法

代码实现: 

void QuickSort(vector<int>& v, int begin, int end)
{
	//如果只剩一个值或者区间不存在直接返回
	if (begin >= end)
	{
		return;
	}

	int left = begin, right = end;
	int key = v[begin];
	int piti = begin;
	while (left < right)
	{
		//右边先走,找到比key小的就停下来
		while (left < right && v[right] >= key)
		{
			right--;
		}

		v[piti] = v[right];
		piti = right;

		//左边走,找到比key大的就停下来
		while (left < right && v[left] <= key)
		{
			left++;
		}

		v[piti] = v[left];
		piti = left;
	}
	
	v[piti] = key;

	//左区间
	QuickSort(v, begin, piti - 1);
	//右区间
	QuickSort(v, piti + 1, end);
}

 前后指针法

代码实现: 

void QuickSort(vector<int>& v, int begin, int end)
{
	//如果只剩一个值或者区间不存在直接返回
	if (begin >= end)
	{
		return;
	}

	int prev = begin, cur = prev + 1;
	int keyi = begin;

	while (cur <= end)
	{
		if (v[cur] < v[keyi] && ++prev != cur)
			Swap(v[prev], v[cur]);

		cur++;
	}
	Swap(v[prev], v[keyi]);
	keyi = prev;

	//左区间
	QuickSort(v, begin, keyi - 1);
	//右区间
	QuickSort(v, keyi + 1, end);
}

 非递归版本

递归的问题,在极端场景下如果深度太深,会出现栈溢出,所以我们要改成非递归版本

我这里就用个栈来模拟递归过程,当然你用个队列来实现也是可以的。

步骤:

  1. 先将大区间进行入栈,先入区间右边的数,再入区间左边的数
  2. 取栈顶元素,划分为小区间
  3. 将这些小区间全部入栈

一直重复这三步就模拟出了递归的过程

int PartQuickSort(vector<int> &v, int begin, int end)
{
	int key = v[begin];
	int piti = begin;
	while (begin < end)
	{
		//右边先走,找到比key小的就停下来
		while (begin < end && v[end] >= key)
		{
			end--;
		}

		v[piti] = v[end];
		piti = end;

		//左边走,找到比key大的就停下来
		while (begin < end && v[begin] <= key)
		{
			begin++;
		}

		v[piti] = v[begin];
		piti = begin;
	}
	v[piti] = key;
	return piti;

}

//利用栈来模拟递归从场景—栈是先进后出
void QuickSortNonR(vector<int> &v, int begin, int end)
{
	stack<int> st;
	//先入右在入左
	st.push(end);
	st.push(begin);

	while (!st.empty())
	{
		int left = st.top();
		st.pop();

		int right = st.top();
		st.pop();

		int keyi = PartQuickSort(v, left, right);

		//左区间入栈
		if (left < keyi - 1)
		{
			st.push(keyi - 1);
			st.push(left);
		}
		
		//右区间入栈
		if (keyi + 1 < right)
		{
			st.push(right);
			st.push(keyi + 1);
		}
	}
}

快速排序中的优化

①对于选择key值的优化,key的选择对于快速排序来说至关重要,因为如果你选择的key值为最大值或者最小值时快速排序的效率就会有所影响,key值最好的是取这组数据的中间值来达到完全二分的情况。所以折中一下在一组数据的首、尾、中间位置去中间值。

//三个数取中间值做为key
int GetMidKeyi(vector<int>& v, int begin, int end)
{
	int mid = (begin + end) / 2;
	if (v[begin] < v[mid])
	{
		if (v[mid] < v[end])
		{
			return mid;
		}
		else if (v[begin] < v[end])
		{
			return end;
		}
		else
		{
			return begin;
		}
	}
	else//v[begin] > v[mid]
	{
		if (v[mid] > v[end])
		{
			return mid;
		}
		else if (v[begin] < v[end])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
}

②对于递归的小区间优化,在递归到小区间时,我们可以选择用插入排序来完成排序工作,因为此时这段小区间的数据肯定是接近有序的而插入排序在接近排序的情况下效率最高为O(N)。

归并排序

归并排序的思想:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

动图演示

代码实现:

递归版本

//归并排序—时间复杂度O(N*logN)
//空间复杂度O(N)
void _MergeSort(vector<int> &v, int begin, int end, vector<int> &tmp)
{
	//递归返回的条件
	if (begin >= end)
		return;

	int mid = (begin + end) / 2;

	//进行递归
	_MergeSort(v, begin, mid, tmp);
	_MergeSort(v, mid + 1, end, tmp);

	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin1;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (v[begin1] < v[begin2])
		{
			tmp[i++] = v[begin1++];
		}
		else
		{
			tmp[i++] = v[begin2++];
		}
	}

	//如果后面还有数,也要拷贝到tmp中去
	while (begin1 <= end1)
		tmp[i++] = v[begin1++];

	while (begin2 <= end2)
		tmp[i++] = v[begin2++];

	//深拷贝
	int j = begin, k = end - begin + 1;
	while(k-- && j <= end)
	{
		v[j] = tmp[j];
		j++;
	}
}


void MergeSort(vector<int> &v, int n)
{
	vector<int> tmp(n, 0);
	_MergeSort(v, 0, n - 1, tmp);
}

非递归版本

注意边界问题防止越界,对于越界的区间直接进行修正即可

//非递归版本
void MergeSortNonR(vector<int>& v, int n)
{
	vector<int> tmp(n, 0);

	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;

			//修正边界,防止越界
			if (end1 >= n)
			{
				end1 = n - 1;
				begin2 = n;
				end2 = n - 1;
			}
			else if (begin2 >= n)
			{
				begin2 = n;
				end2 = n - 1;
			}
			else if (end2 >= n)
			{
				end2 = n - 1;
			}


			int j = begin1;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (v[begin1] < v[begin2])
				{
					tmp[j++] = v[begin1++];
				}
				else
				{
					tmp[j++] = v[begin2++];
				}
			}

			//如果后面还有数,也要拷贝到tmp中去
			while (begin1 <= end1)
				tmp[j++] = v[begin1++];

			while (begin2 <= end2)
				tmp[j++] = v[begin2++];
		}

		//深拷贝
		for (int k = 0; k < n; k++)
		{
			v[k] = tmp[k];
		}

		gap *= 2;
	}
}

这里是归并完一次,就将tmp数据一次性拷回原数组中。

你也可以归并完一部分就将这一部分的数据拷回原数组中去,也就是下面的这种写法。

或者

void MergeSortNonR(vector<int>& v, int n)
{
	vector<int> tmp(n, 0);

	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;

			//修正边界,防止越界
			if (end1 >= n || begin2 >= n)
			{
				break;
			}
			else if (end2 >= n)
			{
				end2 = n - 1;
			}

			int k = end2 - begin1 + 1;
			int j = begin1;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (v[begin1] < v[begin2])
				{
					tmp[j++] = v[begin1++];
				}
				else
				{
					tmp[j++] = v[begin2++];
				}
			}

			//如果后面还有数,也要拷贝到tmp中去
			while (begin1 <= end1)
				tmp[j++] = v[begin1++];

			while (begin2 <= end2)
				tmp[j++] = v[begin2++];

			int m = i;
			while (k-- && m < n)
			{
				v[m] = tmp[m];
				m++;
			}
		}

		gap *= 2;
	}
}

由于我这里用的是C++来编写的,所以在将tmp数组中的数据拷贝回原数组中时, 不能使用memcpy函数进行拷贝,因为这里涉及到了深浅拷贝的问题,memcpy是浅拷贝。如果你用的是C语言来写的话就可以使用memcpy函数。

计数排序

计数排序的思想:统计相同元素出现的次数,然后将统计的结果写回到原数组中去。

 

对于B应该开多少空间来存放数据合适,使用A中的最大值 - 最小值 + 1,即为B应该开的空间数。时间复杂度:O(max(range,N)) ,空间复杂度:O(range),range为所开空间数。

计数排序的局限性:

  1. 如果是浮点数,字符串之类的就排不了了。
  2. 如果数据范围很大,空间复杂度就会很高,相对不合适。

代码实现:

//计数排序
//时间复杂度:O(max(range,N))
//空间复杂度:O(range)
void CountSort(vector<int>& v, int n)
{
	int max = v[0], min = v[0];
	for (auto vv : v)
	{
		if (vv < min)
			min = vv;

		if (vv > max)
			max = vv;
	}

	int range = max - min + 1;
	vector<int> count(range, 0);

	//统计次数
	for (int i = 0; i < n; i++)
	{
		count[v[i] - min]++;
	}

	//回写排序
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			v[j++] = i + min;
		}
	}
}

 总结

稳定性的概念:假定在待排序的记录序列中,存在多个具有相同的关键字,若经过排序,这些记录的相对次序保持不变,即在原序列中,v[i]=v[j],且v[i]在v[j]之前,而在排序后的序列中,v[i]仍然在v[j]之前,则称这种排序算法使稳定的,否则称为不稳定。 

计数排序在这里不做比较。 

今天的分享就到这里,如果觉得有所收获的话,就给博主三连吧,创作不易,你的支持将是我创作的动力。

谢谢!!!

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

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

相关文章

ICMP——网际控制报文协议

目录 1.1 网际控制报文协议 ICMP 1.2 ICMP 报文的格式 1.2.1 ICMP 报文的种类 ICMP 差错报告报文 ICMP 询问报文 1.3 ICMP 的应用 1.4 ICMP抓包 1.4.1 ICMP请求包&#xff08;request&#xff09; 1.4.2 ICMP应答包&#xff08;reply&#xff09; 1.1 网际控制报文协议…

解决maven 在IDEA 下载依赖包速度慢的问题

1.idea界面双击shift键 2.打开setting.xml文件 复制粘贴 <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sc…

Spring AOP实现

Spring AOP实现 AOP概述什么是AOP什么是Spring AOP Spring AOP快速入门引入依赖实现计时器 Spring AOP详解Spring AOP核心概念切点(Pointcut)连接点(Join Point)通知(Advice)切面(Aspect) 通知类型注意事项 PointCut多个切面切面优先级 Order切点表达式execution表达式annotati…

【开源】基于JAVA的就医保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预约挂号模块2.4 我的挂号模块 三、系统展示四、核心代码4.1 用户查询全部医生4.2 新增医生4.3 查询科室4.4 新增号源4.5 预约号源 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVue…

双链表的基本知识以及增删查改的实现

满怀热忱&#xff0c;前往梦的彼岸 前言 之前我们对单链表进行了非常细致的剖析&#xff0c;现在我们所面临的则是与之相对应的双链表&#xff0c;我会先告诉诸位它的基本知识&#xff0c;再接着把它的增删查改讲一下&#xff0c;ok&#xff0c;正文开始。 一.链表的种类 我…

07.领域驱动设计:掌握整洁架构、六边形架构以及3种常见微服务架构模型的对比和分析

目录 1、概述 2、整洁架构 3、六边形架构 4、三种微服务架构模型的对比和分析 5、从三种架构模型看中台和微服务设计 5.1 中台建设要聚焦领域模型 5.2 微服务要有合理的架构分层 5.2.1 项目级微服务 5.2.2 企业级中台微服务 5.3 应用和资源的解耦与适配 6、总结 1、概…

三步万能公式解决软件各种打不开异常

程序员都知道,辛苦做的软件发给客户打不开那是一个大写的尴尬,尴尬归尴尬还是要想办法解决问题. 第一步清理环境. 目标机台有环境和没有运行环境的,统统把vs环境卸载了,让目标机台缺少环境.第二步打包环境 源代码添加打包工程,setup,重新编译.![添加setup ](https://img-blo…

LeetCode——415. 字符串相加

C开头 &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#…

【架构论文】SCALE: Secure and Scalable Cache Partitioning(2023 HOST)

SCALE: Secure and Scalable Cache Partitioning 摘要 LLC可以提高性能&#xff0c;但是会引入安全漏洞&#xff0c;缓存分配的可预测变化可以充当侧信道&#xff0c;提出了一种安全的缓存分配策略&#xff0c;保护缓存免受基于时间的侧信道攻击。SCALE使用随机性实现动态可扩…

AI大模型专题:2024大模型安全流通平台市场厂商评估报告

今天分享的是AI大模型系列深度研究报告&#xff1a;《AI大模型专题&#xff1a;2024大模型安全流通平台市场厂商评估报告》。 &#xff08;报告出品方&#xff1a;揽睿星舟&#xff09; 报告共计&#xff1a;22页 大模型安全流通平台市场分析 企业需要大模型安全流通平台覆盖…

C语言 开发篇+一个简单的数据库管理系统ZDB

说明&#xff1a;本文供数据库爱好者和初级开发人员学习使用 标签&#xff1a;数据库管理系统、RDBMS、C语言小程序、C语言、C程序 系统&#xff1a;Windows 11 x86 CPU &#xff1a;Intel IDE &#xff1a;CLion 语言&#xff1a;C语言 标准&#xff1a;C23 提示&#xff1a;如…

C语言用SHBrowseForFolder弹出选择文件夹的对话框

【程序运行效果】 【程序代码】 main.c&#xff1a; #define COBJMACROS #include <stdio.h> #include <tchar.h> #include <Windows.h> #include <windowsx.h> #include <CommCtrl.h> #include <ShlObj.h> #include "resource.h&q…

JVM-类的生命周期

类的生命周期概述 类的生命周期描述了一个类加载、使用、卸载的整个过程。整体可以分为&#xff1a; 加载 连接&#xff0c;其中又分为验证、准备、解析三个子阶段 初始化 使用 卸载 加载阶段 加载(Loading)阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方…

深入玩转Playwright:高级操作解析与实践

playwright高级操作 iframe切换 ​ 很多时候&#xff0c;网页可能是网页嵌套网页&#xff0c;就是存在不止一个html标签&#xff0c;这时候我们的selenium或者playwright一般来说定位不到&#xff0c;为什么呢&#xff1f; ​ 因为默认是定位到第一个标准的html标签内部。 …

费一凡:土木博士的自我救赎之道 | 提升之路系列(五)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

五、防御保护---防火墙出口选路篇

五、防御保护---防火墙智能选路篇 一、就近选路二、策略路由选路1.策略路由的概念1.1匹配条件&#xff08;通过ACL定义&#xff09;1.2动作 三、智能选路 --- 全局路由策略1.基于链路带宽的负载分担2.基于链路质量进行负载分担3.基于链路权重进行负载分担4.基于链路优先级的主备…

股票市场

&#xff08;一&#xff09;股票市场 顾名思义&#xff0c;就是买卖股票的场所。就是为了撮合想发展但缺钱的企业与有钱但想投资的投资者。 股票市场按照交易场所&#xff0c;可分为场内市场和场外市场&#xff1a; 场内市场是指证券交易所&#xff0c; 场外市场就是证券交易…

比Filebeat更强大的日志收集工具-Fluent bit的http插件实战

文章目录 1.前言2. fluent bit http插件配置以及参数详解3. Http 接口服务3.1 开发Http 接口服务3.2 重启fluent bit向http web服务发送数据 1.前言 Fluent Bit 的 HTTP 插件提供了一种灵活而通用的机制&#xff0c;可用于将日志数据 从各种环境中传输到指定的远程服务器&#…

Python算法题集_滑动窗口最大值

本文为Python算法题集之一的代码示例 题目239&#xff1a;滑动窗口最大值 说明&#xff1a;给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗…

常见的网络安全威胁和防护方法

随着数字化转型和新兴技术在各行业广泛应用&#xff0c;网络安全威胁对现代企业的业务运营和生产活动也产生了日益深远的影响。常见的网络安全威胁通常有以下几种&#xff1a; 1. 钓鱼攻击 攻击者伪装成合法的实体&#xff08;如银行、电子邮件提供商、社交媒体平台等&#xf…