堆和堆排序【数据结构】

目录

  • 一、堆
    • 1. 堆的存储定义
    • 2. 初始化堆
    • 3. 销毁堆
    • 4. 堆的插入
      • 向上调整算法
    • 5. 堆的删除
      • 向下调整算法
    • 6. 获取堆顶数据
    • 7. 获取堆的数据个数
    • 8. 堆的判空
  • 二、Gif演示
  • 三、 堆排序
    • 1. 堆排序
      • (1) 建大堆
      • (2) 排序
    • 2.Topk问题
  • 四、完整代码
    • 1.堆的代码
      • Heap.c
      • Heap.h
      • test.c
    • 2. 堆排序的代码

前言:
什么是堆呢?
堆(Heap)是一种数据结构,它是 一种特殊的二叉树 ,其中父节点的键值总是大于或等于(或小于或等于)其任何一个子节点的键值。这意味着在堆中,根节点具有最大(或最小)键值。
堆:一般是数组数据看做一棵完全二叉树
完全二叉树的逻辑结构:
大堆01

  • 大堆: 任意一个父结点 大于等于 子结点
    大堆02

  • 小堆: 任意一个父结点 小于等于 子结点
    小堆
    数组存储完全二叉树
    在这里插入图片描述

一、堆

1. 堆的存储定义

因为存储结构,这里使用动态数组的形式来存放数据。但是也要注意其中的逻辑结构是完全二叉树。定义一个指针指向动态数组,定义存储堆的容量capacity,记录堆中的数据的个数size

代码

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;	//指向动态数组
	int capacity;	//堆的容量
	int size;		//堆中数据个数
}Heap;

2. 初始化堆

类似顺序表的初始化

代码

//初始化堆
void InitHeap(Heap* hp) 
{
	assert(hp);
	hp->a = NULL;
	hp->capacity = 0;
	hp->size = 0;
}

3. 销毁堆

避免内存泄漏

代码

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

4. 堆的插入

重点:
在堆的插入前,我们需要注意的就是,首先判断其容量,然后使用realloc给数组分配空间
分配空间后,把数据插入堆。但是数据在插入堆时,由于堆一般分为大根堆和小根堆,所以这里使用的大根堆。 大堆:父结点的值大于等于其孩子结点的值
但是数据的值不能确定,这个时候就需要我们使用 堆的向上调整算法

向上调整算法

在数组的末端插入元素,进行与其父结点进行比较,大堆的情况下,如果其孩子结点的值大于父亲结点的值时,把插入的数据向上调整,向上调整的方法是:把插入的数据与其父结点进行交换,交换后继续判断是否还需要向上调整。(使用向上调整算法的条件是前面结点的树是构成堆的)

这里是使用的是数组,所以当插入元素时,在数组的末端进行插入数据

物理存储:
在这里插入图片描述
逻辑存储情况:
在这里插入图片描述

在插入的数据时,我们就需要考虑一下,
1. 当插入的孩子结点的值大于其父亲结点的值时,就向上调整
思路:
首先是根据孩子结的下标找父结点的下标,(孩子结点下标-1)/2 == 父结点下标,因为可能调整所以将判断条件放到循环里面(当然也可以用递归),在循环里面切记一定要及时更新当前孩子结点的下标和父结点的下标,孩子结点的值大于父结点的值就向上调整,否则就跳出循环。当孩子结点的下标到0时,向上调整完成,循环结束。
在这里插入图片描述
2. 当小于等于时,不需要调整
在这里插入图片描述
代码

//向上调整
void AdjustUp(HPDataType * a,int child) 
{
	//先找到父结点的下标
	int parent = (child - 1) / 2;
	while (child > 0)	//child等于0时,说明已经调整ok了
	{
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			//可能会向上调整多次
			child = parent;
			parent = (parent - 1) / 2;
		}
		else 
		{
			break;
		}
	}
}

//堆的插入
void PushHeap(Heap* hp, HPDataType x)
{
	assert(hp);
	//堆满判断
	if (hp->capacity == hp->size) 
	{
		int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;
		HPDataType* tmp = (HPDataType*)realloc(hp->a,sizeof(HPDataType)*newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		hp->a = tmp;
		hp->capacity = newcapacity;
	}
	//堆元素的插入
	hp->a[hp->size] = x;
	hp->size++;
	//堆的向上调整
	AdjustUp(hp->a,hp->size-1);
}

调试,查看一下数据存储情况
在这里插入图片描述

5. 堆的删除

堆中元素的删除,发现直接删除尾结点是简单的(size减一即可),但是,一般堆,删除元素都是删除的头结点。
直接删除头结点时:发现逻辑结构上变成了两棵树,这样直接删除头结点的方法不推荐。
在这里插入图片描述
交换结点再删除
头尾结点交换后,再删除尾结点,然后头结点使用堆的向下调整算法,调堆。
使用前提就是,当进行交换的时候,保证左右仍是堆。第一个结点与最后一个结点的值交换后,向下调整。

向下调整算法

这里调的堆是大堆(根结点的值大于左右孩子结点的值)

  • 第一步,找到第一个根结点的孩子结点,这里使用假设法,先让左孩子的值最大,再进行判断左孩子还是右孩子的值是最大的,找出大的。
  • 第二步与根结点进行比较,大于根结点就交换。
  • 及时更新父结点和孩子结点的下标
  • 注意当孩子结点值都小于父亲结点值就跳出循环;循环结束条件:孩子结点的下标大于数组最大的下标(就是孩子下标<数组的个数,child<size,大于等于时说明循环就结束了)。

过程:
在这里插入图片描述
调整后
在这里插入图片描述
这样就完成堆头结点的删除。
还需要注意的就是:
在这里插入图片描述

代码

//向下调整
void AdjustDown(HPDataType* a, int size, int parent)
{
	//先去找根结点的较大的孩子结点
	int child = 2 * parent + 1;
	//可能会向下调整多次
	while (child<size) 
	{
		//这里使用假设法,先假设左孩子的值最大
		//如果不对就进行更新
		if ((child+1 < size)&&a[child] < a[child+1]) 
		{
			child++;
		}
		//根结点与其孩子结点中的较大的一个进行交换
		if(a[child] > a[parent]) 
		{
			swap(&a[child],&a[parent]);
			//更新下标
			parent = child;
			child = 2 * parent + 1;
		}
		else 
		{
			break; //调完堆
		}
	}
}
//堆的删除
void PopHeap(Heap* hp)
{
	assert(hp);
	assert(hp->size>0);
	//头尾交换
	swap(&hp->a[0],&hp->a[hp->size-1]);
	hp->size--;
	//向下调整
	AdjustDown(hp->a,hp->size,0);
}

调试一下:
在这里插入图片描述
上图中指向下标6其实有数据65的,但是数组的下标有效范围在0-5

6. 获取堆顶数据

前提:堆得有数据
代码

//获取堆顶数据
HPDataType TopHeap(Heap* hp) 
{
	assert(hp);
	assert(hp->size>0);
	return hp->a[0];
}

7. 获取堆的数据个数

代码

//获取堆的数据个数
int SizeHeap(Heap* hp)
{
	assert(hp);
	return hp->size;
}

8. 堆的判空

代码

//堆的判空
bool EmptyHeap(Heap* hp) 
{
	assert(hp);
	return hp->size == 0;
}

二、Gif演示

调堆演示
堆动图gif

三、 堆排序

堆排序是一种选择排序。
堆排序:可以从小到大进行排序(使用大堆)。Top k 问题:取出最大的前k个值。

1. 堆排序

堆排序(Heap Sort)是一种基于完全二叉树的排序算法,它通过将待排序的元素建成一个二叉堆。堆排序的时间复杂度为O(nlogn),它是不稳定排序算法。

堆排序的思路如下:

  1. 升序排序为例,先建立一个大堆(父节点的值大于子节点的值),将待排序的元素都插入堆中。
  2. 将堆顶元素(最大值)与堆末尾元素交换,然后将堆的大小减1。
  3. 对堆顶元素向下调整操作,使得堆重新满足最大堆的性质。
  4. 重复2-3步,直到堆的大小为1。排序完成。

(1) 建大堆

使用 向下 调整算法来向上建堆:使用向下调整算法,把数组调成大堆
因为堆本身是一个完全二叉树,假设一共有h层,我们从第h-1层(即不是叶子结点的那一层开始)
因为是大堆,根结点的值大于孩子结点的值,从最下方使用向下调整来不断把较大的值来调到根节点。
注意:虽然使用的是向下调整算法,其实还是不断往上调整(把大的值调到上面)。
如图:
在这里插入图片描述
直到调整到第一层为止
建堆时间复杂度:O(N)

//堆排序
void HeapSort(int* arr, int n) 
{
	int i = 0;
	//使用向下调整算法向上调整,把大的值调到上方。
	for (i = (n - 1 - 1) / 2; i >= 0;i--)
	{
		//先找到数组最后端的父结点的下标
		//父结点的下标减一就是另一个
		//使用向下调整算法进行调整
		AdjustDown(arr,n,i);
	}
}

当然也可以用向上算法进行向上建堆。

思路:先让一个独自成堆,然后尾插一个结点,再进行与根结点进行比较,大于根结点的值就交换。
但是这个使用向上调整算法向上建堆的时间复杂度为:O(Nlog(N))

//向上调整算法进行堆排序
void HeapSort(int* arr, int n)
{
	int i = 0;
	//先让第一个结点独自成堆
	//再一次尾增结点进行向上调整
	for (i = 1; i < n; i++) 
	{
		AdjustUp(arr,i);
	}
}

(2) 排序

因为建成大堆后,将堆顶元素(最大值)与堆末尾元素交换

	//注意end 是从n-1开始的(数组最后一个元素的下标)
	int end = n-1;
	while (end > 0) 
	{
		//swap end = n-1 这表示下标
		swap(&arr[0],&arr[end]);
		//adjustdown 函数里面的end是元素的个数,所以不是先--end
		//所以
		AdjustDown(arr,end,0);
		end--;
	}

注意这里的end–,上述是从数组最后一个元素下标n-1 开始。堆的首元素与尾元素交换完后,接着就是堆的个数减1,然后下进行向下调整。这里的end–放在了最后。因为AdjustDown中的第二个参数是传的是堆的大小,正好数组下标n-1 , 堆由n减一也是 n -1。

下方给出了 end 从n 开始的优化,但是可读性就会下降

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

	//堆顶元素与堆尾元素进行交换,进而把大的元素放到后面
	int end = n;
	while (end > 0) 
	{
		swap(&arr[--end],&arr[0]);
		AdjustDown(arr,end,0);
	}
}

2.Topk问题

topk问题,例如:在10000个数据排名中找出前10;或者在10000个数中找出最大的前10个

这里我们就以在10000个数中找出最大的前10(k = 10)个为例

首先应先准备数据,随机生成10000个数(注意srand函数只能生成30000多个随机数)
核心思想: 建一个可以存储k个数据的小堆。先把文件数据前10个数据读取到小堆中(进行向下调成小堆),然后再把文件中的其他数据一个一个读出与小堆的根结点的值进行比较,如果大于小堆的根结点,就进放入堆中,然后进行向下调堆。

//创建数据
void Createdata() 
{
	int n = 10000;
	srand((unsigned)time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file,"w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}
	for (int i = 0; i < n;i++)
	{
		int x = (rand() + i) % 100000;
		//把随机生成的数据写到fin文件中去
		fprintf(fin,"%d\n",x);
	}
	fclose(fin);
}
void PrintTopK(int k) 
{
	//从文件中读出数据
	const char* file = "data.txt";
	FILE* fout = fopen(file,"r");
	if (fout == NULL)
	{
		perror("fout error");
		return;
	}
	//将数据读出到容量为k的动态数组中
	int* arr = (int*)malloc(sizeof(int)*k);
	if (arr == NULL)
	{
		perror("malloc error");
		exit(-1);
	}
	//先把前k个数据放入数组中
	for (int i = 0; i < k; i++)
	{
		//将数据读到数组中
		fscanf(fout,"%d",&arr[i]);

		//放数据的同时进行建堆
		AdjustUp(arr,i);
	}

	int x = 0;
	//当文件里面的数据读完后会返回EOF
	while (fscanf(fout, "%d", &x) != EOF) 
	{
		//当从文件拿出的数据大于小堆中的数据时
		//将数据放到小堆中
		//并使用向下调整
		//这样每次来的比较大的数据就可以放到小堆中
		if (x > arr[0]) 
		{
			arr[0] = x;
			AdjustDown(arr,k,0);
		}
	}

	//打印数据
	for (int i = 0; i < k;i++) 
	{
		printf("%d ",arr[i]);
	}
	fclose(fout);

}

在这里插入图片描述

四、完整代码

1.堆的代码

Heap.c

#include "Heap.h"

//初始化堆
void InitHeap(Heap* hp) 
{
	assert(hp);
	hp->a = NULL;
	hp->capacity = 0;
	hp->size = 0;
}

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

//交换两个数
void swap(HPDataType* s1,HPDataType* s2) 
{
	HPDataType tmp = *s1;
	*s1 = *s2;
	*s2 = tmp;
}
//向上调整
void AdjustUp(HPDataType * a,int child) 
{
	//先找到父结点的下标
	int parent = (child - 1) / 2;
	while (child > 0)	//child等于0时,说明已经调整ok了
	{
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			//可能会向上调整多次
			child = parent;
			parent = (parent - 1) / 2;
		}
		else 
		{
			break;
		}
	}
}

//堆的插入
void PushHeap(Heap* hp, HPDataType x)
{
	assert(hp);
	//堆满判断
	if (hp->capacity == hp->size) 
	{
		int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;
		HPDataType* tmp = (HPDataType*)realloc(hp->a,sizeof(HPDataType)*newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		hp->a = tmp;
		hp->capacity = newcapacity;
	}
	//堆元素的插入
	hp->a[hp->size] = x;
	hp->size++;
	//堆的向上调整
	AdjustUp(hp->a,hp->size-1);
}

//向下调整
void AdjustDown(HPDataType* a, int size, int parent)
{
	//先去找根结点的较大的孩子结点
	int child = 2 * parent + 1;
	//可能会向下调整多次
	while (child<size) 
	{
		//这里使用假设法,先假设左孩子的值最大
		//如果不对就进行更新
		if ((child+1 < size)&&a[child] < a[child+1]) 
		{
			child++;
		}
		//根结点与其孩子结点中的较大的一个进行交换
		if(a[child] > a[parent]) 
		{
			swap(&a[child],&a[parent]);
			//更新下标
			parent = child;
			child = 2 * parent + 1;
		}
		else 
		{
			break; //调完堆
		}
	}
}
//堆的删除
void PopHeap(Heap* hp)
{
	assert(hp);
	assert(hp->size>0);
	//头尾交换
	swap(&hp->a[0],&hp->a[hp->size-1]);
	hp->size--;
	//向下调整
	AdjustDown(hp->a,hp->size,0);
}

//获取堆顶数据
HPDataType TopHeap(Heap* hp) 
{
	assert(hp);
	assert(hp->size>0);
	return hp->a[0];
}

//获取堆的数据个数
int SizeHeap(Heap* hp)
{
	assert(hp);
	return hp->size;
}

//堆的判空
bool EmptyHeap(Heap* hp) 
{
	assert(hp);
	return hp->size == 0;
}

Heap.h

#pragma once

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

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;	//指向动态数组
	int capacity;	//堆的容量
	int size;		//堆中数据个数
}Heap;

//初始化堆
void InitHeap(Heap* hp);

//销毁堆
void DestroyHeap(Heap* hp);

//堆的插入
void PushHeap(Heap* hp, HPDataType x);

//堆的删除
void PopHeap(Heap*hp);

//获取堆顶数据
HPDataType TopHeap(Heap* hp);

//获取堆的数据个数
int SizeHeap(Heap* hp);

//堆的判空
bool EmptyHeap(Heap* hp);

test.c

#include "Heap.h"

void Test1() 
{
	Heap hp;
	InitHeap(&hp);
	PushHeap(&hp,49);
	PushHeap(&hp,65);
	PushHeap(&hp,34);
	PushHeap(&hp,25);
	PushHeap(&hp,37);
	PushHeap(&hp,27);
	PushHeap(&hp,19);
	//删除65
	PopHeap(&hp);
	//printf("堆的个数:%d\n",SizeHeap(&hp));
	//while (!EmptyHeap(&hp)) 
	//{
	//	printf("%d-", TopHeap(&hp));
	//	PopHeap(&hp);
	//}

	DestroyHeap(&hp);
	//27,19,34,65,49,25,37
}
int main() 
{
	Test1();
	return 0;
}

2. 堆排序的代码

//堆排序
void HeapSort(int* arr, int n) 
{
	int i = 0;
	//使用向下调整算法向上调整,把大的值调到上方。
	for (i = (n - 1 - 1) / 2; i >= 0;i--)
	{
		//先找到数组最后端的父结点的下标
		//父结点的下标减一就是另一个
		//使用向下调整算法进行调整
		AdjustDown(arr,n,i);
	}

	//进行排序
	//因为是大堆,所以根结点的值是最值
	//把最值与堆的最后一个结点进行交换
	//再把交换后的根节点进行向下调整
	//然后堆的大小减一
	

	//注意end 是从n-1开始的(数组最后一个元素的下标)
	int end = n-1;
	while (end > 0) 
	{
		//swap end = n-1 这表示下标
		swap(&arr[0],&arr[end]);
		//adjustdown 函数里面的end是元素的个数,所以不是先--end
		//所以
		AdjustDown(arr,end,0);
		end--;
	}
}

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

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

相关文章

Flink Checkpoint 超时问题详解

第一种、计算量大&#xff0c;CPU密集性&#xff0c;导致TM内线程一直在processElement&#xff0c;而没有时间做CP【过滤掉部分数据&#xff1b;增大并行度】 代表性作业为算法指标-用户偏好的计算&#xff0c;需要对用户在商城的曝光、点击、订单、出价、上下滑等所有事件进…

监听项目中指定属性数据,点击或模块显示时

当项目中&#xff0c;需要获取某个页面上、某个标签上、有指定自定义属性时&#xff0c;需要在点击该元素时进行公共逻辑处理&#xff0c;或该元素在显示的时候进行逻辑处理&#xff0c;这时可以定义一个公共的方法&#xff0c;在每个页面引用&#xff0c;并写入数据即可 &…

SOME/IP SD 协议介绍(一)

概述 服务发现用于定位服务实例并检测服务实例是否正在运行。在车载网络中&#xff0c;服务实例的位置通常是已知的&#xff1b;因此&#xff0c;服务实例的状态是首要关注的。服务的位置&#xff08;即IP地址、传输协议和端口号&#xff09;是次要关注的内容。 术语和定义 S…

防御保护--防火墙的可靠性

目录 前提&#xff1a; VGMP 接口故障切换场景 状态切换备份的过程 HRP 第一种备份方式 --- 自动备份 第二种备份方式 --- 手工备份 第三种备份方式 --- 快速备份 各备份场景过程分析 1&#xff0c;主备形成场景 2&#xff0c;主备模式下&#xff0c;接口故障切…

防火墙用户认证、NAT、策略路由、DNS透明代理以及双机热备笔记

用户认证 防火墙管理员登录认证 --- 检验身份的合法性&#xff0c;划分身份权限 用户认证 --- 上网行为管理的一部分 用户&#xff0c;行为&#xff0c;流量 --- 上网行为管理三要素 用户认证的分类 上网用户认证 --- 三层认证 --- 所有的跨网段的通信都可以属于上网行为。…

redis-主从复制

1.主从复制 1.1简介 主机数据更新后根据配置和策略&#xff0c; 自动同步到备机的master/slaver机制&#xff0c;Master以写为主&#xff0c;Slave以读为主 1.2作用 1、数据冗余&#xff1a;主从复制实现了数据的热备份&#xff0c;是持久化之外的一种数据冗余方式。 2、故…

群辉开启WebDav服务+cpolar内网穿透实现移动端ES文件浏览器远程访问本地NAS文件

文章目录 1. 安装启用WebDAV2. 安装cpolar3. 配置公网访问地址4. 公网测试连接5. 固定连接公网地址6. 使用固定地址测试连接 本文主要介绍如何在群辉中开启WebDav服务&#xff0c;并结合cpolar内网穿透工具生成的公网地址&#xff0c;通过移动客户端ES文件浏览器即可实现移动设…

如何搭建开源笔记Joplin服务并实现远程访问本地数据

文章目录 1. 安装Docker2. 自建Joplin服务器3. 搭建Joplin Sever4. 安装cpolar内网穿透5. 创建远程连接的固定公网地址 Joplin 是一个开源的笔记工具&#xff0c;拥有 Windows/macOS/Linux/iOS/Android/Terminal 版本的客户端。多端同步功能是笔记工具最重要的功能&#xff0c;…

API:低代码平台的强大秘诀与无限可能

应用编程接口 (API) 是应用程序以可编程格式访问其关键能力和功能的一种方式&#xff0c;从而其他应用程序可以利用它们。API 本质上支持应用程序之间的无缝数据流&#xff0c;使开发人员能够在应用程序中添加更多功能&#xff0c;而无需依赖大量编码。 举一个简单的例子。 您…

阿里云如何找回域名,进行添加或删除?

权威域名管理介绍说明&#xff0c;包含添加域名、删除域名、找回域名、域名分组等操作介绍。 一、添加域名 非阿里云注册域名或子域名如需使用云解析DNS&#xff0c;需要通过添加域名功能&#xff0c;将主域名或子域名添加到云解析控制台&#xff0c;才可以启用域名解析服务。…

基于springboot+vue的医院管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

如何发现帕鲁私服漏洞

白天当帕鲁、晚上抓帕鲁 相信所有的帕鲁玩家都不希望辛辛苦苦肝了几百小时抓的帕鲁因为网络入侵消失&#xff0c;除了抵御游戏内的强盗入侵&#xff0c;还要抵御现实世界的网络入侵&#xff0c;原本单纯的帕鲁变的复杂无比。 服务器弱口令、服务漏洞、未授权访问等入侵手段&a…

计算机网络——网络层(2)

计算机网络——网络层&#xff08;2&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 网络层——控制平面概述路由选择转发表路由协议路由信息的交换小结 路由选择算法常见的路由选择算法距离矢量路由算法工作原理优缺点分析 链路状态路由算法基本工作原理优…

D35XB100-ASEMI整流桥D35XB100参数、封装、规格

编辑&#xff1a;ll D35XB100-ASEMI整流桥D35XB100参数、封装、规格 型号&#xff1a;D35XB100 品牌&#xff1a;ASEMI 正向电流&#xff08;Id&#xff09;&#xff1a;35A 反向耐压&#xff08;VRRM&#xff09;&#xff1a;1000V 正向浪涌电流&#xff1a;550A 正向…

JavaScript定义变量及赋值

定义变量及赋值 ☞ 定义变量,未赋值var 变量名; 默认值是undefined ☞ 定义变量,且赋值var 变量名 数据;☞ 总结:1. 一个变量一次只能保存一个值&#xff1b;2. 以最后一次赋值为准3. JS变量区分大小写变量命名规范 ☞ 规则 必须遵守的&#xff0c;不遵守的话 JS引擎 发…

PC电脑端的小程序顶部自定义标题失效的原因

windows客户端不被支持:navigationStyle:custom!! navigationStylestringdefault导航栏样式&#xff0c;仅支持以下值&#xff1a; default 默认样式 custom 自定义导航栏&#xff0c;只保留右上角胶囊按钮。iOS/Android 微信客户端 7.0.0&#xff0c;Windows 微信客户端不支…

一文读懂Python中的映射

python中的反射功能是由以下四个内置函数提供&#xff1a;hasattr、getattr、setattr、delattr&#xff0c;改四个函数分别用于对对象内部执行&#xff1a;检查是否含有某成员、获取成员、设置成员、删除成员。 获取成员: getattr class Foo:def __init__(self, name, age):se…

c语言实战之贪吃蛇

文章目录 前言效果展示游戏用到的图片游戏思路一览游戏前准备一、贪吃蛇、食物、障碍物节点坐标的结构体二、枚举游戏状态、和贪吃蛇的方向三、维护运行的结构体 游戏开始前的初始化一、学习图形库相关知识二、设置背景三、欢迎界面四、初始化贪吃蛇五、生成障碍物六、生成食物…

【Uni-App】Vue3如何使用pinia状态管理库与持久化

安装插件 pinia-plugin-unistorage 引入 // main.js import { createSSRApp } from "vue"; import * as Pinia from "pinia"; import { createUnistorage } from "pinia-plugin-unistorage";export function createApp() {const app create…

Backtrader 文档学习-Order StopTrail(Limit)

Backtrader 文档学习-Order StopTrail(Limit) 1.概述 版本1.9.36.116之后支持[StopTrail, StopTrailLimit and OCO]的订单类型&#xff0c;并支持broker的实时交互 。 StopTrail订单&#xff0c;它是一种追踪止损订单。当市场价格朝定义的交易方向移动时&#xff0c;StopTrai…