排序: 插入\希尔\选择\归并\冒泡\快速\堆排序实现

news2024/9/20 6:28:57

1.排序的概念及应用

1.1概念

排序:所谓排序,就是一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

1.2运用

购物筛选排序:

 

1.3常见排序算法 

2.实现常见的排序算法

int a[ = {5,3,9,6,2,4,7,1,8}; 

2.1插入排序

基本思想:直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其相关键码值逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。我们可以理解成玩扑克牌 

2.1.1直接插入排序

当插入第i个元素时,前面的arr[0],arr[1],arr[2].....,arr[i-1]已经排好序,此时用arr[i]的排序码与arr[i-1],arr[i-2]....的排序码顺序相比较,找到插入位置即将arr[i]插入,原来位置上的与元素挨个向后移动。 

代码实现:

void InsertSort(int* arr, int n)
{
	for (int i = 0; i < n-1; i++)
	{
		int end = i;
		int tmp = arr[end + 1];
		while (end>=0)
		{
			if (arr[end] > tmp) {
				arr[end + 1] = arr[end];
				end--;
			}
			else
			{
				break;
			}
		}
		arr[end+1] = tmp;
	}
}

直接插入排序的特性总结:

1.元素集合越接近有序,直接插入排序算法的效率越高

2.时间复杂度:O(N^2)

3.空间复杂度:O(1) 

2.1.2希尔排序

希尔排序法⼜称缩⼩增量法。希尔排序法的基本思想是:先选定⼀个整数(通常是gap =n/3+1),把 待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排 序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,当gap=1时,就相当于 直接插⼊排序。它是在直接插⼊排序算法的基础上进⾏改进⽽来的,综合来说它的效率肯定是要⾼于直接插⼊排序算 法的。

 

希尔排序的特性总结:

1.希尔排序是对直接插入排序的优化

2.当gap>1时都是预排序,目的时让数组更接近有序。当gap==1时,数组已经接近有序的了,这样就会很快。这样总体而言,可以达到优化的效果。 

代码实现:

/希尔排序
void shellSort(int* arr, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3+1;//3 1 0 要保证最后一次为1
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;//n-gap-1
			int tmp = arr[end + gap];//n-1
			while (end>=0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}
 2.1.2.1希尔排序的时间复杂度计算

希尔排序的时间复杂度估算:

外层循环:外层循环的时间复杂度可以直接给出为:O(log2 n) 或者 O(log3 n) ,即 O(log n)

内层循环:

假设一共有n个数据,合计gap组,则每组为n/gap个数据;在每组中,插入移动的次数最坏的情况下为1+2+3+4+.....+(n/gap-1),一共是gap组,因此:

总计最坏情况下移动总数为:gap*[1+2+3+...+n/gap-1]

gap取值有(以除3为例):n/3 n/9 n/27.....2 1

当gap为n/3时,移动总数为:n/3    (1 + 2) = n
当gap为n/9时,移动总数为: n/9    (1 + 2 + 3 + .... + 8) = n/9∗  8(1 + 8)/2 =4n
最后⼀躺,gap=1即直接插⼊排序,内层循环排序消耗为n

2.2选择排序

选择排序的基本思想:每一次从待排序的数据元素中选出最小或者最大的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

2.2.1直接选择排序

1.在元素集合arr[i]--arr[n-1]中选择最大和最小的数据元素

2.若它不是这个组元素中的最后一个元素或者第一个元素,则将它与这组元素中的最后一个和第一个元素进行交换

3.在剩余的arr[i]--arr[n-1]  arr[i+1]--arr[n-2]集合中,重复上面的步骤直到集合只剩一个元素

//选择排序
void SelectSort(int* arr, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin<end)
	{
		int mini = begin;
		int maxi = begin;
		for (int i = begin; i <= end; i++)
		{
			if (arr[i] > arr[maxi])
			{
				maxi = i;
			}
			if (arr[i] < arr[mini])
			{
				mini = i;
			}
		}
		if (maxi == begin)
		{
			maxi = mini;
		}
		Swap(&arr[begin], &arr[mini]);
		Swap(&arr[end], &arr[maxi]);
		begin++;
		end--;
	}
	
}

直接选择排序非常好理解,但是效率不高,实际中很少用

时间复杂度:O(N^2)

空间复杂度:O(1) 

2.2堆排序

堆排序(Heapsort)是指利⽤堆积树(堆)这种数据结构所设计的⼀种排序算法,它是选择排序的⼀
种。它是通过堆来进⾏选择数据。需要注意的是排升序要建⼤堆,排降序建⼩堆。
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

// 堆排序
void AdjustDwon(int* arr, int parent, int n)
{
	int child = 2 * parent + 1;//左孩子
	//大堆找最大
	//小堆找最小
	while (child < n)
	{
		if (child + 1 < n && arr[child] < arr[child + 1])
		{
			child++;
		}
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* arr, int n)
{
	//1.先建堆
	//升序建大堆
	//降序建小堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDwon(arr, i, n);
	}
	//交换根结点和最后一个有效数据的位置(没交换一次少一个数据)然后向下调整
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		//向下调整
		AdjustDwon(arr, 0, end);
		end--;
	}
}

2.3交换排序 

交换排序基本思想:

所谓交换,就是根据序列中两个记录键值的⽐较结果来对换这两个记录在序列中的位置交换排序的特点是:将键值较⼤的记录向序列的尾部移动,键值较⼩的记录向序列的前部移动

2.3.1冒泡排序 

前⾯在算法题中我们已经接触过冒泡排序的思路了,冒泡排序是⼀种最基础的交换排序之所以叫做冒泡排序,因为每⼀个元素都可以像⼩⽓泡⼀样,根据⾃⾝⼤⼩⼀点⼀点向数组的⼀侧移动。

 

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

冒泡排序的特性总结:

时间复杂度为:O(N^2)

空间复杂度为:O(1) 

2.3.2快速排序

快速排序是一种高效的排序算法,由英国计算机科学家托尼·霍尔(Tony Hoare)在1960年提出。它的基本思想是分而治之,通过一趟排序将待排记录分割成独立的两部分,其中一部分的所有记录均比另一部分的所有记录要小,然后再按此方法对这两部分分别进行快速排序,整个排序过程可以递归进行,以至整个数据变成有序序列。

快速排序实现的主框架:

//快速排序
void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	//找基准值mid
	int key = _QuickSort(arr, left, right);
	//左子序列:[left,mid-1]
	QuickSort(arr, left, key - 1);
	//右子序列:[mid+1,right]
	QuickSort(arr, key + 1, right);
}

将区间中的元素划分的 _QuickSort方法主要有一下几种实现方式:

2.3.2.1hoare版本

算法思路:

1.创建左右指针,确定基准值

2.从右向左找比基准值小的数据,从左向右找比基准值大的数据,左右指针数据交换,进入下次循环。当left>right时,即right走到left的左侧,而left扫描过的数据均不大于key,因此right此时指向的数据一定不大于key。

left和right指向的数据与key相等时也要交换,相等的值参与交换确实有一些损耗。实际还有各种复杂的场景,假设数组中的数据大量重复时,无法进行有效的数据分割。 

 

代码实现:

//hoare法
int _QuickSort(int* arr, int left, int right)
{
	int key = left;
	left++;
	while (left<=right)//使效率更高
	{
		//right从右到左找比基准值小的
		while (left<=right&&arr[right]>arr[key])
		{
			right--;
		}
		//left从左到右找比基准值大的
		while (left<=right&&arr[left]<arr[key])
		{
			left++;
		}
		if (left <= right)
		{
			Swap(&arr[left++], &arr[right--]);
		}
	}
	//跳出循环,交换right和基准值
	Swap(&arr[key], &arr[right]);
	//返回基准值
	return right;
}
2.3.2.2挖坑法
思路:创建左右指针。⾸先从右向左找出⽐基准⼩的数据,找到后⽴即放⼊左边坑中,当前位置变为新的"坑",然后从左向右找出⽐基准⼤的数据,找到后⽴即放⼊右边坑中,当前位置变为新的"坑",结束循环后将最开始存储的分界值放⼊当前的"坑"中,返回当前"坑"下标(即分界值下标)
//挖坑法
int _QuickSort1(int* arr, int left, int right)
{
	int mid = arr[left];
	int hole = left;
	int key = arr[hole];
	while (left<right)
	{
		while (left < right && arr[right] > key)
		{
			right--;
		}
		//填坑
		arr[hole] = arr[right];
		hole = right;
		while (left<right&&arr[left]<key)
		{
			left++;
		}
		//填坑
		arr[hole] = arr[left];
		hole = left;
	}
	arr[hole] = key;
	//返回基准值
	return hole;
}
2.3.2.3lomuto前后指针

创建前后指针,从左往右找比基准值小的进行交换,使得小的都排在基准值的左边。

//lomuto法
int _QuickSort2(int* arr, int left, int right)
{
	int prev = left;
	int cur = left + 1;
	int key = left;
	while (cur<=right)
	{
		if (arr[cur] < arr[key] && ++prev != cur)
		{
			Swap(&arr[cur], &arr[prev]);
		}
		cur++;
	}
	Swap(&arr[key], &arr[prev]);
	//返回基准值
	return prev;
}

快速排序的特性:

时间复杂度:O(n*logn)

空间复杂度:O(logn)

2.3.2.4非递归版本

非递归版本的快速排序需要借助数据结构:栈

//非递归
//栈结构
void QuickSortNonR(int* arr, int left, int right)
{
	ST st;

	STInite(&st);
	//入栈
	STPush(&st, right);
	STPush(&st, left);
	while (!STEmpty(&st)) 
	{
		//取栈顶--取两次
		int begin = STTop(&st);
		STPop(&st);

		int end = STTop(&st);
		STPop(&st);

		//找基准值
		int prev = begin;
		int cur = begin + 1;
		int key = begin;
		while (cur<=end)
		{
			if (arr[cur] < arr[key] && ++prev != cur)
			{
				Swap(&arr[prev], &arr[cur]);
			}
			cur++;
		}
		Swap(&arr[prev], &arr[key]);


		key = prev;
		//根据基准值划分左右区间
		//left:[begin,key-1]
		//right:[key+1,end]

		if (key+1<end)
		{
			STPush(&st, end);
			STPush(&st, key + 1);
		}

		if (begin<key-1)
		{
			STPush(&st, key - 1);
			STPush(&st, begin);
		}
	}

	STDestroy(&st);
}

2.4归并排序 

 归并排序算法思想:归并排序(MERGE-SORT是建⽴在归并操作上的⼀种有效的排序算法,算法是采⽤分治法(Divide and Conquer的⼀个⾮常典型的应⽤。将已有序的⼦序列合并,得到完全有序的序列;即先使每个 ⼦序列有序,再使⼦序列段间有序若将两个有序表合并成⼀个有序表称为⼆路归并。归并排序核⼼步骤:

void _mergeSort(int* arr, int left, int right,int* tmp)
{
	if (left >= right)
	{
		return;
	}
	int mid = (left + right) / 2;
	//[left,mid]  [mid+1,right]
	_mergeSort(arr, left, mid, tmp);
	_mergeSort(arr, mid + 1, right, tmp);

	//合并
	//[left,mid]  [mid+1,right]
	int begin1 = left;
	int end1 = mid;

	int begin2 = mid + 1;
	int end2 = right;

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

	//要么begin1越界,要么begin2越界
	while (begin1<=end1)
	{
		tmp[index++] = arr[begin1++];
	}

	while (begin2<=end2)
	{
		tmp[index++] = arr[begin2++];
	}

	//把tmp中的数据拷贝会arr中
	for (int i = left; i <=right; i++)
	{
		arr[i] = tmp[i];
	}
}
//归并排序
void mergeSort(int* arr, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);

	_mergeSort(arr, 0, n - 1, tmp);

	free(tmp);
}

归并排序特性总结:

时间复杂度:O(n*logn)

空间复杂度: O(n)

2.5计数排序

计数排序⼜称为鸽巢原理,是对哈希直接定址法的变形应⽤。 操作步骤:
1)统计相同元素出现次数
2)根据统计的结果将序列回收到原来的序列中
//计数排序
void CountSort(int* arr, int n)
{
	int max = arr[0];
	int min = arr[0];

	//找到最大值和最小值求范围
	for (int i = 1; i < n; i++)
	{
		if (arr[i] < min)
		{
			min = arr[i];
		}
		if (arr[i] > max)
		{
			max = arr[i];
		}
	}
	int range = max - min + 1;
	//开辟数组大小
	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	//初始化置为0
	memset(count, 0, range * sizeof(int));
	//统计数组中每个数据出现的次数
	for (int i = 0; i < n; i++)
	{
		count[arr[i] - min]++;
	}

	//取count中的数据往arr中放
	int index = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			arr[index++] = i + min;
		}
	}
}

2.6测试代码:排序性能对比

//测试排序性能
void Testop()
{
	srand(time(0));
	const int N = 100000;

	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);
	int* a3 = (int*)malloc(sizeof(int) * N);
	int* a4 = (int*)malloc(sizeof(int) * N);
	int* a5 = (int*)malloc(sizeof(int) * N);
	int* a6 = (int*)malloc(sizeof(int) * N);
	int* a7 = (int*)malloc(sizeof(int) * N);
	int* a8 = (int*)malloc(sizeof(int) * N);

	for (int i = 0; i < N; ++i)
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
		a8[i] = a1[i];
	}

	int begin7 = clock();
	BubbleSort(a7, N);
	int end7 = clock();

	int begin1 = clock();
	InsertSort(a1, N);
	int end1 = clock();

	int begin2 = clock();
	shellSort(a2, N);
	int end2 = clock();

	int begin3 = clock();
	SelectSort(a3, N);
	int end3 = clock();

	int begin4 = clock();
	HeapSort(a4, N);
	int end4 = clock();

	int begin5 = clock();
	QuickSort(a5, 0, N - 1);
	//QuickSortNonR(a5, 0, N - 1);
	int end5 = clock();

	int begin6 = clock();
	mergeSort(a6, N);
	int end6 = clock();

	int begin8 = clock();
	CountSort(a8, N);
	int end8 = clock();

	printf("InsertSort:%d\n", end1 - begin1);
	printf("ShellSort:%d\n", end2 - begin2);
	printf("SelectSort:%d\n", end3 - begin3);
	printf("HeapSort:%d\n", end4 - begin4);
	printf("QuickSort:%d\n", end5 - begin5);
	printf("MergeSort:%d\n", end6 - begin6);
	printf("BubbleSort:%d\n", end7 - begin7);
	printf("CountSort:%d\n", end8 - begin8);

	free(a1);
	free(a2);
	free(a3);
	free(a4);
	free(a5);
	free(a6);
	free(a7);
	free(a8);
}

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

MySQL数据库专栏(三)数据库服务维护操作

1、界面维护&#xff0c;打开服务窗口找到MySQL服务&#xff0c;右键单击可对服务进行启动、停止、重启等操作。 选择属性&#xff0c;还可以设置启动类型为自动、手动、禁用。 2、指令维护 卸载服务&#xff1a;sc delete [服务名称] 例如&#xff1a;sc delete MySQL 启动服…

嵌入式软件开发学习一:软件安装(保姆级教程)

资源下载&#xff1a; 江协科技提供&#xff1a; 资料下载 一、安装Keil5 MDK 1、双击.EXE文件&#xff0c;开始安装 2、 3、 4、此处尽量不要安装在C盘&#xff0c;安装路径选择纯英文&#xff0c;防止后续开发报错 5、 6、 7、弹出来的窗口全部关闭&#xff0c;进入下一步&a…

STM32(一):新建工程

stm32f10x.h文件&#xff1a;描述stm32有哪些寄存器&#xff08;外围&#xff09;和它对应的地址。stm32由内核和内核外围的设备组成的&#xff0c;内核寄存器描述和外围寄存器描述文件存储位置不在一起core_cm3.h core_cm3.c内核寄存器描述文件。mic.c内核库函数 stm32f10x_co…

【初阶数据结构】通讯录项目(可用作课程设计)

文章目录 概述1. 通讯录的效果2. SeqList.h3. Contact.h4. SeqList.c5. Contact.c6. test.c 概述 通讯录项目是基于顺序表这个数据结构来实现的。如果说数组是苍蝇小馆&#xff0c;顺序表是米其林的话&#xff0c;那么通讯录就是国宴。 换句话说&#xff0c;通讯录就是顺序表…

pycharm windows/mac 指定多版本python

一、背景 工作中经常会使用不同版本的包&#xff0c;如同时需要tf2和tf1&#xff0c;比较新的tf2需要更高的python版本才能安装&#xff0c;而像tf1.5 需要低版本的python 才能安装&#xff08;如 python3.6&#xff09;,所以需要同时安装多个版本。 二、安装多版本python py…

会员系统开发,检测按钮位置,按钮坐标,弹出指定位置对话框-SAAS 本地化及未来之窗行业应用跨平台架构

一 获取元素坐标 var 按钮_obj document.querySelector(#未来之窗玄武id);var 按钮_rect 按钮_obj.getBoundingClientRect()console.log(按钮_rect);输出结果 bottom : 35 height : 21 left : 219.921875 right : 339.921875 top : 14 width : 120 x : 219.921875 y…

R语言统计分析——组间差异的非参数检验

参考资料&#xff1a;R语言实战【第2版】 如果数据无法满足t检验或ANOVA的参数假设&#xff0c;可以转而使用非参数检验。举例来说&#xff0c;若结果变量在本质上就严重偏倚或呈现有序关系&#xff0c;那么可以考虑非参数检验。 1、两组的比较 若两组数据独立&#xff0c;可以…

大厂进阶五:React源码解析之Diff算法

本文主要针对React源码进行解析&#xff0c;内容有&#xff1a; 1、Diff算法原理、两次遍历 一、Diff源码解析 以下是关于 React Diff 算法的详细解析及实例&#xff1a; 1、React Diff 算法的基本概念和重要性 1.1 概念 React Diff 算法是 React 用于比较虚拟 DOM 树之间…

初识C++ · 类型转换

目录 前言&#xff1a; 1 C中的类型转换 1.1 static_cast 1.2 reinterpret_cast 1.3 const_cast 1.4 dynamic_cast 前言&#xff1a; C可以说是恨死了隐式类型转换&#xff0c;你可能会疑问了&#xff0c;为什么&#xff1f;不是单参数隐式类型转换为自定义类型的时候人…

苹果笔记本电脑可以玩steam游戏吗 MacBook支持玩steam游戏吗 在Steam上玩黑神话悟空3A大作 苹果Mac怎么下载steam

游戏是生活的润滑剂&#xff0c;越来越多的用户开始关注Mac平台上可玩的游戏。幸运的是&#xff0c;Steam作为最大的数字发行平台之一&#xff0c;提供了大量适用于Mac操作系统的游戏。无论你是喜欢策略、冒险还是射击类游戏&#xff0c;都能在Steam上找到适合自己Mac设备玩耍的…

ESP32CAM人工智能教学18

ESP32CAM人工智能教学18 获取数据并显示 如果我们给ESP32Cam外挂一些传感器&#xff08;比如温湿度传感器、超声波测距传感器、红外人体传感器等&#xff09;&#xff0c;我们怎么把ESP32Cam捕获到的数据&#xff0c;传递到客户端的浏览器&#xff0c;并在网页index.html中显示…

WordPress网站速度优化

提升网站速度对用户体验和搜索引擎排名至关重要。无论你是新手博主&#xff0c;还是经验丰富的网站开发人员&#xff0c;要想优化WordPress网站&#xff0c;需要长时间的努力和坚持。以下是按入门、中级和专家级别介绍的12个实用方法&#xff0c;帮助你提升WordPress网站的整体…

zabbix监控进程,日志,主从状态和主从延迟

自定义监控进程 使用httpd服务为例&#xff0c;监控httpd的进程 在zabbix-agent上安装httpd yum -y install httpd 重启httpd systemctl restart httpd systemtctl enable httpd 查看httpd的进程 [rootzabbix-agent ~]# ps -ef | grep httpd root 2407458 1 0 16:…

soapui调用接口参数传递嵌套xml,多层CDATA表达形式验证

1.环境信息 开发工具&#xff1a;idea 接口测试工具&#xff1a;soapui 编程语言&#xff1a;java 项目环境&#xff1a;jdk1.8 webservice&#xff1a;jdk自带的jws 处理xml&#xff1a;jdk自带的jaxb 2.涉及代码 package org.example.webdemo;import javax.jws.WebMethod; i…

Python,Spire.Doc模块,处理word、docx文件,极致丝滑

Python处理word文件&#xff0c;一般都是推荐的Python-docx&#xff0c;但是只写出一个&#xff0c;一句话的文件&#xff0c;也没有什么样式&#xff0c;就是36K。 再打开word在另存一下&#xff0c;就可以到7-8k&#xff0c;我想一定是python-docx的问题&#xff0c;但一直没…

汽车免拆诊断案例 | DAF(达富)汽油尾气处理液故障警示

故障现象 距离我上次在货卡上工作已经有一段时间了&#xff0c;让它们在道路上保持安全行驶是非常重要的。因此&#xff0c;当故障警示灯亮起时&#xff0c;我们需要迅速找到问题方向以及排除故障。 车辆的仪表板亮起多个故障灯以及警示灯&#xff0c;我们需要用解码器查找触…

数据分析与应用:微信-情人节红包流向探索分析

目录 0 需求描述 1 红包发送方用户的基本信息缺失率有多高?(即有多少红包发送方用户无法在用户基本信息表中匹配? 2 哪一组红包金额的拒收率最高? 3、最受二线城市欢迎的红包金额为?(即发出次数最多) 4 北上广深 4 大城市中,哪座城市的男性用户发出的 520 红包比例…

《密码编码学与网络安全原理与实践》第十四章第十五章密钥管理和用户认证

密钥管理与分发 密钥分发管理 传统上&#xff0c;对称加密被用于实现消息的保密性&#xff08;confidentiality&#xff09; 面临的攻击&#xff1a;局域网内监听、搭线窃听 传输媒介&#xff1a;线缆(双绞线、同轴电缆、光纤) (电磁波干扰)、微波链路、卫星信道 保密通信…

windows11-ubuntu-可爱的截图-启动时按F2可以选简体中文

windows11-ubuntu-可爱的截图-启动时按F2可以选简体中文

c++ 46 const

const伪命题 可以间接修改