【数据结构与算法】堆 / 堆排序 / TopK问题(Heap)

文章目录

  • 1.堆
  • 2.C语言实现堆
    • 2.1 堆结构与基本操作
    • 2.2 其它辅助操作
    • 2.3 堆的基本操作
      • 2.3.1 插入
      • 2.3.2 删除
  • 3. 堆排序
  • 4. TopK
  • 5. 所有代码

1.堆

堆总是一棵完全二叉树,而完全二叉树更适合使用**顺序结构(数组)**存储,完全二叉树前h-1层是满的,最后一层不一定是满的,但节点一定连续的。需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
在这里插入图片描述
非完全二叉树不适合用数组来存储,因为存在空间浪费。而极端的二叉搜索树则会造成更多浪费,二叉搜索树即右孩子节点比父节点大,左孩子节点比父节点小的树。
在这里插入图片描述
使用数组存储二叉树,基于父子节点下标间的关系:leftchild = parent * 2 + 1,rightchild = parent * 2 + 2,parent = (child - 1) / 2,如果打破这种存储关系则数组无法表示二叉树,所以数组存储非完全二叉树注定要浪费空间。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。最大堆即任意一个父节点都大于等于孩子节点,最小堆即任意一个父节点都小于等于孩子节点。
在这里插入图片描述

满二叉树实际上也是一棵特殊的完全二叉树,树的每一层都是满节点即是满二叉树。满二叉树有这样一个规律,第一层的节点数为20,第二层节点数为21,假设树的高度为h,则第h层的节点数为2h-1,不难看出是一个等比数列,所以满二叉树的节点数量为2h-1。
在这里插入图片描述
基于这样一个规律,则完全二叉树最多有2h-1个节点,最少有2h-1个节点:[2h-1,2h-1]。知道了节点数量,也就知道了树的高度h:假设N是节点数量,N = 2h-1,则h = log2(N) + 1;N = 2h-1,则h = log2(N+1)。

2.C语言实现堆

2.1 堆结构与基本操作

堆结构看起来与顺序表无异,毕竟都是数组实现。不一样的是逻辑结构,顺序表是线性结构,堆是树形结构。堆的基本操作只有插入和删除,应用场景有堆排序和TopK(前k个最大或最小的数)。

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

// 堆结构
typedef int datatype;
typedef struct Heap {
	datatype* arr;
	int size;
	int capacity;
} Heap;

// 其它辅助操作
void HeapInit(Heap* heap);
void HeapDestroy(Heap* heap);
datatype HeapTop(Heap* heap); // 取堆顶元素
size_t HeapSize(Heap* heap);
bool HeapEmpty(Heap* heap);

// logn
void HeapPush(Heap* heap, datatype val);
void HeapPop(Heap* heap); // 删除堆顶元素
// 插入或删除时,堆向上、向下调整
void Swap(datatype* x, datatype* y);
void AdjustUp(datatype* arr, int child);
void AdjustDown(datatype* arr, int size, int parent);

// 堆排序 nlogn、求TopK nlogk
void HeapSort(datatype* arr, int size);
void PrintTopK(const char* file, int k);

2.2 其它辅助操作

void HeapInit(Heap* heap) {
	assert(heap);
	heap->arr = NULL;
	heap->size = heap->capacity = 0;
}

void HeapDestroy(Heap* heap) {
	assert(heap);
	free(heap->arr);
	heap->arr = NULL;
	heap->size = heap->capacity = 0;
}

datatype HeapTop(Heap* heap) {
	assert(heap && heap->arr && heap->size > 0);
	return heap->arr[0];
}

size_t HeapSize(Heap* heap) {
	assert(heap);
	return heap->size;
}

bool HeapEmpty(Heap* heap) {
	assert(heap);
	return heap->size == 0;
}

2.3 堆的基本操作

2.3.1 插入

直接往数组插入数据,然后再向上调整即可。以构建最小堆举例,只要插入的数据比父节点小,就与父节点交换,重复这个操作直到不能再做交换。

void HeapPush(Heap* heap, datatype val) {
	assert(heap);
	if (heap->size == heap->capacity) { // 空间不够时扩容
		heap->capacity = heap->capacity == 0 ? 10 : heap->capacity * 2;
		datatype* tmp = realloc(heap->arr, sizeof(datatype) * heap->capacity);
		if (tmp == NULL) {
			perror("HeapPush malloc failed.");
			exit(-1);
		}
		heap->arr = tmp;
	}
	// 插入
	heap->arr[heap->size++] = val;
	AdjustUp(heap->arr, heap->size - 1);
}
void Swap(datatype* x, datatype* y) {
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
// logn
void AdjustUp(datatype* arr, int child) {
	int parent = (child - 1) / 2;
	while (child > 0 && arr[child] < arr[parent]) {
		Swap(&arr[child], &arr[parent]); // up
		child = parent;
		parent = (child - 1) / 2;
	}
}

如果将while循环的条件arr[child] < arr[parent]改成大于arr[child] > arr[parent],则是调整构建最大堆。

Heap heap;
HeapInit(&heap);
// 建堆 nlogn
HeapPush(&heap, 67864);
HeapPush(&heap, 7432);
HeapPush(&heap, 854312);
HeapPush(&heap, 909876);
HeapPush(&heap, 8765);
HeapPush(&heap, 2345678);
HeapPush(&heap, 2563);
HeapPush(&heap, 12676);
HeapPush(&heap, 6543);
HeapPush(&heap, 2167);
for (int i = 0; i < heap.size; i++) {
	printf("%d ", heap.arr[i]);
}
HeapDestroy(&heap);

在这里插入图片描述

2.3.2 删除

删除堆元素,只能删除堆顶元素,这是合理的规定,其它诸如任意删除、删除最后一个元素的操作对堆而言都是没有意义的。

如果是直接删除堆顶元素,数组剩下的元素不再构成堆,所以不能这么做。还是以最小堆为例,(1)标准的实现是:将堆顶元素与数组最后一个元素进行交换,即最小的数与较大的数交换,接着删除最后一个元素,然后再向下调整,目的是将堆顶元素往下沉,重新构建最小堆;(2)向下调整的思路:从左右孩子节点中选出最小的,这个孩子节点比父节点小就做交换,重复这个操作。

void HeapPop(Heap* heap) {
	assert(heap && heap->arr && heap->size > 0);
	Swap(&heap->arr[0], &heap->arr[--heap->size]);
	AdjustDown(heap->arr, heap->size, 0);
}
void Swap(datatype* x, datatype* y) {
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
// logn
void AdjustDown(datatype* arr, int size, int parent) {
	int child = parent * 2 + 1; // left or right 
	child = child + 1 < size && arr[child + 1] < arr[child]
										? ++child : chi
	// child<parent调整为小堆,child>parent调整为大堆 
	while (child < size && arr[child] < arr[parent]) {
		Swap(&arr[child], &arr[parent]); // down
		parent = child;
		child = parent * 2 + 1; // left or right
		child = child+1 < size && arr[child+1] < arr[child]
										? ++child : child;
	}
}

如果将arr[child + 1] < arr[child]改成arr[child + 1] > arr[child],以及while循环的条件arr[child] < arr[parent]改成大于arr[child] > arr[parent],则是调整构建最大堆。

Heap heap;
HeapInit(&heap);
// 建堆 nlogn
HeapPush(&heap, 67864);
HeapPush(&heap, 7432);
HeapPush(&heap, 854312);
HeapPush(&heap, 909876);
HeapPush(&heap, 8765);
HeapPush(&heap, 2345678);
HeapPush(&heap, 2563);
HeapPush(&heap, 12676);
HeapPush(&heap, 6543);
HeapPush(&heap, 2167);
while (!HeapEmpty(&heap)) {
	printf("%d ", HeapTop(&heap));
	HeapPop(&heap);
}
HeapDestroy(&heap);

在这里插入图片描述
这其实相当于排了个序,时间复杂度为nlogn。不过由于还有插入操作的时间复杂度nlogn,所以整体时间复杂度为2n*2logn。

另外这也能解决TopK问题:

int k = 3; 
while (k--) {
	printf("%d ", HeapTop(&heap));
	HeapPop(&heap);
}

3. 堆排序

前面借助堆基本操作Top和Pop也能做到堆排序,不过却比较麻烦,因为需要实现堆的基本操作。这里所指的堆排序是指,直接将数组构建成堆然后排序,不包含建堆的时间则堆排序的时间复杂度为nlogn。
在这里插入图片描述

// 排升序则构建大堆,排降序则构建小堆
void HeapSort(datatype* arr, int size) {
	// 建堆 O(nlogn) 
	//for (int i = 1; i < size; ++i) {
	//	AdjustUp(arr, i);  
	//}

	// 建堆 O(n) 并非是nlogn
	for (int i = (size - 1 - 1) / 2; i >= 0; --i) {
		AdjustDown(arr, size, i);
	}

	// 排序 O(nlogn)
	for (int end = size - 1; end > 0; --end) {
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, end, 0);
	}
}

利用向下调整建堆的时间复杂度为O(n)的原因是,最后一层不需要向下调整,直接从倒数第二层开始向下调整,这节省了很多时间复杂度,毕竟最后一层的节点占了堆节点总数一半。每一层的节点数量越多,向下调整次数越少;每一层的节点数量越少,向下调整的次数才越多。

而利用向上调整构建堆,从最后一层的节点往上,则会耗费较多时间复杂度,因为最后一层也需要向上调整。

4. TopK

如果数据量太大,比如一千万个数据,以int来算则是四千万字节,差不多相当于40G内存,如果还是按以前那样将所有数据插入堆中求TopK显然是不可能的。

void PrintTopK(const char* file, int k) {
	// 文件
	FILE* fr = fopen(file, "r");
	if (fr == NULL) {
		perror("PrintTopK fopen failed.");
		exit(-1);
	}

	// 大小为k的堆
	datatype* minheap = (datatype*)malloc(sizeof(datatype) * k);
	if (minheap == NULL) {
		perror("PrintTopK malloc failed.");
		exit(-1);
	}
	// 从文件读取前k个建小堆
	for (int i = 0; i < k; i++) {
		fscanf(fr, "%d", &minheap[i]);
		AdjustUp(minheap, i); // child<parent
	}

	// 从文件挨个读取,寻找TopK
	int val = 0;
	while (fscanf(fr, "%d", &val) != EOF) {
		if (val > *minheap) {
			*minheap = val; 
			// 大的往下沉 child<parent
			AdjustDown(minheap, k, 0); 
		}
	}

	// 打印TopK
	for (int i = 0; i < k; i++) {
		printf("%d ", minheap[i]);
	}
	printf("\n");
	free(minheap);
	minheap = NULL;
	fclose(fr);
}

5. 所有代码

#pragma once

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

// 堆结构
typedef int datatype;
typedef struct Heap {
	datatype* arr;
	int size;
	int capacity;
} Heap;

void HeapInit(Heap* heap);
void HeapDestroy(Heap* heap);

void HeapPush(Heap* heap, datatype val);
void HeapPop(Heap* heap);
// 插入或删除时,堆向上、向下调整
void Swap(datatype* x, datatype* y);
void AdjustUp(datatype* arr, int child);
void AdjustDown(datatype* arr, int size, int parent);

datatype HeapTop(Heap* heap);
size_t HeapSize(Heap* heap);
bool HeapEmpty(Heap* heap);

// 堆排序、求TopK
void HeapSort(datatype* arr, int size);
void PrintTopK(const char* file, int k);
#define _CRT_SECURE_NO_WARNINGS 1

#include "Heap.h"

void HeapInit(Heap* heap) {
	assert(heap);
	heap->arr = NULL;
	heap->size = heap->capacity = 0;
}

void HeapDestroy(Heap* heap) {
	assert(heap);
	free(heap->arr);
	heap->arr = NULL;
	heap->size = heap->capacity = 0;
}

void HeapPush(Heap* heap, datatype val) {
	assert(heap);
	if (heap->size == heap->capacity) {
		heap->capacity = heap->capacity == 0 ? 10 : heap->capacity * 2;
		datatype* tmp = realloc(heap->arr, sizeof(datatype) * heap->capacity);
		if (tmp == NULL) {
			perror("HeapPush malloc failed.");
			exit(-1);
		}
		heap->arr = tmp;
	}
	heap->arr[heap->size++] = val;
	AdjustUp(heap->arr, heap->size - 1);
}

void HeapPop(Heap* heap) {
	assert(heap && heap->arr && heap->size > 0);
	Swap(&heap->arr[0], &heap->arr[--heap->size]);
	AdjustDown(heap->arr, heap->size, 0);
}

datatype HeapTop(Heap* heap) {
	assert(heap && heap->arr && heap->size > 0);
	return heap->arr[0];
}

size_t HeapSize(Heap* heap) {
	assert(heap);
	return heap->size;
}

bool HeapEmpty(Heap* heap) {
	assert(heap);
	return heap->size == 0;
}

void Swap(datatype* x, datatype* y) {
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void AdjustUp(datatype* arr, int child) {
	int parent = (child - 1) / 2;
	while (child > 0 && arr[child] < arr[parent]) {
		Swap(&arr[child], &arr[parent]); // up
		child = parent;
		parent = (child - 1) / 2;
	}
}

void AdjustDown(datatype* arr, int size, int parent) {
	int child = parent * 2 + 1; //child+1为右孩子节点
	child = child + 1 < size && arr[child + 1] < arr[child]
										? ++child : child;
	// child<parent调整为小堆,child>parent调整为大堆 
	while (child < size && arr[child] < arr[parent]) {
		Swap(&arr[child], &arr[parent]); // down
		parent = child;
		child = parent * 2 + 1; // left or right
		child = child+1 < size && arr[child+1] < arr[child]
										? ++child : child;
	}
}

// 升序构建大堆,降序构建小堆
void HeapSort(datatype* arr, int size) {
	// 建堆 O(nlogn) 
	//for (int i = 1; i < size; ++i) {
	//	AdjustUp(arr, i);  
	//}

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

	// 排序 O(nlogn)
	for (int end = size - 1; end > 0; --end) {
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, end, 0);
	}
}

void PrintTopK(const char* file, int k) {
	// 文件
	FILE* fr = fopen(file, "r");
	if (fr == NULL) {
		perror("PrintTopK fopen failed.");
		exit(-1);
	}

	// 大小为k的堆
	datatype* minheap = (datatype*)malloc(sizeof(datatype) * k);
	if (minheap == NULL) {
		perror("PrintTopK malloc failed.");
		exit(-1);
	}
	// 从文件读取前k个建小堆
	for (int i = 0; i < k; i++) {
		fscanf(fr, "%d", &minheap[i]);
		AdjustUp(minheap, i); // child<parent
	}

	// 从文件挨个读取,寻找TopK
	int val = 0;
	while (fscanf(fr, "%d", &val) != EOF) {
		if (val > *minheap) {
			*minheap = val; 
			// 大的往下沉 child<parent
			AdjustDown(minheap, k, 0); 
		}
	}

	// 打印TopK
	for (int i = 0; i < k; i++) {
		printf("%d ", minheap[i]);
	}
	printf("\n");
	free(minheap);
	minheap = NULL;
	fclose(fr);
}
#define _CRT_SECURE_NO_WARNINGS 

#include "Heap.h"
#include <time.h>

static void CreateNData();

int main() {
	//Heap heap;
	//HeapInit(&heap);
	 建堆 nlogn
	//HeapPush(&heap, 67864);
	//HeapPush(&heap, 7432);
	//HeapPush(&heap, 854312);
	//HeapPush(&heap, 909876);
	//HeapPush(&heap, 8765);
	//HeapPush(&heap, 2345678);
	//HeapPush(&heap, 2563);
	//HeapPush(&heap, 12676);
	//HeapPush(&heap, 6543);
	//HeapPush(&heap, 2167);
	//printf("%zd\n", HeapSize(&heap));
	//for (int i = 0; i < heap.size; i++) {
	//	printf("%d ", heap.arr[i]);
	//}
	//printf("\n");

	// top k
	//int k = 3; 
	//while (k--) {
	//	printf("%d ", HeapTop(&heap));
	//	HeapPop(&heap);
	//}
	//printf("\n");

	// Push nlogn + 排序 nlogn =  O(2nlogn)
	//while (!HeapEmpty(&heap)) {
	//	printf("%d ", HeapTop(&heap));
	//	HeapPop(&heap);
	//}
	//HeapDestroy(&heap);
	//printf("\n");

	// 堆排序
	//int arr[] = { 67864,7432,854312,909876,8765,2345678,2563,12676,6543,2167 };
	//HeapSort(arr, sizeof arr / sizeof arr[0]);
	//for (int i = 0; i < sizeof arr / sizeof arr[0]; i++) {
	//	printf("%d ", arr[i]);
	//}

	// 大量数据下的TopK
	//CreateNData(); 
	PrintTopK("data.txt", 6);
	return 0;
}

static void CreateNData() {
	int n = 100000;
	srand((unsigned int)time(0));
	FILE* fw = fopen("data.txt", "w");
	if (fw == NULL) {
		perror("CreateNData fopen failed.");
		exit(-1);
	}
	for (int i = 0; i < n; i++) {
		fprintf(fw, "%d\n", rand() % n);
	}
	fclose(fw);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云企业用户2核4G5M固定带宽199元一年,续费不涨价

2024年2月阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核…

Echarts统计用户近七日走量趋势:前后端实现

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525;网站…

嵌入式学习Day14 C语言 --- 位运算

位运算 注意&#xff1a;符号位也遵循这个规则 一、按位与(&) 运算规则&#xff1a;一假则假 int a 0x33;a & 0x55;0011 00110101 0101 &----------0001 0001 //0x11 二、按位或(|) 运算规则&#xff1a;一真则真 int a 0x33;a |0x55;0011 00110101 0101 |…

STM32Cubmax stm32f103zet6 SPI通讯

一、基本概念 SPI 是英语 Serial Peripheral interface 的缩写&#xff0c;顾名思义就是串行外围设备接口。是 Motorola 首先在其 MC68HCXX 系列处理器上定义的。 SPI 接口主要应用在 EEPROM&#xff0c; FLASH&#xff0c;实时时 钟&#xff0c; AD 转换器&#xff0c;还有数…

GLSL ES 1.0

GLSL ES 概述 写在前面 程序是大小写敏感的每一个语句都应该以英文分号结束一个shader必须包含一个main函数&#xff0c;该函数不接受任何参数&#xff0c;并且返回voidvoid main() { }数据值类型 GLSL支持三种数据类型&#xff1a; 整型浮点型&#xff1a;必须包含小数点&…

eclipse使用google的Java代码格式

插件下载地址 1.下载eclipse的插件 2.下载的jar包放到eclipse安装目录的dropins文件夹 D:\install_package\STS\sts-4.10.0.RELEASE\dropins&#xff13;.重启后设置 eclipse - windows - preference - java - code style - formatter -

Excel——合并计算

1.表格的合并计算&#xff08;单张表格/多个表格&#xff09; Q&#xff1a;请统计两个表格中各商品的总销量和总销售额&#xff0c;将结果放置在下方任意位置。 A&#xff1a;选择一个需要将合并计算数据放置区域的空白单元格 选择【数据】——【合并计算】&#xff0c;【函…

Linux安装Java

yum安装 下面命令直接复制粘贴一件安装java17 yum list installed | grep java #查看已经安装的javayum remove java* -y #移除现在系统已经安装的javayum list | grep java-17 #查看安装java17yum install -y java-17-openjdk #安装java17此处可…

flink反压及解决思路和实操

1. 反压原因 反压其实就是 task 处理不过来&#xff0c;算子的 sub-task 需要处理的数据量 > 能够处理的数据量&#xff0c;比如&#xff1a; 当前某个 sub-task 只能处理 1w qps 的数据&#xff0c;但实际上到来 2w qps 的数据&#xff0c;但是实际只能处理 1w 条&#…

JVM 性能调优- 五种内存溢出(5)

在介绍之前先简单介绍下 直接内存(Direct Memory)和堆内存(Heap Memory): 关系: 直接内存并不是Java虚拟机的一部分,它是通过Java的NIO库中的ByteBuffer来分配和管理的。直接内存通常由操作系统的本地内存(Native Memory)提供支持。堆内存是Java虚拟机的一部分,用于存…

裸机开发及开发环境搭建

ARM 的裸机开发&#xff0c;也就是不带操作系统开发&#xff0c;就和我们开发 STM32 一样&#xff0c;如果 有 STM32 开发经验的话学起本篇会很容易 1 、裸机开发是了解所使用的 CPU 最直接、最简单的方法&#xff0c;裸机开发是直接操作 CPU 的寄存器。 Linux 驱动开发…

人工智能 | 深度学习的进展

深度学习的进展 深度学习是人工智能领域的一个重要分支&#xff0c;它利用神经网络模拟人类大脑的学习过程&#xff0c;通过大量数据训练模型&#xff0c;使其能够自动提取特征、识别模式、进行分类和预测等任务。近年来&#xff0c;深度学习在多个领域取得了显著的进展&#…

React+Antd+tree实现树多选功能(选中项受控+支持模糊检索)

1、先上效果 树型控件&#xff0c;选中项形成一棵新的树&#xff0c;若父选中&#xff0c;子自动选中&#xff0c;子取消&#xff0c;父不取消&#xff0c;子选中&#xff0c;所有的父节点自动取消。同时支持模糊检索&#xff0c;会检索出所有包含该内容的关联节点。 2、环境准…

Python数据可视化库之ggplot使用详解

概要 数据可视化是数据分析和数据沟通的关键部分。Python 作为一门强大的数据科学和数据分析工具,提供了多种数据可视化库,其中之一就是 ggplot。ggplot 是一个基于 ggplot2 的 Python 数据可视化库,它可以创建精美且高度可定制的图表,以更好地理解和传达数据。本文将深入…

spring boot整合 cache 以redis服务 处理数据缓存 便捷开发

我们常规开发中 就是程序去数据库取数据 然后返回给客户端 但是 如果有些业务业务量非常庞大 不断访问数据库 性能就会非常糟糕 从而造成不好的用户体验 那么 我们自然就可以将数据查到缓存中 然后 用户访问 从缓存中取 这样就会大大提高用户的访问效率 之前 我的文章 java …

【算法设计与分析】求根节点到叶节点数字之和

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给你一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数…

【数据结构】二叉树的三种遍历(非递归讲解)

目录 1、前言 2、二叉树的非递归遍历 2.1、先序遍历 2.2、中序遍历 2.3、后序遍历 1、前言 学习二叉树的三种非递归遍历前&#xff0c;首先来了解一下递归序&#xff1a; 递归序就是按照先序遍历的顺序&#xff0c;遇到的所有结点按顺序排列&#xff0c;重复的结点也必须记…

Java排序算法-持续更新中

一、比较排序 1.1 交换排序 数组两元素交换位置 public class ArrayUtil {/*** 交换数组中的两个元素* param array 数组* param ele1Idx 元素1的索引下标* param ele2Idx 元素1的索引下表*/public static void swap(int[] array, int ele1Idx, int ele2Idx) {int tmp arra…

【Linux开发工具】gcc/g++的使用

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.前言2.gcc/g使用方…

初始Ansible自动化运维工具之playbook剧本编写

一、playbook的相关知识 1.1 playbook 的简介 playbook是 一个不同于使用Ansible命令行执行方式的模式&#xff0c;其功能更强大灵活。简单来说&#xff0c;playbook是一个非常简单的配置管理和多主机部署系统&#xff0c;不同于任何已经存在的模式&#xff0c;可作为一个适…