【数据结构】手推堆实现,拳打堆排序,脚踩Top-k

news2024/11/17 16:02:17

目录

  • 一.完全二叉树的顺序结构
  • 二.堆的概念及结构
  • 三.堆的实现
    • 1.堆向下调整
    • 2.向下调整建堆
    • 3.向下调整建堆时间复杂度
    • 4.堆的插入(向上调整)
    • 5.向上调整建堆
    • 6.向上调整建堆时间复杂度
    • 7.堆的删除
    • 8.堆的代码实现
  • 四.Top-K问题
  • 五.堆排序

一.完全二叉树的顺序结构

堆的逻辑结构采用完全二叉树,而堆就是在一定条件下将完全二叉树使用数组存储,我们可以利用完全二叉树更好的学习堆。

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构(数组)存储。
在这里插入图片描述

如上图该完全二叉树(按从上到下,从左到右顺序存储)的数组结构就叫做堆(上图的数组满足条件所以可以叫做堆,条件下面会讲)

  • 需要注意,这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

二.堆的概念及结构

那是不是只要是一个完全二叉树,把它按顺序放在数组里就是一个堆呢?当然不是

堆的种类分为两种:

  1. 一个堆中某个节点的值总是不大于其父节点的值叫:大堆
  2. 一个堆中某个节点的值总是不小于其父节点的值叫:小堆

在这里插入图片描述
我们得出堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一颗完全二叉树。(可以在逻辑上形成完全二叉树)

只有满足这两点的数组才可以被称之为堆

三.堆的实现

现在给出一个数组,逻辑上看做是一颗完全二叉树。我们已经知道堆分为大堆和小堆两种,那我们要如何才能将它变成一个完整的堆呢?

int arr[8] = { 7,4,2,9,3,4 };

在这里插入图片描述

  • 堆的数据结构,难点就在于堆的创建、插入和删除,所以这三个功能会放在一起讲,剩余的功能最后讲解。

这里就需要先来学一种方法完成堆的构建:堆向下调整

1.堆向下调整

按照完全二叉树的逻辑结构,从最后一个节点的父节点开始,以该节点下标为起始,与自己的两个孩子节点(可能为一个孩子节点)比较大小并根据情况交换位置(大堆比较更大的孩子节点,小堆比较更小的孩子节点),一直调整到根节点,最终得到大堆/小堆

  • 向下调整算法的前提:根节点的左右子树必须都为堆,才能调整,否则在本就无序的情况下去,去使用根节点的值去比对查找,是无法找到适合的元素的,所以向下调整只能从最后一个节点的父节点开始(也可以说是倒数的第一个非叶子节点)对比,才能保证根节点的

我们在这些做一个大堆并画出它的流程图:
在这里插入图片描述

  • 从最后一个父节点向下比较,建大堆,将最大值移到上面,数组的切换如上图

在这里插入图片描述

  • 接着使用下一个父节点与其子节点中最大值比较,与最大值交换

在这里插入图片描述

  • 在将下一个父节点与其子节点中的最大值比较并交换,查看交换后的子节点是否为其子节点的最大值,若不是则继续进行向下调整,否则以调整到根节点,建堆结束。

我们之前以及提过了,这个堆的存储形式是一个数组,而最后一个节点就是数组下标最大的元素,那我们要如何求出它的父节点?

这个是有固定的公式,根据这个公式:
当我们知道孩子节点的下标就能求出其父节点的下标,知道父亲节点的下标,就能求出孩子节点的下标,

下标如下图:

在这里插入图片描述

  • 知道父亲节点下标,求孩子节点下标
    father = 0 :
    左孩子 = father * 2 + 1 = 1;
    右孩子 = father * 2 + 2 = 2;
    father = 3 :
    左孩子 = father * 2 + 1 = 7;
    右孩子 = father * 2 + 2 = 8;
    知道父亲节点,求孩子节点的公式如下:
    左孩子 = father * 2 + 1;
    右孩子 = father * 2 + 2;

  • 知道孩子节点下标,求父亲节点下标
    知道左孩子下标
    由上面的公式推导:father = (左孩子-1)/2;
    知道右孩子下标
    由上面的公式推导:father = (右孩子-2)/2;
    其中,左孩子一定是奇数,右孩子是偶数,而在C语言中,一个偶数减1后除以2和一个偶数减2后除以2是相同的,因为下标为整数,偶数减1后除以2所得必须为整数,除不尽的部分直接舍弃。
    因此,我们不需要知道该孩子节点是左孩子还是右孩子。
    知道孩子节点下标,求父亲节点下标公式如下:
    father = (孩子-1)/2;

2.向下调整建堆

我们已经知道了一个堆是如何创建的,现在有如下数组,我们使用代码来实现堆的创建。

int arr[8] = { 7,4,2,9,3,4,5,6 };

代码如下:

void swap(int* a1, int* a2)
{
	int tmp = *a1;
	*a1 = *a2;
	*a2 = tmp;
}

void AdjustDown(int* arr, int n, int father)//向下调整
{
	int child = father * 2 + 1;//左孩子节点下标

	while (child < n) //向下调整,child只会越来越大,当超出数组范围时,退出循环
	{
		if (child+1 < n && arr[child] < arr[child + 1])//判断是否存在右孩子节点,存在左右孩子结点谁大,要是建小堆,取小的那个元素
			child = child + 1;
		if (arr[father] < arr[child])//判断父亲结点和孩子结点那个大,若孩子结点大,则进行交换,并继续向下调整,建小堆取小值即可
		{
			swap(&arr[father], &arr[child]);//两节点进行交换
			father = child;//孩子结点的下标赋给父亲结点
			child = father * 2 + 1;//孩子节点获得新的左孩子下标
		}
		else
			break;
	}
}

int CreatHeap(int* arr, int n)//arr为要建堆的数组
{
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)//循环的初始值为倒数第一个非叶子节点的下标
	{
		AdjustDown(arr, n, i);//向下调整
	}
}

3.向下调整建堆时间复杂度

时间复杂度是求该函数在最坏的情况下基本操作次数,而我们现在算的是建堆这一功能的时间复杂度,因为堆是完全二叉树,而满二叉树(除叶子节点外,每个节点都有两个孩子节点)也是完全二叉树,此处我们就能使用满二叉树来判断堆的时间复杂度。

在这里插入图片描述
因为需要按照最坏的情况考虑,我们就将堆中除最后一层外的其他节点都需要向下移动到最底层。
在这里插入图片描述
所以:建堆的时间复杂度为O(N)

4.堆的插入(向上调整)

如下图所示,我们在原有完全二叉树的基础上,向其中尾插一个10,之后就需要进行向上调整,做法如下图:
在这里插入图片描述

该堆为小堆,先找到新插入节点的父节点,进行对比,父节点大,进行替换,新插入的节点取代父节点,并向新的父节点进行对比操作,直到到达根节点。若是父节点小于新插入的节点,停止操作,表面堆的插入以完成。

注意:这里最好不要用向下调整,堆的插入操作是在一个堆已经成型的情况下进行,如果用向下调整,新插入的节点的父节点后的所有节点都要重新遍历一遍,时间复杂度一定要比只是移动新节点的向上调整大。

知道孩子节点,如何求父节点的公式之前已经讲了,这里我们就能直接得出代码(这里做的是小堆的插入):

向上调整代码如下:

void AdjustUp(int* arr, int child)
{
	int father = (child - 1) / 2;//获得父亲节点的下标

	while (child)
	{
		if (arr[father] > arr[child])//孩子结点数据小于父亲结点数据,两数交换
		{
			swap(&arr[father], &arr[child]);
			child = father;
			father = (child - 1) / 2;
		}
		else
			break;
	}
}
  • 向上调整也可以被用来做堆的构建但时间复杂度要大于向下调整,在下面堆的代码实现中有完整代码。

5.向上调整建堆

我们在堆的插入中已经学了堆的向上调整的思想,我们也可以利用向上调整来建堆,但是这个时间复杂度要大于向下调整,实际操作中不会用到这个方法建堆,这里简单介绍一下。
在这里插入图片描述

  • 使用如上图片中的数组建大堆

在这里插入图片描述

  • 向上调整建堆,需要按照数组一个一个插入堆中比较,出现比父节点大的数据,进行向上调整,直到数组全部进入堆中。

在这里插入图片描述

  • 发现插入数据比父节点大,按照向上调整,直到遇到更大的或到达根节点停止。
    在这里插入图片描述
    代码如下:
void AdjustUp(int* arr, int child)
{
	int father = (child - 1) / 2;//获得父亲节点的下标

	while (child)
	{
		if (arr[father] > arr[child])//孩子结点数据小于父亲结点数据,两数交换
		{
			swap(&arr[father], &arr[child]);
			child = father;
			father = (child - 1) / 2;
		}
		else
			break;
	}
}
void CreatHeap(int* a,int n)
{
	for (int i = 0; i < n; i++)
	{
		AdjustUp(a, i);
	}
}

6.向上调整建堆时间复杂度

以最坏情况来算时间复杂度,与向下调整不同,假设高度为h,最底层每个节点都要向上移动h-1次,剩余节点按层数依次类推。

在这里插入图片描述
将这些移动次数相加为:
在这里插入图片描述
所以:建堆的时间复杂度为O(Nlog(N))

向上调整建堆的时间复杂度要大于向下调整建堆

7.堆的删除

堆的删除就是将堆顶的数据删除。

具体操作:将堆顶的数据与最后一个节点的数据交换,然后删除数组中的最后一个数据,在对堆顶的数据进行向下调整,如下图。

在这里插入图片描述

8.堆的代码实现

由上面几个功能,比如堆的插入和删除,这是要直接对数组进行扩容等相关操作的,如果只在数组上进行会造成很多的麻烦,所以我们需要创建一个结构体来用来存储堆,而堆的删除也用用到了结构体相关的内容,结构体定义如下:

typedef int HPDataType;
typedef struct Heap
{
HPDataType* _a;
int _size;
int _capacity;
}Heap;

堆的其他功能实现难度不大,这里就只整体展示代码,不一个个讲解了。
注意:下面代码中一些类型用自定义结构体类型交换,与上面实现的代码相同
堆的所有功能代码如下;

//打印堆
void PrintHeap(Heap* hp)
{
	assert(hp);
	for (int i = 0; i < hp->size; i++)
	{
		printf("%d ", hp->a[i]);
	}
	printf("\n");
}

void HeapInit(Heap* hp)
{
	hp->a = NULL;
	hp->capacity = 0;
	hp->size = 0;
}

// 堆的销毁
void HeapDestory(Heap* hp)
{
	assert(hp);
	free(hp->a);
	hp->a = NULL;
	hp->capacity = 0;
	hp->size = 0;
}

堆的构建——偷懒的写法——使用向上调整实现堆的构建
//void HeapCreat(Heap* hp, HPDataType* a, int n)
//{
//	hp->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
//	if (!hp->a)
//	{
//		perror("malloc fail!");
//		exit(-1);
//	}
//	hp->capacity = n;
//
//	for (int i = 0; i < n; i++)
//	{
//		HeapPush(hp, a[i]);
//	}
//}

//堆的构建——建堆算法
void HeapCreat(Heap* hp, HPDataType* a, int n)
{
	hp->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (!hp->a)
	{
		perror("malloc fail!");
		exit(-1);
	}

	memcpy(hp->a, a, sizeof(HPDataType) * n);
	hp->capacity = hp->size = n;

	//建堆算法——函数接收父亲结点算法
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(hp->a, n, i);
	}
}

//两数交换
void swap(HPDataType* a1, HPDataType* a2)
{
	HPDataType tmp = *a1;
	*a1 = *a2;
	*a2 = tmp;
}

//向上调整
void AdjustUp(HPDataType* arr, int child)
{
	int father = (child - 1) / 2;//父亲结点位置

	while (child)
	{
		if (arr[child] > arr[father])//孩子结点数据大于父亲结点数据,两数交换
		{
			swap(&arr[child], &arr[father]);
			child = father;
			father = (child - 1) / 2;
		}
		else
			break;
	}
}

// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	if (hp->capacity == hp->size)
	{
		int newSize = hp->capacity * 2;
		HPDataType* newArr = (HPDataType*)realloc(hp->a, newSize);
		if (!newArr)
		{
			perror("realloc fail!");
			exit(-1);
		}
		hp->capacity = newSize;
		hp->a = newArr;
	}

	hp->a[hp->size++] = x;

	AdjustUp(hp->a, 0);
}

//向下调整
void AdjustDown(HPDataType* arr,int n,int parent)
{
	int child = parent * 2 + 1;

	while (child < n)
	{
		if (child + 1 < n && arr[child] > arr[child + 1])
			child = child + 1;

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

// 堆的删除
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(hp->size);

	hp->a[0] = hp->a[--hp->size];

	AdjustDown(hp->a, hp->size, 0);
}

//取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
	assert(hp);
	assert(hp->size > 0);

	return hp->a[0];
}

//堆的数据的个数
int HeapSize(Heap* hp)
{
	assert(hp);

	return hp->size;
}

//判空
int HeapEmpty(Heap* hp)
{
	assert(hp);

	return hp->size == 0;
}

四.Top-K问题

问题:在一个很大的数据中,取出它最大或最小的前k个值。

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

对于这个问题,想到最简单的方法就是排序,但是数据量非常大,当数据不可能一下子全部加载到内存中时,排序就不太可取了。

最佳的方法就是用堆来解决,基本思路如下:

1. 用数据集合中前k个元素来建堆

  • 取前k个最大的元素,建小堆
  • 取前k个最小的元素,建大堆

2.用剩余的N-k个元素依次与堆顶元素来比较,不满足则替换堆顶元素,在进行向下调整。

将剩余N-k个元素依次与堆顶元素比较完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

如下图,为取前6个最大的元素的一次对比图:

在这里插入图片描述

具体代码如下:

void TopK(int* arr,int n,int k)
{
	int* tmpArr = (int*)malloc(sizeof(int) * k);
	
	//方法1
	//memcop(tmpArr, arr, sizeof(int) * k);//使用内存函数拷贝数组前k个数

	//方法2
	for (int i = 0; i < k; i++)
	{
		tmpArr[i] = arr[i];
	}

	for (int i = (k - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(tmpArr, k, i);//向下调整建堆
	}
	for (int i = k; i < n; i++)
	{
		if (arr[i] > tmpArr[0])
		{
			swap(&arr[i], &tmpArr[0]);
		    AdjustDown(tmpArr, k, 0);//将此时栈顶的元素进行向下调整
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", tmpArr[i]);//打印出这k个数,但此时这k个数是无序的
	}
}

五.堆排序

当我们掌握了上面的堆的创建、向下调整和父亲与孩子节点下标的转换后,堆排序的实现就非常简单

先说一下思路:

当我们想要得到一个排好序的数组时,我们需要将它先建成堆。

  • 升序:大堆
  • 降序:小堆
    假设我们要对一个大小为n的数组进行降序,
    首先,建好的小堆的堆顶就是最小的数,我们将它和第n个数交换,在将堆的大小调整为(n-1),对堆顶进行向下调整。
    其次,此时堆顶的数就是次小的数,我们在将它和第n-1个数交换,在将堆的大小调整为(n-2),对堆顶进行向下调整。
    如此循环,最后得到的n个数就是降序排好的

如下图,是堆排序的部分循环图:

在这里插入图片描述
剩余步骤与上述步骤相同,不在展示。

根据该思路,堆排序的实现代码如下:

void AdjustDown(int* arr, int n, int father)
{
	int child = father * 2 + 1;//左孩子节点下标

	while (child < n)
	{
		if (child+1 < n && arr[child] > arr[child + 1])//判断是否存在右孩子节点,存在左右孩子结点谁大
			child = child + 1;
		if (arr[father] > arr[child])//判断父亲结点和孩子结点那个大,若孩子结点大,则进行交换,并继续向下调整
		{
			swap(&arr[father], &arr[child]);//两节点进行交换
			father = child;//孩子结点的下标赋给父亲结点
			child = father * 2 + 1;//孩子节点获得新的左孩子下标
		}
		else
			break;
	}
}

int* HeapSort(int* arr,int n)
{
	for (int i = (n-1-1)/2; i >= 0; i--)//先建堆
	{
		AdjustDown(arr, n, i);
	}

	for (int i = 0; i < n; i++)//向下调整堆排序
	{
		swap(&arr[i], &arr[n - i - 1]);//堆顶元素与最后一个元素交换,将最大值或最小值放在最后
		AdjustDown(arr, n - i - 1, 0);
	}

	return arr;
}

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

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

相关文章

GPIO实验

一、GPIO简介 GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出&#xff0c;GPIO可以控制连接在其之上的引脚实现信号的输入和输出 芯片的引脚与外部设备相连&#xff0c;从而实现与外部硬件设备的通讯、控制及信号采集等功能 实验步骤1. 通过电路…

第十七讲:神州三层交换机DHCP服务器配置

DHCP是基于Client&#xff0d;Server模式的协议&#xff0c;DHCP客户机向DHCP服务器索取网络地址及配置参数&#xff1b;服务器为客户机提供网络地址及配置参数&#xff1b;当DHCP客户机和DHCP服务器不在同一子网时&#xff0c;需要由DHCP中继为DHCP客户机和DHCP服务器传递DHCP…

java企业通知小程序微信消息推送小程序企业消息通知系统网站源码

简介 本系统主要是利用小程序和springboot开发的企业分组消息推送&#xff0c;主要是员工关注小程序&#xff0c;由分组领导创建消息主体并设置消息提醒时间&#xff0c;利用微信的消息模板对选定的员工进行消息提醒推送。比如公司的技术部需要在11月3号早上8点举行晨会&#…

【Java编程进阶】面向对象思想初识

推荐学习专栏&#xff1a;Java 编程进阶之路【从入门到精通】 文章目录1. 面向对象初识2. 类和对象2.1 类的定义2.2 对象的创建和使用3. 构造方法4. 方法重载5. static 关键字5.1 static 方法5.2 static 变量6. 对象的引用和 this7. 总结1. 面向对象初识 之前我们学习了 C 语言…

P2367 语文成绩和P5542 Painting The Barn S(一维和二维差分)

目录 前言 一、P2367 语文成绩 二、P5542 Painting The Barn S 前言 图文详解一维差分 图文详解二维差分 一、P2367 语文成绩 题目背景&#xff1a; 语文考试结束了&#xff0c;成绩还是一如既往地有问题。 题目描述&#xff1a; 语文老师总是写错成绩&#xff0c;所以当…

关于C语言中内存分配

一、static在C语言里面可以用来修饰变量&#xff0c;也可以用来修饰函数。 1、 先看用来修饰变量的时候。变量在C语言里面可分为存在全局数据区、栈和堆里。 其实我们平时所说的堆栈是栈而不是堆&#xff0c;不要弄混。 例如&#xff1a;在file.c中 int a ; int main() { int b…

如何在 Python 中自动化处理 Excel 表格?

考虑一个场景&#xff0c;要求在网站上为 30,000 名员工创建一个帐户。手动重复执行此任务会非常枯燥乏味。此外&#xff0c;这将花费太多时间&#xff0c;这不是一个明智的决定。 现在想象一下从事数据输入工作的员工的生活。他们的工作是从 Excel 表格中获取数据并将其插入其…

CSS 实现灯笼动画,祝大家元旦快乐

前言 &#x1f44f;CSS 实现大红灯笼动画&#xff0c;祝大家元旦快乐&#xff0c;2023越来越棒&#xff01;速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现步骤 定义一个灯笼的背景色bg&#xff0c;线条颜色lineColor :root …

数字时代下, 企业如何保证数据的安全

随着全球数字化进程的蓬勃发展&#xff0c;在互联网时代下技术和数据深度融合的数字经济模式为许多行业带来了更大创收。数据也已经成为了五大核心生产要素之一&#xff0c;驱动着国家、社会、企业全方位高速发展。“迎接数字时代&#xff0c;激活数据要素潜能&#xff0c;推进…

四、 Spring-MVC

MVC MVC &#xff1a;Model View Controller&#xff0c;是模型(model)&#xff0d;视图(view)&#xff0d;控制器(controller)的缩写&#xff0c;一种软件设计规范。本质上也是一种解耦。 Model&#xff08;模型&#xff09;是应用程序中用于处理应用程序数据逻辑的部分。通常…

使用CLIP构建视频搜索引擎

CLIP(Contrastive Language-Image Pre-training)是一种机器学习技术&#xff0c;它可以准确理解和分类图像和自然语言文本&#xff0c;这对图像和语言处理具有深远的影响&#xff0c;并且已经被用作流行的扩散模型DALL-E的底层机制。在这篇文章中&#xff0c;我们将介绍如何调整…

再获权威认可 百分点科技入选Forrester AI/ML平台主流供应商

近日&#xff0c;全球领先的研究和咨询公司Forrester发布了2022年第四季度中国AI/ML&#xff08;人工智能/机器学习&#xff09;平台报告《The AI/ML Platform Landscape In China, Q4 2022》&#xff0c;系统分析了AI/ML平台市场的业务价值、市场成熟度及市场动态&#xff0c;…

python基础语法24-多线程实操

上一节说了多线程的理论知识,今天来实际操作一下。 1.创建线程 python中有2中方法创建线程,分别为函数和类继承 (1).使用函数来创建线程 调用 _thread 模块中的start_new_thread()函数来产生新线程。语法如下: _thread.start_new_thread ( function, args[, kwargs] ) 参数说…

保护小程序,防止反编译:打造不怕反编译的小程序

保护小程序&#xff0c;防止反编译 打造不怕反编译的小程序 这几年,小程序、小游戏&#xff0c;非常火。 业内人都知道&#xff0c;小程序或小游戏&#xff0c;就是H5应用&#xff0c;就是htmlJS。这类应用&#xff0c;反编译很容易&#xff0c;网上就有很多方法教程。 对小…

我坦白→低代码功能我有,SQL练习题、数据可视化、数据填充助你高效

简介 今天勇哥看了一下群里的聊天信息&#xff0c;大家都在说低代码平台&#xff0c;见大家对于低代码这么热衷的情况下&#xff0c;勇哥也不藏着掖着了&#xff0c;先放几个低代码功能出来&#xff0c;给大家玩一玩&#xff0c;更多的功能敬请期待。 帮勇哥投个票&#xff1…

Docker进阶 — 一文掌握Docker基础

Docker进阶 — 一文掌握Docker基础 文章目录Docker进阶 --- 一文掌握Docker基础一、初识 Docker1. 什么是Docker2. Docker架构3. DockerHub4. Docker运行模式5. Docker和虚拟机的区别二、Docker 的安装1. Linux安装Docker2. Window 安装Docker环境配置1. 开启 Hyper-V服务2. 安…

五款炫酷精美动态登录页面,彩虹气泡动态云层深海灯光水母炫酷星空蛛网HTMLCSS源码

完整源码详见 微信公众号&#xff1a;创享日记 对话框发送&#xff1a;登录页面 获取HTMLCSSjs等源码文件 一、彩虹气泡登录页面 效果图&#xff1a; HTML源码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-…

linux 下coredump 生成及调试分析

Windows环境崩溃问题&#xff08;dump&#xff09;可根据vs调试或windbg工具查看.linux环境崩溃文件为core文件&#xff0c;可以使用gdb进行调试分析。 前提&#xff1a;都是都是用了root权限的用户操作。 1.生成core文件的前提 产生coredump的条件&#xff0c;首先需要确认…

优化改进YOLOv5算法之添加RepVGG模块(超详细)

在前面的文章中已经详细介绍了在本机上安装YOLOv5的教程&#xff0c;安装YOLOv5可参考前面的文章YOLOv5训练自己的数据集(超详细)https://blog.csdn.net/qq_40716944/article/details/118188085 目录 1、RepVGG原理 1.1 模型定义 1.2 为什么要用VGG式模型 1.3 结构重参数化…

基于ssm+mysql+jsp实现水果蔬菜商城系统

基于ssmmysqljsp实现水果商城系统一、系统介绍1、系统主要功能&#xff1a;2、环境配置二、功能展示1.主页(客户)2.登陆&#xff08;客户&#xff09;3.我的购物车(客户)4.我的订单&#xff08;客户&#xff09;5.主页&#xff08;管理员&#xff09;6.订单管理&#xff08;管理…