数据结构从入门到精通——堆

news2024/11/17 2:47:53

  • 前言
  • 一、二叉树的顺序结构及实现 (堆)
    • 1.1二叉树的顺序结构
    • 1.2堆的概念及结构
  • 二、堆的练习题
    • 答案
  • 三、堆的实现
    • 3.1堆向下调整算法
    • 3.2堆的创建
    • 3.3建堆时间复杂度
    • 3.4堆的插入
    • 3.5堆的删除
    • 3.6堆的代码实现
  • 四、堆的具体实现代码
    • Heap.h
    • Heap.c
    • Test.c
    • 堆的初始化
    • 堆的销毁
    • 数据交换函数
    • 堆的向上交换
    • 元素入堆
    • 堆的向下交换
    • 元素出堆
    • 堆顶元素
    • 堆是否为空
  • 五、堆的应用
    • 5.1 数组向上调整建堆
    • 5.2数组向下调整建堆
    • 5.3堆排序
    • 5.4TOP-K问题
      • 直接建数据
      • 文件建数据
      • 完整代码
        • test.c
        • 数据交换
        • 向下调整
        • 主函数


前言

堆是一种特殊的树形数据结构,具有完全二叉树的特性。在堆中,父节点的值总是大于或等于(大顶堆)或小于或等于(小顶堆)其子节点的值。堆通常用于实现优先队列,其中每个元素都有一个优先级,优先级最高的元素总是位于堆的根节点。堆的插入和删除操作的时间复杂度都是O(log n),因此堆是一种高效的数据结构。此外,堆还可以用于实现内存管理,例如垃圾回收和内存分配等。


一、二叉树的顺序结构及实现 (堆)

1.1二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
在这里插入图片描述

1.2堆的概念及结构

如果有一个关键码的集合K = {K0 ,K1 ,K2 ,…,Kn-1 },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <=K2*i+1 且Ki <=K2*i+2 ( Ki>=K2*i+1 且Ki >= K2*i+2) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质

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

在这里插入图片描述

二、堆的练习题

  1. 下列关键字序列为堆的是:()
    A、 100,60,70,50,32,65
    B 、60,70,65,50,32,100
    C、 65,100,70,32,50,60
    D、 70,65,100,32,50,60
    E、 32,50,100,70,65,60
    F 、50,100,70,65,60,32

  2. 已知小根堆为8,15,10,21,34,16,12,删除关键字 8 之后需重建堆,在此过程中,关键字之间的比较次数是()。
    A 、1
    B、 2
    C 、3
    D 、4

  3. 一组记录排序码为(5 11 7 2 3 17),则利用堆排序方法建立的初始堆为
    A、(11 5 7 2 3 17)
    B、(11 5 7 2 17 3)
    C、(17 11 7 2 3 5)
    D、(17 11 7 5 3 2)
    E、(17 7 11 3 5 2)
    F、(17 7 11 3 2 5)

  4. 最小堆[0,3,2,5,7,4,6,8],在删除堆顶元素0之后,其结果是()
    A、[3,2,5,7,4,6,8]
    B、[2,3,5,7,4,6,8]
    C、[2,3,4,5,7,8,6]
    D、[2,3,4,5,6,7,8]

答案

1.A
2.C
3.C
4.C

三、堆的实现

3.1堆向下调整算法

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int array[] = {27,15,19,18,28,34,65,49,25,37};

在这里插入图片描述

3.2堆的创建

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

int a[] = {1,5,3,8,7,6}; 

在这里插入图片描述

3.3建堆时间复杂度

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):

在这里插入图片描述
因此:建堆的时间复杂度为O(N)。

3.4堆的插入

先插入一个10到数组的尾上,再进行向上调整算法,直到满足堆。

在这里插入图片描述

3.5堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

在这里插入图片描述

3.6堆的代码实现

typedef int HPDataType;
typedef struct Heap
{
 	HPDataType* _a;
 	int _size;
 	int _capacity; 
}Heap;
 
// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);

四、堆的具体实现代码

Heap.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* a;
	int capacity;
	int size;
}HP;

void Swap(HPDataType* a, HPDataType* b);//数据交换函数
void AdjustUp(HPDataType* a, int child);//向上交换
void AdjustDown(HPDataType* a, int n,int parent);//向下交换
//堆的初始化
void HPInit(HP* php);
//堆的销毁
void HPDestroy(HP* php);

//插入数据
void HPPush(HP* php,HPDataType x);

HPDataType HPTop(HP* php);//堆顶元素
//删除堆顶元素
void HPPop(HP* php);
bool HPEmpty(HP* php);

Heap.c

#include "Heap.h"
void HPInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->capacity =  php->size = 0;
}
void HPDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->capacity = php->size = 0;
}
void Swap(HPDataType* a, HPDataType* b)
{
	HPDataType temp = *a;
	*a = *b;
	*b = temp;
}
void HPPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->capacity == php->size)
	{
		size_t newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* newnode = (HPDataType*)realloc(php->a,sizeof(HPDataType) * newcapacity);
		if (newnode == NULL)
		{
			perror("newnode realloc : ");
			return;
		}
		php->a = newnode;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	AdjustUp(php->a, php->size - 1);
}
void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void HPPop(HP* php)
{
	assert(php);
	assert(!HPEmpty(php));
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}
void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent* 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
HPDataType HPTop(HP* php)
{
	assert(php);
	return php->a[0];
}
bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

Test.c

#include"Heap.h"

int main()
{
	//int a[] = { 50,100,70,65,60,32 };
	int a[] = { 60,70,65,50,32,100 };

	HP hp;
	HPInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HPPush(&hp, a[i]);
	}

	printf("%d\n", HPTop(&hp));
	HPPop(&hp);
	printf("%d\n", HPTop(&hp));
	while (!HPEmpty(&hp))
	{
		printf("%d\n", HPTop(&hp));
		HPPop(&hp);
	}

	HPDestroy(&hp);

	return 0;
}

堆的初始化

//堆的初始化
void HPInit(HP* php);
void HPInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->capacity =  php->size = 0;
}

堆是一种特殊的树形数据结构,通常用于实现优先队列。在初始化堆时,需要按照一定规则将元素填充到堆中。一般来说,堆的初始化可以采用从上到下、从左到右的方式遍历数组,对于每个非叶子节点,将其与其子节点中较大的一个进行交换,确保父节点的值不小于其子节点的值,从而满足堆的性质。这种操作被称为堆化或调整。通过遍历整个数组并进行堆化操作,最终可以得到一个满足堆性质的堆结构。

堆的销毁

//堆的销毁
void HPDestroy(HP* php);
void HPDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->capacity = php->size = 0;
}

堆的销毁是释放由堆分配的内存空间的过程。当不再需要堆上分配的对象时,必须显式地销毁它们以释放内存,防止内存泄漏。销毁操作通常通过调用对象的析构函数来完成,它会执行必要的清理任务,如释放对象拥有的资源。销毁后,对象变得无效,不应再被使用。在C++中,可以使用delete操作符来销毁堆上分配的对象。在销毁过程中,需要特别注意避免重复销毁和野指针问题。

数据交换函数

void Swap(HPDataType* a, HPDataType* b);//数据交换函数

void Swap(HPDataType* a, HPDataType* b)
{
	HPDataType temp = *a;
	*a = *b;
	*b = temp;
}

堆的向上交换

void AdjustUp(HPDataType* a, int child);//向上交换

void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

堆的向上交换是在堆排序算法中常用的一个操作。在堆排序过程中,当某个节点的值大于其父节点时,需要进行向上交换,即将该节点与其父节点交换位置,以保持堆的性质。这种交换操作从下往上进行,直至满足堆的定义要求。向上交换是堆排序中调整堆结构的关键步骤之一,有助于提高排序效率。

元素入堆

//插入数据
void HPPush(HP* php,HPDataType x);
void HPPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->capacity == php->size)
	{
		size_t newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* newnode = (HPDataType*)realloc(php->a,sizeof(HPDataType) * newcapacity);
		if (newnode == NULL)
		{
			perror("newnode realloc : ");
			return;
		}
		php->a = newnode;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	AdjustUp(php->a, php->size - 1);
}

元素入堆是指将一个元素插入到堆(Heap)这种数据结构中的过程。堆通常是一种特殊的树形数据结构,其每个父节点的值都大于或等于(在最大堆中)或小于或等于(在最小堆中)其子节点的值。元素入堆的过程通常涉及到调整堆的结构,以保持其性质。在插入新元素后,可能需要通过“上浮”或“下沉”操作来调整元素位置,确保堆的性质得以维持。这个过程对于堆排序、优先队列等算法至关重要。

堆的向下交换

void AdjustDown(HPDataType* a, int n,int parent);//向下交换

void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent* 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

堆的向下交换是堆排序算法中的一个重要步骤。在堆排序中,首先构建一个最大堆或最小堆,然后通过不断将堆顶元素与堆尾元素交换并重新调整堆结构,达到排序的目的。向下交换是指将堆顶元素与其子节点中较大的(对于最大堆)或较小的(对于最小堆)元素交换位置,然后重新调整子堆,以保持堆的性质。这个过程重复进行,直到整个堆排序完成。向下交换是堆排序算法中的关键步骤,能够确保堆的性质得以维持,从而实现快速排序。

元素出堆

void HPPop(HP* php);

void HPPop(HP* php)
{
	assert(php);
	assert(!HPEmpty(php));
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}

出堆操作是堆数据结构中的一种常见操作,主要用于从堆中移除并返回堆顶元素(即具有最大或最小值的元素)。在执行出堆操作时,首先需要将堆顶元素与堆的最后一个元素交换位置,然后调整剩余元素以维持堆的性质。对于最大堆,堆顶元素总是最大的,而对于最小堆,堆顶元素总是最小的。出堆操作的时间复杂度通常为O(log n),其中n是堆中元素的数量。通过出堆操作,可以高效地获取并删除堆中的最大或最小元素,从而在各种算法和数据结构中实现高效的数据处理和查询。

堆顶元素

HPDataType HPTop(HP* php);//堆顶元素

HPDataType HPTop(HP* php)
{
	assert(php);
	return php->a[0];
}

堆是否为空

bool HPEmpty(HP* php);
bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

五、堆的应用

5.1 数组向上调整建堆

void HPInitArray(HP* php, HPDataType* a, int n)
void HPInitArray(HP* php, HPDataType* a, int n)
{
	assert(php);
	php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->a == NULL)
	{
		perror("php->a malloc :");
		return;
	}
	memcpy(php->a, a, sizeof(HPDataType) * n);
	php->capacity = php->size = n;
	//向上排序 时间复杂度N*log N
	for (int i = 1; i < php->size; i++)
	{
		AdjustUp(php->a, i);
	}
}

数组向上调整建堆是一种构建堆(Heap)的方法,通常用于实现堆排序算法。该方法从数组的中间位置开始,将每个元素作为潜在的堆顶,然后通过向上调整操作,确保以该元素为根的子树满足堆的性质(最大堆或最小堆)。向上调整操作包括将根节点与其子节点比较,并在必要时交换它们的位置,以确保堆的性质得以维持。通过从数组的中间位置到第一个元素的顺序进行向下调整,最终可以构建出一个完整的堆结构。这种方法的时间复杂度为O(nlogn),其中n是数组的长度。
在这里插入图片描述

在这里插入图片描述

5.2数组向下调整建堆

void HPInitArray(HP* php, HPDataType* a, int n)
void HPInitArray(HP* php, HPDataType* a, int n)
{
	assert(php);
	php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->a == NULL)
	{
		perror("php->a malloc :");
		return;
	}
	memcpy(php->a, a, sizeof(HPDataType) * n);
	php->capacity = php->size = n;
	向上排序 时间复杂度N*log N
	//for (int i = 1; i < php->size; i++)
	//{
	//	AdjustUp(php->a, i);
	//}
	//向下排序,时间复杂度N
	for (int i = (php->size - 1) / 2; i >= 0; i--)
	{
		AdjustDown(php->a, php->size, i);
	}
}

数组向下调整建堆是指在构建一个最大堆(或最小堆)时,从数组末尾开始,逐个向上调整每个非叶子节点,使其满足堆的性质。具体步骤如下:

  1. 从最后一个非叶子节点开始,向前遍历数组。
  2. 对于每个节点,检查其是否满足堆的性质,即是否大于(或小于)其子节点。
  3. 如果不满足堆的性质,则将其与其较大的子节点交换位置,并继续向下调整子树,直到满足堆的性质。
  4. 重复步骤2和3,直到遍历完所有节点。

通过这种向下调整的方式,可以高效地构建一个最大堆(或最小堆),为后续的堆排序等操作提供基础。这种办法的时间复杂度是O(N).
在这里插入图片描述
在这里插入图片描述

5.3堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:

  • 建堆
    • 升序:建大堆
    • 降序:建小堆
  • 利用堆删除思想来进行排序

建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。

在这里插入图片描述

void HeapSort(HPDataType* 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[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

堆排序是一种基于二叉堆数据结构的排序算法。它首先将待排序序列构造成一个大顶堆(或小顶堆),然后依次将堆顶元素(最大值或最小值)与堆尾元素交换并删除,再通过调整堆结构使其保持为堆,重复此过程直至堆为空。这样,就能得到一个有序序列。堆排序的时间复杂度O(nlogn),空间复杂度为O(1)。

5.4TOP-K问题

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

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

对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:

  • 用数据集合中前K个元素来建堆
    • 前k个最大的元素,则建小堆
    • 前k个最小的元素,则建大堆
  • 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。
ps:剩余的数据可能是非递增的,想要递增的话,可以自己添加排序算法

直接建数据

void PrintTopK(int* a, int n, int k)
{
 // 1. 建堆--用a中前k个元素建堆
 
 // 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换
}
 
void TestTopk()
{
 	int n = 10000;
 	int* a = (int*)malloc(sizeof(int)*n);
 	srand(time(0));
 	for (size_t i = 0; i < n; ++i)
	 {
 		a[i] = rand() % 1000000;
 	}
	a[5] = 1000000 + 1;
 	a[1231] = 1000000 + 2;
 	a[531] = 1000000 + 3;
 	a[5121] = 1000000 + 4;
	a[115] = 1000000 + 5;
 	a[2335] = 1000000 + 6;
 	a[9999] = 1000000 + 7;
 	a[76] = 1000000 + 8;
 	a[423] = 1000000 + 9;
	a[3144] = 1000000 + 10;
 	PrintTopK(a, n, 10);
}

文件建数据

void CreateNDate()
{
	int k = 10000;
	srand((unsigned int)time(NULL));
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("pf fopen :");
		return;
	}
	for (int i = 0; i < k; i++)
	{
		fprintf(pf, "%d\n", rand()%10000 + i );
	}
	fclose(pf);
}

完整代码

test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
void CreateNDate()
{
	int k = 10000;
	srand((unsigned int)time(NULL));
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("pf fopen :");
		return;
	}
	for (int i = 0; i < k; i++)
	{
		fprintf(pf, "%d\n", rand()%10000 + i );
	}
	fclose(pf);
}
void Swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
void AdjustDown(int* a, int n, int parent)
{
	assert(a);
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			++child;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
int main()
{
	//CreateNDate();
	int k = 0;
	printf("输入需要排序的个数:  \n", &k);
	scanf("%d", &k);
	int* a = (int*)malloc(sizeof(int) * k);
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("pf fopen :");
		return;
	}
	for (int i = 0; i < k; i++)
	{
		fscanf(pf, "%d", &a[i]);
	}
	for (int i = (k - 1 - 1) / 2 ; i >= 0; i--)
	{
		AdjustDown(a, k, i);
	}
	int x = 0;
	while (fscanf(pf, "%d", &x) != EOF)
	{
		if (a[0] < x)
		{
			a[0] = x;
			AdjustDown(a, k, 0);
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", a[i]);
	}

	fclose(pf);
	return 0;
}
数据交换
void Swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
向下调整
void AdjustDown(int* a, int n, int parent)
{
	assert(a);
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			++child;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
主函数
int main()
{
	//CreateNDate();  在需要新数据的时候开启或关闭
	int k = 0;
	printf("输入需要排序的个数:  \n", &k);
	scanf("%d", &k);
	int* a = (int*)malloc(sizeof(int) * k);
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("pf fopen :");
		return;
	}
	for (int i = 0; i < k; i++)
	{
		fscanf(pf, "%d", &a[i]);
	}
	for (int i = (k - 1 - 1) / 2 ; i >= 0; i--)
	{
		AdjustDown(a, k, i);
	}
	int x = 0;
	while (fscanf(pf, "%d", &x) != EOF)
	{
		if (a[0] < x)
		{
			a[0] = x;
			AdjustDown(a, k, 0);
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", a[i]);
	}

	fclose(pf);
	return 0;
}

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

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

相关文章

二叉树相关题目

1.中序遍历和后序遍历构建二叉树&#xff1b; TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {//判空if(postorder.size() 0) return nullptr;//找到后序的最后元素就是根节点以及栈来存放数据auto rootnew TreeNode(postorder[post…

Hadoop大数据应用:Linux 部署 MapReduce 与 Yarn

目录 一、实验 1.环境 2.Linux 部署 MapReduce 3.Linux 部署 Yarn 4.Linux 调用大数据集群分析数据 二、问题 1.hadoop 的启动和停止命令 2.HDFS 使用命令 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构软件版本IP备注hadoop NameNode &#xf…

基于单片机的指纹采集识别系统设计

目 录 摘 要 I Abstract II 引 言 3 1 硬件选择与设计 5 1.1 总体设计及方案选择 5 1.1.1主控单片机选择 5 1.1.2传感器模块选择 6 1.1.3显示器模块选择 6 1.2 系统总体设计 7 2 系统硬件电路设计 8 2.1 系统主电路设计 8 2.1.1 主体电路设计 8 2.1.2 单片机最小系统设计 8 2.…

python的函数与类的定义

目录 1.函数 1.函数的定义 2.输入参数与输出参数的类型 3.输入和输出多个参数 1.普通参数 2.含有任意数量的参数 3.关键字参数 4.普通参数与多个参数的结合 2.类 1.类的定义 2.类的实例化 3.继承 1.函数 1.函数的定义 def 函数名(输入参数): 文档字符串 函数体 …

ElasticSearch深度分页问题如何解决

文章目录 概述解决方法深度分页方式from size深度分页之scrollsearch_after 三种分页方式比较 概述 Elasticsearch 的深度分页问题是指在大数据集上进行大量分页查询时可能导致的性能下降和资源消耗增加的情况。这种情况通常发生在需要访问大量数据的情形下&#xff0c;比如用…

finalshell连接cetOS7卡顿(配置完静态IP后出现的问题)

检查后的原因是:ssh服务端在连接时自动检测dns环境是否一致&#xff0c;这里将此次检测关闭即可 解决方案如下: vi /etc/ssh/sshd_config(打开后一直回车键到最下边)找到DNS&#xff0c;改为useDNS no&#xff08;默认为#useDNSyes&#xff09; 修改后重启服务&#xff1a; sys…

基于Java+SpringBoot+vue+element实现前后端分离玩具商城系统

基于JavaSpringBootvueelement实现前后端分离玩具商城系统 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文…

Pytorch入门实战 P2-CIFAR10彩色图片识别

目录 一、前期准备 1、数据集CIFAR10 2、判断自己的设备&#xff0c;是否可以使用GPU运行。 3、下载数据集&#xff0c;划分好训练集和测试集 4、加载训练集、测试集 5、取一个批次查看下 6、数据可视化 二、搭建简单的CNN网络模型 三、训练模型 1、设置超参数 2、编…

【Vue2】slot 插槽全家桶

插槽-默认插槽 插槽的基本语法 组件内需要定制的结构部分&#xff0c;改用<slot></slot>占位使用组件时, <MyDialog></MyDialog>标签内部, 传入结构替换slot给插槽传入内容时&#xff0c;可以传入纯文本、html标签、组件 插槽-默认值 封装组件时&am…

Nginx的日志怎么看,在哪看,access.log日志内容详解

Nginx 的日志文件通常位于服务器的文件系统中&#xff0c;具体位置可能因配置而异。以下是查看 Nginx 日志的几种方法&#xff1a; 1、查看访问日志&#xff1a;在默认配置下&#xff0c;Nginx 的访问日志文件路径为 /var/log/nginx/access.log。您可以通过命令 sudo cat /var…

创新营销的新篇章:企业如何通过VR虚拟发布会提升品牌影响力

在数字化转型的浪潮中&#xff0c;VR虚拟发布会作为一种新兴的营销手段&#xff0c;正逐渐成为企业品牌推广和产品发布的重要选择。通过利用虚拟现实技术&#xff0c;企业能够在虚拟空间中举办发布会&#xff0c;为参与者提供沉浸式的体验。 一、创新体验&#xff1a;虚拟空间的…

linux系统对于docker容器的监控

容器监控 容器监控原生命令操作问题 容器监控三剑客CAdvisorInfluxDBGranfana compose编排监控工具新建目录创建CIG.yml文件启动docker-compose测试 容器监控 CAdvisorInfluxDBGranfana 原生命令 操作 docker stats问题 通过docker stats命令可以很方便的看到当前宿主机上所…

【黑马程序员】Python文件操作

文章目录 文件操作文件编码什么是编码为什么要使用编码 文件的读取openmodel常用的三种基础访问模式读操作相关方法 文件的写入注意代码示例 文件操作 文件编码 什么是编码 编码就是一种规则集合&#xff0c;记录了内容和二进制间进行互相转换的规则 最常用的是UTF-8编码 …

魔法手链(burnside+矩阵优化+dp acwing 3134)

题目&#xff1a;3134. 魔法手链 - AcWing题库 思路&#xff1a; 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #i…

史上最全Spring教程,从零开始带你深入♂学习(三)—

减少数据处理量&#xff0c;提高查询效率 (一)使用Limit分页 –从第2个开始查询&#xff0c;每一页10个 select * from user limit 2,10 –从第0个开始查询&#xff0c;每一页10个 SELECT * from user limit 10; 领取资料 (二)使用Mybatis实现分页&#xff0c;核心SQL 1、编…

小文件问题及GlusterFS的瓶颈

01海量小文件存储的挑战 为了解决海量小文件的存储问题&#xff0c;必须采用分布式存储&#xff0c;目前分布式存储主要采用两种架构&#xff1a;集中式元数据管理架构和去中心化架构。 (1)集中式元数据架构&#xff1a; 典型的集中式元数据架构的分布式存储有GFS&#xff0…

一、NLP中的文本分类

目录 1.0 文本分类的应用场景 1.1 文本分类流程 ​编辑 1.2 判别式模型 1.3 生成式模型 1.4 评估 1.5 参考文献 NLP学习笔记系列&#xff0c;欢迎收藏交流&#xff1a; 零、自然语言处理开篇-CSDN博客 一、NLP中的文本分类-CSDN博客 二、NLP中的序列标注&#xff08;分…

413 Request Entity Too Large 问题如何解决

遇到“413 Request Entity Too Large”错误通常意味着你尝试上传或提交到服务器的数据量超过了服务器能够处理的限制。这个问题通常与Web服务器的配置相关&#xff0c;比如Nginx或Apache。这个问题出现在使用Nginx作为Web服务器的环境中。这里有几种解决方法&#xff1a; 1. 调…

openGauss学习笔记-242 openGauss性能调优-SQL调优-典型SQL调优点-SQL自诊断

文章目录 openGauss学习笔记-242 openGauss性能调优-SQL调优-典型SQL调优点-SQL自诊断242.1 SQL自诊断242.1.1 告警场景242.1.2 规格约束 openGauss学习笔记-242 openGauss性能调优-SQL调优-典型SQL调优点-SQL自诊断 SQL调优是一个不断分析与尝试的过程&#xff1a;试跑Query&…

流水账-20240314

目录 Linux系统删除文件后&#xff0c;磁盘大小没变化mysql事务和neo4j事务冲突误诊描述解决方法网上提供的方法重置Neo4j密码&#xff0c;成功解决问题高版本低版本 Linux系统删除文件后&#xff0c;磁盘大小没变化 lsof L1|grep 删除的文件名kill进程 mysql事务和neo4j事务…