二叉树的存储结构(顺序存储)—— 数据结构与算法

news2024/11/24 22:31:23

在这里插入图片描述
请添加图片描述

😶‍🌫️Take your time ! 😶‍🌫️
💥个人主页:🔥🔥🔥大魔王🔥🔥🔥
💥代码仓库:🔥🔥魔王修炼之路🔥🔥
💥所属专栏:🔥魔王的修炼之路–数据结构🔥
如果你觉得这篇文章对你有帮助,请在文章结尾处留下你的点赞👍和关注💖,支持一下博主。同时记得收藏✨这篇文章,方便以后重新阅读。


文章目录

  • 一、前言
  • 二、二叉树的顺序存储结构
    • 1、二叉树采取顺序存储的原因
    • 2、堆的概念及结构
  • 三、堆的实现
    • 1、介绍
    • 2、向上调整建堆
      • 说明
      • 实现
    • 3、向下调整建堆
      • 说明
      • 实现
    • 4、向上向下调整时间复杂度
    • 5、堆的插入
    • 6、堆的删除
    • 7、总代码
      • Heap.h
      • Heap.c
      • Test.c
  • 四、堆的应用
    • 堆排序
      • 介绍
      • 实现
    • TOP-K问题
  • 五、总结

一、前言

上一篇博客详细讲述了二叉树的概念,那么接下来这篇博客将讲述二叉树的存储方式的一种:顺序存储。

二、二叉树的顺序存储结构

1、二叉树采取顺序存储的原因

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

2、堆的概念及结构

  • 堆可以这么理解:它是一个完全二叉树,并且完全二叉树都可以转变为堆,为什么说堆是特殊的二叉树呢?因为堆其实就是把这个完全二叉树变得有规律了。

堆分为大根堆和小根堆。
大根堆:所有父节点都不小于子节点。
小根堆:所有父节点都不大于子节点。
需要注意的是:兄弟节点之间没有什么联系,可以大于可以小于也可以相等。

在这里插入图片描述

三、堆的实现

1、介绍

实现堆的方法:有两种,分别为向上调整建堆和向下调整建堆。

  • 需要注意的是,无论是向上调整还是向下调整,我们都需要保证的前提是除了要调整的这个元素外,其余节点本身就是一个堆(大根堆或小根堆),也就是说是在原本堆的基础上进行的向下和向上调整。

2、向上调整建堆

说明

向上调整建堆:就像刚才说的,我们进行调整时其本身必须为一个堆,因此我们只能一点一点的调整,所以从第二个开始向上调整(因为第一个没有比较的东西,所以从第二个开始调整),使每次比较都能是在原本就是堆的基础上进行。如图:从红色位置开始向上调整建堆。
在这里插入图片描述

实现

  • 建大堆
    在这里插入图片描述
//向上调整建大堆
#include <stdio.h>

void AdjustUp(int* a,int n)
{
	int child = n;
	int parent = (child - 1) / 2;
	while (child > 0)
	//判断条件不能为parent,因为parent为整型,但是最后那个结果是-0.5,对于整型来说,浮点数小数点后的忽略,那么此时parent还是0,child也变成0了,它们的值会相等然后return,虽然这样程序照样过了,但是这种想法其实是错的,所以我们通过判断child是否>0来作为是否结束的标志。
	{
		if (a[child] > a[parent])
		{
			int temp = a[child];
			a[child] = a[parent];
			a[parent] = temp;
		}
		else
			return;//如果子节点小于父亲节点那么本次循环就不用比了,因为再向上比的那些之前已经调整过了。
		child = parent;
		parent = (parent - 1) / 2;
	}
}

int main()
{
	int a[7] = { 2,5,6,7,4,9,3 };
	int size = sizeof(a) / sizeof(int);
	int n = 1;
	while (n < size)
	{
		AdjustUp(a, n);
		n++;
	}
	for (int n = 0; n < size; n++)
	{
		printf("%d ", a[n]);
	}
	return 0;
}

3、向下调整建堆

说明

向下调整建堆:和向上调整很像,也必须一点一点的建,只不过是从下面开始,我们跳过最后一层,层倒数第二层开始逐个向下调整(确保除了要调整的这个,其余参与的节点本身构成一个堆)。如图:
在这里插入图片描述

实现

  • 大根堆

在这里插入图片描述

//向下调整建大堆
#include <stdio.h>
void AdjustDown(int* a, int n,int size)
{
	int parent = n;
	int child = n * 2 + 1;//先假设左子树是孩子中较大的,然后再进行判断,看是否替换为右子树(右子树需要存在)。
	while (child < size)
	{
		if (child + 1 < size && a[child] < a[child + 1])//第一个判断的原因是首先右子树要存在才能比较。
		{
			child = child + 1;
		}

		if (a[parent] < a[child])
		{
			int temp = a[parent];
			a[parent] = a[child];
			a[child] = temp;
		}
		parent = child;
		child = child * 2 + 1;
	}
}
int main()
{
	int a[7] = { 2,5,6,7,4,9,3};
	int size = sizeof(a) / sizeof(int);
	int n = (size - 2) / 2;
	while (n >= 0)
	{
		AdjustDown(a, n,size);
		n--;
	}
	n = 0;
	while (n < size)
	{
		printf("%d ", a[n]);
		n++;
	}
	return 0;
}
  • 就像上面两幅图,虽然相同的数采用向上和向下调整建堆的方法建出来的堆不太一样,但是都是大根堆。

4、向上向下调整时间复杂度

  • 向上调整建堆时间复杂度:O(N*logN) --向上调整建堆时层的结点个数少时向上的层数少(也就相当于每个遍历的次数少),层的结点个数多时向上的层数多(每个节点遍历的次数多),因此时间复杂度大。
  • 向下调整建堆时间复杂度:O(N) --向下调整建堆时层的结点个数多时向下的层数少,层的结点个数少时向下的层数多,所以会比向上调整效率高。
  • 向下调整时间复杂度证明
    在这里插入图片描述

向上调整与这个证明过程类似。

5、堆的插入

先将这个元素插入到尾部,然后让这个数据进行向上调整就行了。

6、堆的删除

让根与最后一个元素交换位置,然后让数组删除最后一个元素(size–),然后让这个取代根位置的元素进行向下调整即可。

7、总代码

Heap.h

#pragma once

typedef int HeapDateType;

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct Heap
{
	HeapDateType* a;
	int size;
	int capacity;
}Heap;

//堆的初始化
void HeapCreat(Heap* php);

//堆的销毁
void HeapDestory(Heap* php);

//堆的插入
void HeapPush(Heap* php, HeapDateType x);

//堆的删除
void HeapPop(Heap* php);

//取堆顶的数据
HeapDateType HeapTop(Heap* php);

//堆的数据个数
int HeapSize(Heap* php);

//堆的判空
int HeapEmpty(Heap* php);

Heap.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Heap.h"


//堆的初始化
void HeapInit(Heap* php)
{
	assert(php);
	php->a = (HeapDateType*)malloc(sizeof(HeapDateType) * 4);
	if (php->a == NULL)
	{
		perror("malloc error");
		assert(php);
	}
	php->size = 0;
	php->capacity = 4;
}

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

//数据交换
void Swap(HeapDateType* a, HeapDateType* b)
{
	int temp = 0;
	temp = *b;
	*b = *a;
	*a = temp;
}

void AdjustUp(HeapDateType* a, int n)
{
	assert(a);
	int child = n - 1;
	int parent = (child - 1) / 2;
	while (child > 0)
    //判断条件不能为parent,因为parent为整型,但是最后那个结果是-0.5,对于整型来说,浮点数小数点后的忽略,那么此时parent还是0,child也变成0了,它们的值会相等然后return,虽然这样程序照样过了,但是这种想法其实是错的,所以我们通过判断child是否>0来作为是否结束的标志。
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);//后面还会用到交换,所以封装成一个函数。
		}
		else
			return;
		child = parent;
		parent = (parent - 1) / 2;
	}
}

//堆的插入
void HeapPush(Heap* php,HeapDateType x)
{
	assert(php);
	if (php->capacity == php->size)
	{
		HeapDateType* inspect = realloc(php->a, sizeof(HeapDateType) * php->capacity * 2);
		if (inspect == NULL)
		{
			perror("realloc error");
			assert(inspect);
		}
		php->a = inspect;
		inspect = NULL;
		php->capacity *= 2;
	}

	php->a[php->size] = x;
	php->size++;
	AdjustUp(php->a, php->size);
}

//向上向下调整的前提是必须调整前是一个堆(大堆或者小堆)
void AdjustDown(HeapDateType* a, int n,int parent)
{
	assert(a);
	int child = parent*2+1;//默认向下调整是跟左孩子交换,如果下面比较左右孩子大小时右孩子大,那么让child+1即可表示与右孩子交换。
	while (child <= n)
	{
		if (child < n&& (a[child] < a[child + 1]))//前提是要有右兄弟,不然就会越界
		{
			child = child + 1;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
		}
		else
			return;
		parent = child;
		child = child * 2 + 1;
	}
}

//堆的删除(删除的是堆顶,也就是根)
void HeapPop(Heap* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	Swap(&php->a[php->size - 1], & php->a[0]);//直接让最后一个覆盖根也行,因为根是要删掉的,就算这样交换了,下面size--后,根还是没有了。
	php->size--;
	AdjustDown(php->a, php->size,0);
}

//取堆顶的数据
HeapDateType HeapTop(Heap* php)
{
	assert(php);
	return php->a[0];
}

//堆的数据个数
int HeapSize(Heap* php)
{
	assert(php);
	return php->size;

}

//堆的判空
int HeapEmpty(Heap* php)
{
	assert(php);
	return php->size == 0;
}

Test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Heap.h"


int main()
{
	Heap hp;
	HeapInit(&hp);

	HeapPush(&hp, 0);
	HeapPush(&hp, 47);
	HeapPush(&hp, 26);
	HeapPush(&hp, 48);
	HeapPush(&hp, 52);
	HeapPush(&hp, 79);
	HeapPush(&hp, 6);
	HeapPush(&hp, 83);
	HeapPush(&hp, 38);
	HeapPush(&hp, 24);

	HeapPop(&hp);
	HeapPop(&hp);
	HeapPop(&hp);
	HeapPop(&hp);

	return 0;
}

四、堆的应用

堆排序

介绍

  • 虽然我们知道堆分为大根堆和小根堆,子节点和父节点有明确的大小关系,但因为兄弟节点的大小关系不确定,随意实际在数组中并不是顺序存放的,我们利用堆里删除元素的思想对堆进行排序。
  • 规律:升序建大堆,降序建小堆!
  • 原因如下:

对于升序建大堆来说:我们采用的方法是每次将根与最后一个元素交换位置,然后让这个堆忽略掉末尾元素(size–)(也就是原来的根,因为它已经到了应该的位置了),然后一直这样,直到这个堆只剩下一个元素,那么此时就排好了。
在这里插入图片描述

  • 注意:堆排序首先是要建堆

实现

//堆排序实现
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//数据交换
void Swap(int* a, int* b)
{
	int temp = 0;
	temp = *b;
	*b = *a;
	*a = temp;
}

void AdjustUp(int* a, int n)
{
	assert(a);
	int child = n - 1;
	int parent = (child - 1) / 2;
	while (parent >= 0)
		//判断条件不能为parent,因为parent为整型,但是最后那个结果是-0.5,对于整型来说,浮点数小数点后的忽略,那么此时parent还是0,child也变成0了,它们的值会相等然后return,虽然这样程序照样过了,但是这种想法其实是错的,所以我们通过判断child是否>0来作为是否结束的标志。
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);//后面还会用到交换,所以封装成一个函数。
		}
		else
			return;
		child = parent;
		parent = (parent - 1) / 2;
	}
}

//向上向下调整的前提是必须调整前是一个堆(大堆或者小堆)
void AdjustDown(int* a, int n, int parent)
{
	assert(a);
	int child = parent * 2 + 1;//默认向下调整是跟左孩子交换,如果下面比较左右孩子大小时右孩子大,那么让child+1即可表示与右孩子交换。
	while (child < n)
	{
		if (child < n - 1 && (a[child] < a[child + 1]))//前提是要有右兄弟,不然就会越界
		{
			child = child + 1;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
		}
		else
			return;
		parent = child;
		child = child * 2 + 1;
	}
}

void HeapSort(int* arr, int size)//假设要求升序排列
{
	向上调整建大堆--时间复杂度为N*logN
	//for (int n = 2; n < size; n++)
	//{
	//	AdjustUp(arr, n);
	//}
	//向下调整建堆--时间复杂度为N
	for (int n = (size - 2) / 2; n >= 0; n--)//size-1是指最后一个元素的下标,另一个-1是公式套的
	{
		AdjustDown(arr, size, n);
	}
	//排序--第一个和最后一个替换,然后让新根向下调整即可,这样就让该堆中最大的数放到了该放的位置。
	while (size--)
	{
		Swap(&arr[0], &arr[size]);
		AdjustDown(arr, size, 0);
	}
}

int main()
{
	int arr[] = { 45,26,91,34,82,41,67,81,47,35 };
	HeapSort(arr, sizeof(arr) / sizeof(int));
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

TOP-K问题

  • TOP-K问题:即当求数据结合中前K个最大或者最小元素,一般情况下数据量会很大。比如:世界500强,富豪榜等等。你可能会想,直接排序不就行了,但是如果当数据量特别大时,整个内存都放不下,这时候最佳方法就是使用堆排序。

求最大的前k个:建小堆。
求最小的前k个,建大堆。

  • 解释:因为TOP-K一般是求前k个最值数,所以我们需要将其找出来,但是当数据特别多时,内存放不下,所以就不能使用堆排序(内存放不下),因此我们用另外的方法:假设求最大的前K个,我们先建一个k个数的小堆,然后我们将剩下的数放进文件(磁盘)里,然后分别与小堆的根(最小的数比较),如果大于这个根,那么直接覆盖上去,并让新根进行向下调整,使得覆盖后仍然是一个小堆。
  • 注意:不能与我们建的堆的最后一个元素比,因为它不一定是最大或最小,只有根我们才能确定它一定是一个最值。

五、总结

  • 升序建大堆,降序建小堆原因:假如升序建小堆,那么第一个当然就是我们要的最小的数,但是之后就不行了,因为虽然这个位置是最小的不用动了,但是当我们找第二小的时,我们就要忽略掉第一个已经定了的这个,那么这次谁当根呢,直接父子兄弟什么的全乱了,我们只能再次通过(N-1)个数进行一次堆排序建立一个新堆然后新堆的根就是第二小的,但是这样就太麻烦了,因为建一次堆的时间复杂度就是O(N*logN)(向上调整建堆)或者O(N)(向下调整建堆)而如果建成相反的(大堆),然后根和最后一个元素换一下再向下调整,这样就能确定最大的数,一次时间复杂度是logN。
  • 关于堆(顺序存储)的所有操作注意:就是尽量不破坏原本堆的结构,不让父子乱辈,不然就可能乱了很多,处理起来就很麻烦,只能重新建堆。
  • TOP-K问题总结:求最大的建小堆,求最小的建大堆。

  • 博主长期更新,博主的目标是不断提升阅读体验和内容质量,如果你喜欢博主的文章,请点个赞或者关注博主支持一波,我会更加努力的为你呈现精彩的内容。

🌈专栏推荐
😈魔王的修炼之路–C语言
😈魔王的修炼之路–数据结构初阶
😈魔王的修炼之路–C++
😈魔王的修炼之路–Linux
更新不易,希望得到友友的三连支持一波。收藏这篇文章,意味着你将永久拥有它,无论何时何地,都可以立即找到重新阅读;关注博主,意味着无论何时何地,博主将永久和你一起学习进步,为你带来有价值的内容。

请添加图片描述

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

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

相关文章

《雷达像智能识别对抗研究进展》阅读记录

&#xff08;1&#xff09;引言 ​ 神经网络通常存在鲁棒性缺陷&#xff0c;易受到对抗攻击的威胁。攻击者可以隐蔽的诱导雷达智能目标识别做出错误预测&#xff0c;如&#xff1a; ​ a图是自行车&#xff0c;加上对抗扰动后神经网络就会将其识别为挖掘机。 &#xff08;2&a…

一探Linux下的七大进程状态

文章目录 一、前言二、操作系统学科下的进程状态1、运行状态2、阻塞状态3、挂起状态 三、Linux下的7种进程状态1、运行状态R2、浅度睡眠状态S3、深度睡眠状态D一场有趣的官司 4、停止状态T5、进程跟踪状态t6、死亡状态X7、僵死状态Z —— 两个特殊进程① 僵尸进程② 孤儿进程 四…

算法竞赛备赛之搜索与图论训练提升,暑期集训营培训

目录 1.DFS和BFS 1.1.DFS深度优先搜索 1.2.BFS广度优先搜索 2.树与图的遍历&#xff1a;拓扑排序 3.最短路 3.1.迪杰斯特拉算法 3.2.贝尔曼算法 3.3.SPFA算法 3.4.多源汇最短路Floy算法 4.最小生成树 4.1.普利姆算法 4.2.克鲁斯卡尔算法 5.二分图&#xff1a;染色法…

嵌入式学习之strcpy、memset、realloc、malloc使用方法

今天主要针对C语言的strcpy memset realloc mallooc函数进行了学习。 char* strcpy(char* destination,const char* source); void memset ( void *s , char ch, unsigned n )&#xff1b; void* realloc(void* memblock, size_t size)&#xff1b; void *malloc(size_t si…

tkinter打造三维绘图系统,附源代码

文章目录 输入数据加载数据绘图函数源代码 Python绘图系统系列&#xff1a;将matplotlib嵌入到tkinter 简单的绘图系统 数据导入 输入数据 三维绘图需要一个新的坐标变量&#xff0c;设置为z&#xff0c;这个改改UI就可以办到&#xff0c;并不困难。但是&#xff0c;此前用于…

git安装介绍

一、分布式版本控制系统Git概述 1.1 分布式版本控制系统Git介绍 版本控制定义 记录和跟踪项目中各文件内容的改动变化 保存项目的版本历史&#xff0c;以及改动原因&#xff0c;从而让用户能够查看各个历史版本 版本控制系统也是帮助人员进行协作开发的利器 为什么需要版本…

WebRTC音视频通话-WebRTC本地视频通话使用ossrs服务搭建

iOS开发-ossrs服务WebRTC本地视频通话服务搭建 之前开发中使用到了ossrs&#xff0c;这里记录一下ossrs支持的WebRTC本地服务搭建。 一、ossrs是什么&#xff1f; ossrs是什么呢&#xff1f; SRS(Simple Realtime Server)是一个简单高效的实时视频服务器&#xff0c;支持RTM…

福康源:用孝道温暖每一个心灵,共筑幸福健康新人生!

福康源&#xff1a;用孝道温暖每一个心灵&#xff0c;共筑幸福健康新人生 孝道的光芒&#xff1a;福康源的初心 在浮躁的现代社会&#xff0c;孝道的力量正被越来越多的人忽略。然而&#xff0c;福康源的初心却始终坚守孝顺的真谛。孝道不仅是对父母的敬爱&#xff0c;更是一种…

【解析postman工具的使用---基础篇】

postman前端请求详解 主界面1.常见类型的接口请求1.1 查询参数的接口请求1.1.1 什么是查询参数?1.1.2 postman如何请求 1.2 ❤表单类型的接口请求1.2.1 复习下http请求1.2.2❤ 什么是表单 1.3 上传文件的表单请求1.4❤ json类型的接口请求 2. 响应接口数据分析2.1 postman的响…

程序设计 树基础

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

Lorilla LLM - 面向API调用生成的专用AI大模型

Gorilla 是一种先进的大型语言模型 (LLM)&#xff0c;旨在与各种 API 有效交互&#xff0c;从而增强 LLM 在实际应用中的功能。 Gorilla LLM的相关链接&#xff1a;官网 | github | 论文。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 1、Gorilla LLM简介 通过使用自…

CentOS 项目作出声明,宣称自家 Linux 社区 “始终向所有人开放”

导读在红帽 RHEL 开源事件后&#xff0c;许多兼容 RHEL 的发行版最近都进行了表态&#xff0c;CentOS 项目也在日前作出了声明&#xff0c;宣称自家社区 “始终向所有人开放”。 据悉&#xff0c;CentOS 项目董事会日前在官方博客发布了一则公告&#xff0c;内容主要涉及“ Ce…

拒绝摆烂!C语言练习打卡第一天

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;每日一练 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ &#x1f5d2;️前言&#xff1a; 在前面我们学习完C语言的所以知识&#xff0c;当…

LangChain手记 Models,Prompts and Parsers

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Models,Prompts and Parsers 模型&#xff0c;提示词和解析器&#xff08;Models, Prompts and Parsers&#xff09; 模型&#xff1a;大语言模型提示词&#xff1a;构建传递给模型的输入的方式解析器&#xff1a;…

NAS搭建指南二——影视资源中心

1. 刮削 这一部分是利用 tinyMediaManager 进行影视资源的评分、简介以及图片的搜集工作tinyMediaManager 官方网站地址下载及安装过程&#xff1a;略我的主要修改的设置项如下所示&#xff1a; 使用方法&#xff1a; a. 点击更新媒体库 b. 选择影片–>右键单击–>…

Ubuntu 20.04(服务器版)安装 Anaconda

0、Anaconda介绍 Anaconda是一个开源的Python发行版本&#xff0c;包含了包括Python、Conda、科学计算库等180多个科学包及其依赖项。因此&#xff0c;安装了Anaconda就不用再单独安装CUDA、Python等。 CUDA&#xff0c;在进行深度学习的时候&#xff0c;需要用到GPU&#xf…

生信分析pandas数据处理 Python简明教程 | 视频18

开源生信 Python教程 生信专用简明 Python 文字和视频教程 源码在&#xff1a;https://github.com/Tong-Chen/Bioinfo_course_python 目录 背景介绍 编程开篇为什么学习Python如何安装Python如何运行Python命令和脚本使用什么编辑器写Python脚本Python程序事例Python基本语法 数…

软件开发中常用数据结构介绍:C语言链表

工作之余来写写C语言相关知识&#xff0c;以免忘记。今天就来聊聊C语言链表&#xff0c;我是分享人M哥&#xff0c;目前从事车载控制器的软件开发及测试工作。 学习过程中如有任何疑问&#xff0c;可底下评论&#xff01; 如果觉得文章内容在工作学习中有帮助到你&#xff0c;麻…

干不完根本干不完,我也不想加班,快来围观时间管理大师

时间不够用&#xff0c;怎么办&#xff1f; 成功不靠加班。生产队的驴都不加班&#xff0c;你加什么班&#xff1f;到点就下班&#xff0c;该玩玩&#xff0c;该学习认真学&#xff0c;累了就睡觉。 你可以做任何事&#xff0c;但不必做所有事。 时间管理&#xff0c;不是管…

(十七)大数据实战——Hive的hiveserver2服务安装部署

前言 HiveServer2 是 Apache Hive 的一个服务器端组件&#xff0c;用于支持客户端与 Hive 进行交互和执行查询。HiveServer2服务的作用是提供jdbc/odbc接口&#xff0c;为用户提供远程访问Hive数据的功能。HiveServer2 允许多个客户端同时连接并与 Hive 交互。这些客户端可以通…