【完全二叉树魔法:顺序结构实现堆的奇象】

news2024/10/5 17:27:01

本章重点

  • 二叉树的顺序结构
  • 堆的概念及结构
  • 堆的实现
  • 堆的调整算法
  • 堆的创建
  • 堆排序
  • TOP-K问题

1.二叉树的顺序结构

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

访问结点的规律:

//访问孩子节点
leftchild = parent*2+1
rightchild = parent*2+2
 
//访问父亲结点
parent = (child-1)/2

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

解析:

        堆(Heap)是一种特殊的树形数据结构,它通常有两种类型:小堆(Min Heap)和大堆(Max Heap)。在小堆中,父节点的值小于或等于其子节点的值,而在大堆中,父节点的值大于或等于其子节点的值。

        要判断一个序列是否是堆,需要检查该序列是否满足堆的性质。我们发现A符合大堆的性质父节点的值大于或等于其子节点的值。

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

A 1

B 2

C 3

D 4

解析:

        在一个小根堆中删除根节点后,需要重新构建小根堆。删除根节点后,通常会将堆的最后一个元素移动到根的位置,然后通过与其子节点的比较来逐级下移,以确保小根堆的性质得以恢复。

        给定的小根堆是:8, 15, 10, 21, 34, 16, 12。

        首先删除根节点8后,将最后一个元素12移到根的位置,得到:12, 15, 10, 21, 34, 16。

        然后,我们需要逐级下移12,直到小根堆性质得以恢复。在这个过程中,我们将12与其子节点进行比较,选择较小的子节点来交换位置。

        第一次比较:12与15比较,不需要交换。

        第二次比较:12与10比较,需要交换。

        第三次比较:12与16比较,不需要交换。

        因此,关键字之间的比较次数是3次。

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)

        堆排序是一种基于堆数据结构的排序算法,通常会建立一个最大堆(Max Heap)或最小堆(Min Heap)来进行排序。在这里,我们需要建立一个最大堆。

        初始堆的建立过程通常是从数组的末尾开始,逐步将元素向上移动,以满足堆的性质。对于给定的排序码数组(5 11 7 2 3 17),初始堆的建立步骤如下:

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]

3.堆的实现

        

        这里的堆是使用数组实现的,博主重点介绍堆的删除和插入接口,其他接口同顺序表相同,这里就不过多赘述了。

typedef int HPDataType;

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

// 堆的初始化
void HeapInit(HP* php);
// 堆的打印
void HeapPrint(HP* php);
// 堆的销毁
void HeapDestroy(HP* php);
//堆的创建
void HeapInitArray(HP*php, int* a, int n);
// 堆的插入
void HeapPush(HP* php, HPDataType x);
// 堆的删除
void HeapPop(HP* php);
// 取堆顶的数据
HPDataType HeapTop(HP* php);
// 堆的数据个数
int HeapSize(HP* php);
// 堆的判空
bool HeapEmpty(HP* php);

3.1堆的插入:void HeapPush(HP* php, HPDataType x)

  1. 先将元素插入到堆的末尾,即最后一个孩子之后。
  2. 插入之后如果堆的性质遭到破坏,将信新插入节点顺着其双亲往上调整到合适位置即可,即向上调整
  3. 向上调整结束的条件是child等于0,parent等于-1,但是我们写的循环结束条件是child大于0,因为parent的值不会是-1,而是0,这里可以去看我的另外一篇文章,里面介绍了c语言取整规则:链接

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

//向上调整
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 HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if(php->size == php->capacity)
	{
		int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* temp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newCapacity);
		if (temp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		php->a = temp;
		php->capacity = newCapacity;
	}

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

	AdjustUP(php->a, php->size - 1);
}

3.2堆的删除:void HeapPop(HP* php)

  1. 将堆顶元素与堆中最后一个元素进行交换。
  2. 删除堆中最后一个元素。
  3. 将堆顶元素向下调整到满足堆特性为止。
  4. 向下调整的结束条件是child等于叶子结点。
void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

//向下调整
void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	//parent到叶子结点就结束
	while (child < n)
	{
		//可能不存在右孩子
		if (child + 1 < n && 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 HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);

	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;

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

4.堆的调整算法

4.1堆向下调整算法

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

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

//向下调整
void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	//parent到叶子结点就结束
	while (child < n)
	{
		//可能不存在右孩子
		if (child + 1 < n && a[child] > a[child + 1])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
	
}

4.2堆向上调整算法

        现在我们给出一个数组,前n-1个数已经是堆了,现在再添加一个数要让其满足堆的性质。我们通过从最后一个叶子结点向上调整算法可以把它调整成一个小堆。向上调整算法有一个前提:前面的数据必须是一个堆,才能调整。

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

5.堆的创建

方法一:向上调整插入的思想

        下面我们给出一个数组,利用上面push函数的思路,将数组a中的元素依次插入向上调整,把第一个数当成堆,满足堆向上调整的前提,可以调整成堆。

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

//建堆
//向上调整:前提是前面的数据是堆
// 思路:第一个数据当作堆,后面数据依次插入,向上调整
//时间复杂度O(N*logN)
for (int i = 1; i < n; i++)
{
	AdjustUp(a, i);
}

        所以这里我们就可以给堆结合实现一个创建堆的接口:使用向上调整的思路。

void HeapInitArray(HP* php, int* a, int n)
{
	assert(php);
	assert(a);

	php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	php->size = php->capacity = n;

	memcpy(php->a, a, sizeof(HPDataType) * n);

	for (int i = 0; i < n; i++)
	{
		AdjustUp(php->a, i);
	}
}

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

因此:建堆的时间复杂度为O(N*logN)。

方法二:倒数第一个非叶子结点向下调整的思想

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

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

//倒数第一个非叶子结点:(最后一个叶子结点-1)/2 

//建堆
//向下调整建堆
//找到倒数第一个非叶子结点
//时间复杂度O(N)
for (int i = (n - 1 - 1)/2; i >= 0; i--)
{
	AdjustDown(a, n, i);
}

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

因此:建堆的时间复杂度为O(N)。

6.堆排序

1. 排序如何建堆

  • 升序:建大堆
  • 降序:建小堆

        为什么升序是建大堆呢?按照我们的常理,我们先建小堆,然后再取出堆顶的数据,这样就取得了最小的数据,这样数据不就有序了,为什么要去建大堆呢???

        取出堆顶的数据,这样就取得了最小的数据,然后再选次小的数,此时我们只能将剩下的数看做堆,但是剩下的数据还是堆嘛?

        此时就要重新建堆,然后再取堆顶数据,再建堆...每次建堆的时间复杂度N*logN,一共有N个数据,所以总的排序时间复杂度就是N * logN * N,那还不如直接遍历一遍排序来的快呢!!!

2. 利用堆删除思想来进行排序

        所以此时我们可以建大堆,将堆顶的数据和最后一个叶子结点交换,由于此时的堆结构没有破坏,左子树和右子树仍然是堆,使用堆的向下调整去调整堆,然后在缩小下次向下调整的范围,也就是把最大的那个数不算做堆的范围了,这样最大的数据就保存在了下标最大的位置处,满足了升序的要求。每次向下调整的时间复杂度是logN,一共有N个数据,所以总的排序时间复杂度就是N * logN。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

void Swap(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
//向上调整
void AdjustUp(int* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
//向下调整
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	//parent到叶子结点就结束
	while (child < n)
	{
		//可能不存在右孩子
		if (child + 1 < n && 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 HeapSort1(int a[],int n)
{
	//建堆
	//向上调整:前提是前面的数据是堆
	// 思路:第一个数据当作堆,后面数据依次插入,向上调整
	//O(N*logN)
    for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}

	//升序建大堆
    //O(N*logN)
	//向下调整:前提是左右子树是堆
	int end = n - 1;
	while (end > 0)
	{

		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}
void HeapSort2(int a[],int n)
{
	//建堆
	//向下调整:前提是左右子树是堆
	// 思路:找到倒数第一个非叶子结点,与最后一个叶子结点进行向下调整,直至根节点
	//O(N)
    for (int i = (n - 1 - 1)/2; i >= 0; i--)
    {
	    AdjustDown(a, n, i);
    }

	//升序建大堆
    //O(N*logN)
	//向下调整:前提是左右子树是堆
	int end = n - 1;
	while (end > 0)
	{

		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}
int main()
{
	int a[] = { 3,17,4,20,16,5 };
	//HeapSort1(a,sizeof(a)/sizeof(a[0]));
    HeapSort2(a,sizeof(a)/sizeof(a[0]));
	int i = 0;
	for (i = 0; i < sizeof(a) / sizeof(a[0]); i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

运行结果:

7.TOP-K问题

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

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

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

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

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

这里不能用大堆,如果第一个数据就是最大的,放在堆顶,其余数据就无法入堆,所以要用小堆,最大的前k个数肯定比堆顶大,此时该数替换堆顶的数入堆,入完k个后就找到前k个最大的元素。

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

2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

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

3.复杂度

  • 时间复杂度:O(N*logK)
  • 空间复杂度:O(K)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void Swap(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
//向下调整
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	//parent到叶子结点就结束
	while (child < n)
	{
		//可能不存在右孩子
		if (child + 1 < n && 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 PrintTopK(const char *filename, int k)
{
	// 1. 建堆--用a中前k个元素建堆
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		exit(-1);
	}
	int *Minheap = (int*)malloc(sizeof(int) * k);
	if (Minheap == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	//读文件
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &Minheap[i]);
	}
	//向下调整建小堆
	for (int i = (k-2)/2; i >= 0; --i)
	{
		AdjustDown(Minheap, k, i);
	}
	// 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (x > Minheap[0])
		{
			Minheap[0] = x;
			AdjustDown(Minheap, k, 0);
		}
	}

	for (int i = 0; i < k; ++i)
	{
		printf("%d ", Minheap[i]);
	}
	printf("\n");
	fclose(fout);
}
void CreatNData()
{
	//造数据
	int n = 10000;
	srand((unsigned int)time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen fail");
		exit(-1);
	}
	for (int i = 0; i < n; ++i)
	{
		int x = rand() % 1000000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}
int main()
{
	//CreatNData();
	PrintTopK("data.txt",10);
	return 0;
}

运行结果:

但是我们怎么知道这几个数据就是前k个最大的呢?我们可以在文件中手动创造10个最大的值,看看输出是不是我们刚刚手动创造10个最大的值。

1000001;1000002;1000003;10000041000005;

1000006;1000007;1000008;1000009;1000009。

这样就完成了我们的TOP-K问题!!!

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

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

相关文章

JavaScript系列从入门到精通系列第六篇:JavaScript中其他进制数字以及其他的数据类型强制转换为Boolean数据类型

文章目录 一&#xff1a;各种进制数字 1&#xff1a;表示十进制 2&#xff1a;表示16进制 3&#xff1a;表示8进制 4&#xff1a;表示二进制数字 二&#xff1a;其他进制字符穿转数字 三&#xff1a;其他数据类型强制转换为Boolean 1&#xff1a;Number转Boolean 2&am…

【3dmax】怎么将点删除而面保留

在编辑多边形模式下&#xff0c;选择点模式&#xff0c;选择要删除的点&#xff0c;在下拉面板中找到【移除】

eNSP基础网络学习-v02

一、eNSP 1.什么是eNSP eNSP(Enterprise Network Simulation Platform)是一款由华为提供的免费的、可扩展的、图形化操作的网络仿真工具平台&#xff0c;主要对企业网络路由器、交换机进行软件仿真&#xff0c;完美呈现真实设备实景&#xff0c;支持大型网络模拟&#xff0c;让…

Java基础-环境篇:JDK安装与环境变量配置jdk8/11/17(保姆式详解)

目录 一、Java简介 Java版本 名词解释JDK、JRE JDK版本选择 二、JDK的下载 下载方式1&#xff1a; &#xff08;1&#xff09;在Developers页面中间的技术分类部分&#xff0c;选择Java&#xff0c;单击进入&#xff0c;如图所示&#xff1a; &#xff08;2&#xff09;…

set和map的学习

文章目录 1.set的原型2.set的成员函数1.构造函数2.代码演示 3.map的原型4.map的成员函数1.构造函数2.代码演示 5.OJ练习1.前K个高频单词2.两个数组的交集3.随即链表的复制 1.set的原型 template <class T, //set::key_typeclass Compare less<T>,…

【刷题-牛客】链表内指定区间反转

链表定区间翻转链表 题目链接题目描述核心思想详细图解代码实现复杂度分析 题目链接 链表内指定区间反转_牛客题霸_牛客网 (nowcoder.com) 题目描述 核心思想 遍历链表的过程中在进行原地翻转 [m,n]翻转区间记作子链表,找到子链表的 起始节点 left 和 终止节点 right记录在…

ForkJoin详解

1.分支合并 (大数据量的去使用) package com.kuang.forkjoin;import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.function.LongBinaryOperator; import java.util.stre…

【ROS入门】使用 ROS 话题(Topic)机制实现消息发布与订阅及launch文件的封装

文章结构 任务要求话题模型实现步骤创建工作空间并初始化创建功能包并添加依赖创建发布者代码&#xff08;C&#xff09;创建订阅方代码&#xff08;C&#xff09;配置CMakeLists.txt执行启动roscore编译启动发布和订阅节点 launch封装执行 任务要求 使用 ROS 话题(Topic)机制…

使用容器运行Nginx应用及Docker命令

目录 一、使用容器运行Nginx应用 1.1 使用docker run命令运行Nginx应用 1.1.1 观察下载容器镜像过程 1.1.2 观察容器运行情况 ​编辑 1.2 访问容器中运行的Nginx服务 1.2.1 确认容器IP地址 1.2.2 容器网络说明 1.2.3 在主机中使用curl命令容器IP地址访问 二、Docker命…

使用veth和bridge模拟容器网络

使用veth和bridge模拟容器网络 随着虚拟化技术、容器化技术的发展&#xff0c;我们在工作中会使用到虚拟化网络技术。简单来说&#xff0c;以往的网卡、交换机、路由器&#xff0c;当前可以通过操作系统使用程序来进行模拟。 通常使用最为广泛的是下面的虚拟设备&#xff1a;…

新一代爬虫工具 katana 配置及使用

新一代爬虫工具 katana 配置及使用。 功能&#xff1a; 快速且完全可配置的网络爬行 标准和无外设模式支持 JavaScript 解析/爬网 可定制的自动表单填写 范围控制 - 预配置字段/正则表达式 可自定义的输出 - 预配置字段 输入 - 标准输入、URL 和列表 输出 - 标准输出、…

【Java Web】CSS

目录 1.CSS(Cascading Style Sheets) 层叠样式表 2.标签 1.注释 2.三种书写样式 1.内部样式 2.内联样式 3.外部样式 3.CSS选择器 &#xff08;1&#xff09;标签选择器 &#xff08;2&#xff09;类选择器 &#xff08;3&#xff09;ID选择器 复合选择器 &#xf…

人力资源HR 怎么选择在线人才测评工具

测评已经是普及度很好了&#xff0c;不仅仅是大企业&#xff0c;中小企业也都在启用人才测评&#xff0c;也有叫素质测评等等&#xff0c;内容多样化。但是根本形式是一样的&#xff0c;那就是在线测评&#xff0c;目的也是一样的&#xff0c;就是为了招来最适合的职员。 而市…

细胞个数统计

1.1 应用示例目的与思路 (1) 对输入图像进行灰度化、滤波和阈值分割&#xff1b; (2) 对区域进行填充、连通域分析和面积筛选&#xff1b; (3) 对区域进行距离变换&#xff0c;对变换后的距离信息图像进行类型转换和图像增强&#xff1b; (4) 使用分水岭算法提取区域&#…

windows安装c环境

一. 下载安装mingw-w64 mingw-w64 解压后放到window环境变量路径 sysdm.cpl参看是否安装成功 二. 安装c idea Dev-Cpp下载及安装 新建文件 运行 编译&#xff08;F9&#xff09;、运行&#xff08;F10&#xff09;以及编译运行&#xff08;F11&#xff09; 参考 安装C…

使用 LangChain 和 Elasticsearch 对私人数据进行人工智能搜索

关于本博文的所有代码可以在地址下载&#xff1a;GitHub - liu-xiao-guo/python-vector-private 我将在本博文中其中深入研究人工智能和向量嵌入的深水区。 ChatGPT 令人大开眼界&#xff0c;但有一个主要问题。 这是一个封闭的托管系统。 在一个被大型网络公司改变的世界里生…

代码随想录—力扣算法题:07.链表相交. Java版(示例代码与导图详解)

版本说明 当前版本号[20230923]。 版本修改说明20230923初版 07. 链表相交 同&#xff1a;160.链表相交 力扣题目链接 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示…

C/C++正常血压 2019年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C正常血压 一、题目要求 1、编程实现 2、输入输出 二、解题思路 1、案例分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 C/C正常血压 2019年12月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 监护室每小时测量一次病人的血压&#x…

链式二叉树的实现及遍历(C语言版)

目录 1 基本概念 1.1 树的概念 1.2 二叉树的链式表示 1.2.1 "左孩子右兄弟"表示法 1.2.2 "左右子树"表示法 1.2.3 手动构建一棵树 2 树的遍历 2.1 前序遍历/先序遍历 2.2 中序遍历 2.3 后序遍历 2.4 层序遍历 2.4.1 算法思想 ​编辑 2.4.2 带头…

堆向上调整及堆向下调整

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言&#xff1a; 在堆这一节中&#xff0c;孩子和其父节点有如下关系&#xff1a; 左孩子&#xff1a;left_child parent * 2 1; 右孩子&#xff1a;right_child parent * 2 2; 父节点在计算时&#xff0c;因为兄弟…