排序算法的实现

news2024/9/22 5:25:49


文章目录

  • 一、排序的概念及其运用
    • 1.排序的概念
    • 2.常见的排序算法
  • 二、常见排序算法的实现
    • 1.插入排序
      • 1.直接插入排序
      • 2.希尔排序
    • 2.选择排序
      • 1.直接选择排序
      • 2.堆排序
    • 3.交换排序
      • 1.冒泡排序
      • 2.快速排序
        • 1.hoare版本
        • 2.挖坑法
        • 3.前后指针版本
    • 4.归并排序
    • 5.非比较排序
  • 三、排序算法复杂度及其稳定性分析


一、排序的概念及其应用

1.排序的概念

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

稳定性:在待排序的序列中,存在多个具有相同的值,若经过排序,使得这些值的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,在排序后,次序仍然保持不变,那就称这种排序算法稳定的,否则就称为不稳定的。

内部排序:数据元素全部放在内存中的排序。

外部排序:数据元素太多不能同时放在内存中,根据排序过程中的要求不能拿在内外存之间移动数据的排序。

2.常见的排序算法

二、常见排序算法的实现(跑排序算法OJ链接)

插入排序

插入排序的思想是一种简单的插入排序法,其基本思想是:将待排序的记录按照其值大小依次逐个插入到一个已经排好序的有序序列中,知道所有的记录插入完为止,得到一个新的有序序列

1.直接插入排序

//简单插入排序
void InsertSort(int* a, int n)
{
	//需要将n-2后面的元素插入排序
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;//将end中后面一个元素插入到有序的区间[0,end]中
		int tmp = a[end + 1];//保存一下end后面一个元素的大小
		while (end >= 0)//将所插入的元素中的前面end个元素进行比较
		{
			if (tmp < a[end])//如果end后面一个元素的值比前面一个元素小的话往后移动
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;/*如果end此时的值比后面一个元素的值小的话则退出后进
				行赋值保证了此时数据能够全部插入
				而且有序*/
			}

		}
		a[end + 1] = tmp;/*将此时的tmp赋值
		(一种是因为这个有序区间的值都比后面这个大遍历完之后end为-1此时应该将tmp赋值
		第二种是因为此时break之后数值没有赋值)*/
	}

直接插入排序特性总结:

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

2.时间复杂度(O(n^2)

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

4.稳定性:稳定

2.希尔排序(缩小增量排序)

排序思想:先选定一个整数,把待排序文件中所有记录分成小组,所有距离为记录的分在一个同一个小组内进行排序。然后,取,重复上述分组和排序的工作。当到达1时,所有记录在统一组内排好序。

1预排序(使接近有序)

2直接插入排序(有序)

	//希尔排序(存在gap的简单排序)
	void ShellSort(int* a, int n)
	{
		int gap = n;//定义一个步长
		while (gap > 1)//确保gap的最后一次等于1(最后一次为插入排序)
		{
			gap = gap / 3 + 1;//(无论gap是奇数还是偶数使得最后一次的gap为1)
            //gap=gap/2;
			for (int i = 0; i < n - gap; i++)
			{
				int end = i;
				int tmp = a[end + gap];
				while (end >= 0)
				{
					if (tmp < a[end])//如果end后面一个元素的值比前面一个元素小的话往后移动
					{
						a[end + 1] = a[end];
						end = end - gap;
					}
					else
					{
						break;/*如果end此时的值比后面一个元素的值小的话则退出后进
				行赋值保证了此时数据能够全部插入
				而且有序*/
					}
					a[end + gap] = tmp;
					/*将此时的tmp赋值
		(一种是因为这个有序区间的值都比后面这个大遍历完之后end为-1此时应该将tmp赋值
		第二种是因为此时break之后数值没有赋值)*/
				}
			}
		}
	}

 希尔排序的特性总结:

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

2.当gap>1时都是预排序,目的是让数组更接近于有序。当gap=1时。数组已经接近于有序了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

3.希尔排序的时间复杂度不好计算,因为gap取值方法比较多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定;

4.稳定性:不稳定

选择排序

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

直接选择排序

在元素集合 array[i]--array[n-1] 中选择关键码最大 ( ) 的数据元素
若它不是这组元素中的最后一个 ( 第一个 ) 元素,则将它与这组元素中的最后一个(第一个)元素交
换。
在剩余的 array[i]--array[n-2] array[i+1]--array[n-1] )集合中,重复上述步骤,直到集合剩余 1 个元素 。

void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;

	while (begin < end) {
		int mini = begin, maxi = begin;

		for (int i = begin + 1; i <= end; i++) {
			if (a[i] < a[mini])
				mini = i;
			if (a[i] > a[maxi])
				maxi = i;
		}

		Swap(&a[begin], &a[mini]);
		if (maxi == begin)
			maxi = mini;

		Swap(&a[end], &a[maxi]);

		begin++;
		end--;
	}
}

直接选择排序的特性总结:
        1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
        2. 时间复杂度: O(N^2)
`       3. 空间复杂度: O(1)
        4. 稳定性:不稳定         

堆排序

堆排序 (Heapsort) 是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。 需要注意的是排升序要建大堆,排降序建小堆。

 

void AdjustDown(int* a, int size, int parent)
{
	int child = parent * 2 + 1;

	while (child<size) {
		if (child+1<size&&a[child] < a[child + 1])
			child++;

		if (a[child] > a[parent]) {
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

void HeapSort(int* a, int n)
{
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
		AdjustDown(a, n, i);

	int end = n - 1;
	while (end >= 0) {
		Swap(&a[end], &a[0]);
		AdjustDown(a, end, 0);
		end--;
	}
}
直接选择排序的特性总结:
        1. 堆排序使用堆来选数,效率就高了很多。
        2. 时间复杂度: O(N*logN)
        3. 空间复杂度: O(1)
        4. 稳定性:不稳定

交换排序

基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排 序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

冒泡排序

void BubbleSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++) {
		int exchange = 0;
		for (int j = 1; j < n - i; j++) {
			if (a[j - 1] >a[j]) {
				Swap(&a[j], &a[j - 1]);
				exchange = 1;
			}
		}

		if (exchange == 0)
			break;
	}
}

冒泡排序的特性总结:

        1. 冒泡排序是一种非常容易理解的排序
        2. 时间复杂度: O(N^2)
        3. 空间复杂度: O(1)
        4. 稳定性:稳定

         

快速排序

快速排序是Hoare 1962 年提出的一种二叉树结构的交换排序方法,其基本思想为: 任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
按照基准值来对区间中数据进行划分的方式即可。
将区间按照基准值划分为左右两半部分的常见方式有:
1. hoare版本

//hoare版本
int PartSort1(int* a, int begin, int end)
{
	int left = begin, right = end;
	int keyi = left;

	while (left < right) {
		while (a[right] >= a[keyi] && left < right)
			--right;
		while (a[left] <= a[keyi] && left < right)
			++left;

		Swap(&a[left], &a[right]);
	}

	Swap(&a[left], &a[keyi]);
	keyi = left;

	return left;
}
void QuickSort(int* a, int begin, int end)
{
	if (begin >end)
		return;

	int mid = PartSort1(a, begin,end);

	QuickSort(a, begin, mid - 1);
	QuickSort(a, mid + 1, end);
}
	

2.挖矿法

int PartSort2(int* a, int begin, int end)
{
	int key = a[begin];
	int piti = begin;

	while (begin < end) {
		while (begin < end && a[end] >= a[piti])
			--end;
		Swap(&a[end], &a[piti]);
		piti = end;

		while (begin < end && a[begin] <= a[piti])
			++begin;
		Swap(&a[begin], &a[piti]);
		piti = begin;
	}

	a[piti] = key;
	return piti;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >end)
		return;

	int mid = PartSort2(a, begin,end);

	QuickSort(a, begin, mid - 1);
	QuickSort(a, mid + 1, end);
}

 3.前后指针法

int PartSort3(int* a, int begin, int end)
{
	int prev = begin;
	int cur = begin + 1;
	int keyi = begin;

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

	Swap(&a[prev], &a[keyi]);
	keyi = prev;

	return keyi;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >end)
		return;

	int mid = PartSort3(a, begin,end);

	QuickSort(a, begin, mid - 1);
	QuickSort(a, mid + 1, end);
}
	
快速排序优化
1. 三数取中法选 key
2. 递归到小的子区间时,可以考虑使用插入排序
int GetMidIndex(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;

	if (a[begin] < a[mid]) {
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] < a[end])
			return end;
		else
			return begin;
	}
	else
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

int PartSort3(int* a, int begin, int end)
{
	int prev = begin;
	int cur = begin + 1;
	int keyi = begin;

	int mid = GetMidIndex(a, begin, end);

	Swap(&a[mid], &a[keyi]);

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

	Swap(&a[prev], &a[keyi]);
	keyi = prev;

	return keyi;
}

void _QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	else if (end - begin > 10) {
		int keyi = PartSort3(a, begin, end);

		_QuickSort(a, begin, keyi - 1);
		_QuickSort(a, keyi + 1, end);
	}
	else
		InsertSort(a+begin, end-begin+1);
}

快速排序非递归
void QuickSortNonR(int* a, int begin, int end)
{
	ST st;
	StackInit(&st);
	StackPush(&st, end);
	StackPush(&st, begin);

	while (!StackEmpty(&st)) {
		int left = StackTop(&st);
		StackPop(&st);

		int right = StackTop(&st);
		StackPop(&st);

		int keyi = PartSort3(a, left, right);

		if (keyi + 1 < right) {
			StackPush(&st, right);
			StackPush(&st, keyi + 1);
		}

		if (left < keyi - 1) {
			StackPush(&st, keyi - 1);
			StackPush(&st, left);
		}
	}

	StackDestroy(&st);
}
快速排序的特性总结:
1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫 快速 排序
2. 时间复杂度: O(N*logN)
3. 空间复杂度: O(logN)
4. 稳定性:不稳定

归并排序

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

 

void _MergeSort(int* a, int begin, int end,int* tmp)
{
	if (begin >= end)
		return;

	int mid = (begin + end) / 2;

	_MergeSort(a,begin, mid,tmp);
	_MergeSort(a, mid + 1, end,tmp);

	int begin1 = begin, end1 = mid ;
	int begin2 = mid + 1, end2 = end;
	int i = begin1;

	while (begin1 <= end1 && begin2 <= end2) {
		if (a[begin1] < a[begin2])
			tmp[i++] = a[begin1++];
		else
			tmp[i++] = a[begin2++];
	}

	while (begin1 <= end1)
		tmp[i++] = a[begin1++];
	while (begin2 <= end2)
		tmp[i++] = a[begin2++];

	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int)*n);

	if (tmp == NULL) {
		printf("malloc fail!\n");
		exit(-1);
	}

	_MergeSort(a, 0, n - 1,tmp);

	free(tmp);
}

 归并非递归

/*void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL) {
		printf("malloc fail!\n");
		exit(-1);
	}

	int gap = 1;
	while (gap < n) {
		for (int i = 0; i < n; i += 2 * gap) {
			//[i,i+gap-1][i+gap,i+2*gap-1]
			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 (a[begin1] < a[begin2])
					tmp[j++] = a[begin1++];
				else
					tmp[j++] = a[begin2++];
			}

			while (begin1 <= end1)
				tmp[j++] = a[begin1++];
			while (begin2 <= end2)
				tmp[j++] = a[begin2++];
		 }
		memcpy(a, tmp, sizeof(int) * n);
		gap *= 2;
	}
}*/
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL) {
		printf("malloc fail!\n");
		exit(-1);
	}

	int gap = 1;
	while (gap < n) {
		for (int i = 0; i < n; i += 2 * gap) {
			//[i,i+gap-1][i+gap,i+2*gap-1]
			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 m = end2 - begin1 + 1;
			int j = begin1;
			while (begin1 <= end1 && begin2 <= end2) {
				if (a[begin1] < a[begin2])
					tmp[j++] = a[begin1++];
				else
					tmp[j++] = a[begin2++];
			}

			while (begin1 <= end1)
				tmp[j++] = a[begin1++];
			while (begin2 <= end2)
				tmp[j++] = a[begin2++];
			memcpy(a+i, tmp+i, sizeof(int) * m);
		 }
		
		gap *= 2;
	}
}

归并排序的特性总结:
1. 归并的缺点在于需要 O(N) 的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
2. 时间复杂度: O(N*logN)
3. 空间复杂度: O(N)
4. 稳定性:稳定

非比较排序

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 操作步骤:
1. 统计相同元素出现次数
2. 根据统计的结果将序列回收到原来的序列中

void CountSort(int* a, int n)
{
	int min = a[0], max = a[0];
	for (int i = 1; i < n; i++) {
		if (a[i] < min)
			min = a[i];
		if (a[i] > max)
			max = a[i];
	}

	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * range);

	if (count == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}

	memset(count, 0, sizeof(int) * range);

	for (int i = 0; i < n; i++) {
		count[a[i]-min]++;
	}

	int j = 0;
	for (int i = 0; i < n; i++)
	{
		while (count[i]--)
			a[j++] = i + min;
	}
}

计数排序的特性总结:

1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
2. 时间复杂度: O(MAX(N, 范围 ))
3. 空间复杂度: O( 范围 )
4. 稳定性:稳定

排序算法复杂度及稳定性分析

 

 

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

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

相关文章

AOSP 8.0 系统启动之一内核启动

目录 一、前言 二、涉及源码​​​​​​​ 三、源码分析​​​​​​​ 一、前言 Android本质上就是一个基于Linux内核的操作系统&#xff0c;与Ubuntu Linux、Fedora Linux类似&#xff0c;我们要讲Android&#xff0c;必定先要了解一些Linux内核的知识。 Linux内核的东西…

LeetCode - 630 课程表Ⅲ

目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 630. 课程表 III - 力扣&#xff08;LeetCode&#xff09; 题目描述 这里有 n 门不同的在线课程&#xff0c;按从 1 到 n 编号。给你一个数组 courses &#xff0c;其中 courses[i] [durationi, lastDay…

被面试官问住了,MySQL两阶段提交是什么鬼?

前言 MySQL通过两阶段提交的机制&#xff0c;保证了redo log和bin log的逻辑一致性&#xff0c;进而保证了数据的不丢失以及主从库的数据一致。 而说起两阶段提交&#xff0c;就不得不先介绍一下redo log和bin log。 redo log redo log即重做日志&#xff0c;是InnoDB引擎特…

捷报频传 | 中睿天下再获“2022信创产业实干者企业”荣誉称号

近日&#xff0c;国内信创专业媒体“信创产业”正式公布“2022信创产业实干者”申报结果&#xff0c;同期发布信创产业实干者全景图。作为以“实战对抗”为特点的能力价值型网络安全厂商&#xff0c;中睿天下凭借自主研发实力、信创生态兼容性等综合实力&#xff0c;再次入选信…

stm32使用TB6600驱动器控制42BYGH型步进电机

stm32使用TB6600驱动器控制42BYGH型步进电机 stm32使用TB6600驱动器控制42BYGH型步进电机 文章目录stm32使用TB6600驱动器控制42BYGH型步进电机前言一、使用的设备说明介绍24V开关电源TB6600驱动器产品特点技术规格拨码开关设定42BYGH 步进电机接线方法控制步进电机的正反转控…

深度学习与排序模型发展

8.3 深度学习与排序模型发展 学习目标 目标 了解深度学习排序模型的发展应用 无 8.3.1 模型发展 CTR/CVR预估经历了从传统机器学习模型到深度学习模型的过渡。下面先简单介绍下传统机器学习模型&#xff08;GBDT、LR、到深度模型及应用&#xff0c;然后再详细介绍在深度学习…

基于遗传算法的配电网重构研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Android MVVM 开发新姿势 一

Android MVVM 开发新姿势 一 1. 前言 网上有不少关于Android架构的讨论&#xff0c;如MVC&#xff0c; MVP&#xff0c;MVVM&#xff0c;最近还有MVI&#xff0c;emmm…不得不感慨时代变化太快。MVVM出来也有一段很长的时间了&#xff0c;接触时间不长&#xff0c;写一篇文章…

快速入门pandas进行数据挖掘数据分析[多维度排序、数据筛选、分组计算、透视表](一)

1. 快速入门python&#xff0c;python基本语法 Python使用缩进(tab或者空格)来组织代码&#xff0c;而不是像其 他语言比如R、C、Java和Perl那样用大括号。考虑使用for循 环来实现排序算法: for x in list_values:if x < 10:small.append(x)else:bigger.append(x)标量类型 …

uni-app中vant-Weapp组件库的使用

先创建一个基础的uni-app目录从github下载vant包&#xff0c;zip格式的https://github.com/youzan/vant-weapp/releases项目根目录下创建wxcomponents文件夹把我们下好的文件vant-weapp里面只留下dist其余的可以全部删掉&#xff0c;然后把vant-weapp放到 wxcomponents里面App.…

在CentOS-6.9配置apache服务(2)---虚拟目录配置

文章目录一 需求二 系统环境三 基于Alias普通别名3.1 配置个人主页3.2 编写虚拟目录配置文件3.3 测试四 基于ScriptAlias脚本别名4.1 编写主配置文件4.2 创建测试主页4.3 测试一 需求 基于用户个人主页的身份验证&#xff0c;在浏览器输入 10.0.0.100/~a 可以得到用户a的个人网…

Linux:CPU频率调节模式以及降频方法简介

概述 cpufreq的核心功能&#xff0c;是通过调整CPU的电压和频率&#xff0c;来兼顾系统的性能和功耗。在不需要高性能时&#xff0c;降低电压和频率&#xff0c;以降低功耗&#xff1b;在需要高性能时&#xff0c;提高电压和频率&#xff0c;以提高性能。 cpufreq 是一个动态调…

拉伯证券|机构看好中国经济 人民币资产吸引力持续增强

2023年人民币汇率以及A股强势开局。1月以来人民币对美元中心价已累计增值超3%&#xff0c;接连3个月增值。到1月末&#xff0c;北向资金累计净买入额达1311.46亿元&#xff0c;刷新了沪深股通单月净买入新高。 在“真金白银”加仓布局人民币财物的一起&#xff0c;外资组织也纷…

CSS实现9宫格布局的4种方法:flex、float、grid、table布局

一、实现效果及html代码 1、实现效果 2、html代码 <body><div class"container"><div style"background-color: red">1</div><div style"background-color: blue">2</div><div style"background-…

十二、树结构的实际应用—赫夫曼树

1、赫夫曼树 1.1 基本介绍 给定 n 个权值作为 n 个叶子节点&#xff0c;构造一棵二叉树&#xff0c;若该树的带权路径长度&#xff08;wpl&#xff09;达到最小&#xff0c;称这样的二叉树为最优二叉树&#xff0c;也称哈夫曼树&#xff08;Huffman Tree&#xff09;&#xf…

Java工厂模式

定义&#xff1a;将创建对象的权利交给工厂类实现&#xff0c;解耦对象使用者和对象创建过程。 工厂模式有三种&#xff1a; 1、简单工厂模式 2、工厂方法模式 3、抽象工厂模式 使用工厂模式作用&#xff1a; 1、客户类和对象之间的耦合关系转移到了工厂方法和对象之间 …

pl/sql篇之變量的定義

簡述本篇文章主要介紹pl/sql的變量的簡單數據類型&#xff0c;複雜數據類型定義和調用方法&#xff0c;希望能對讀者有些許作用數據類型介紹變量的定義和調用在pl/sql中&#xff0c;定義的變量在聲明之後&#xff0c;可以直接在後續的sql調用&#xff0c;使用上非常方便簡單數據…

图解 MySQL MVCC 实现原理

文章目录MVCC 产生背景InnoDB 引擎表的隐藏列Undo 回滚版本链一致性视图MVCC 实现原理举例说明 MVCC 实现过程MVCC 产生背景 最早的数据库系统,只有读读之间可以并发,读写,写读,写写之间都要阻塞。而 MVCC (Muti Version Concurrency Control) , 是一种多版本并发控制机制。在…

Pandas+Pyecharts | 全国吃穿住行消费排行榜,最‘抠门’的地区居然是北京!!!

文章目录&#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 计算各项占比&#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 全国各地区人均收入、消费支出排行榜3.2 全国各地区人均可支配收入地图3.3 全国…

HCIA之ARP协议

ARP协议1、原理2、ARP工作过程3、ARP分类1、原理 根据已知的地址来获取与其对应的另一种地址 2、ARP工作过程 目标MAC全F&#xff0c;对于交换机&#xff0c;会洪泛&#xff1b;对于所有主机&#xff0c;都会以为是找自己的。 发送者PC1&#xff1a;发出广播帧&#xff0c;源I…